24 #include "base/macros.h"
33 static const int kNanoSecondsPerSecond = 1000000000;
35 std::string MakeNanoSecondString(uint8 second, uint32 nanosecond) {
41 static const std::string kSecondReplString =
"%02u";
42 char seconds_buffer[3];
43 snprintf(seconds_buffer,
sizeof(seconds_buffer), kSecondReplString.c_str(),
46 if (nanosecond == 0) {
47 return std::string(seconds_buffer);
51 DCHECK_LT(nanosecond, static_cast<uint32>(kNanoSecondsPerSecond));
52 nanosecond = nanosecond % kNanoSecondsPerSecond;
55 while (nanosecond % 10 == 0)
58 static const char kResultFormat[] =
"%s.%u";
59 char result_buffer[256];
60 snprintf(result_buffer,
sizeof(result_buffer), kResultFormat,
61 seconds_buffer, nanosecond);
62 return std::string(result_buffer);
67 static inline int64 Quotient(int64 a, int64 b) {
68 return static_cast<int64
>(
69 floor(static_cast<double>(a) / static_cast<double>(b)));
72 static inline int64 Quotient(int64 a, int64 low, int64 high) {
73 return Quotient(a - low, high - low);
76 static inline int64 Modulo(int64 a, int64 b) {
return a - Quotient(a, b) * b; }
78 static inline int64 Modulo(int64 a, int64 low, int64 high) {
79 return Modulo(a - low, high - low) + low;
82 static inline int MaximumDayInMonthFor(int64 year,
int month) {
83 int m =
static_cast<int>(Modulo(month, 1, 13));
84 int64 y = year + Quotient(month, 1, 13);
102 if ((Modulo(y, 400) == 0 || Modulo(y, 100) != 0) && Modulo(y, 4) == 0)
112 static inline bool IsLeapYear(int64 y) {
113 return (Modulo(y, 4) == 0 && (Modulo(y, 400) == 0 || Modulo(y, 100) != 0));
117 static inline int CumulativeDays(int64 y,
int m) {
118 static int month_days[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304,
127 return month_days[m - 1] + (m > 2 && IsLeapYear(y));
137 static inline int64 CumulativeEpochDaysToYear(int64 year) {
147 int64 days_since_year_0 = 0;
149 int64 prev_years = year - 1;
151 int64 num_leap_years =
152 (prev_years / 4 - prev_years / 100) + prev_years / 400 + 1;
153 days_since_year_0 = num_leap_years * 366 + (year - num_leap_years) * 365;
154 }
else if (year < 0) {
155 int64 pos_years = -year;
156 int64 num_leap_years = (pos_years / 4 - pos_years / 100) + pos_years / 400;
158 -(num_leap_years * 366 + (pos_years - num_leap_years) * 365);
160 days_since_year_0 = 0;
164 return days_since_year_0 - 719528;
170 Set(kUndefinedYear, 1, 1, 0, 0, 0, 0, 0, 0);
178 uint8 minute, uint8 second, uint32 nanosecond,
179 int8 zone_hours, int8 zone_minutes) {
181 Set(year, month, day, hour, minute, second, nanosecond, zone_hours,
190 const std::chrono::nanoseconds time_since_epoch_nanos =
191 std::chrono::duration_cast<std::chrono::nanoseconds>(
192 time.time_since_epoch());
193 const std::chrono::seconds time_since_epoch_seconds =
194 std::chrono::duration_cast<std::chrono::seconds>(time.time_since_epoch());
195 SetFromPosixSecondsOnly(time_since_epoch_seconds.count(), zone_hours,
198 std::chrono::duration_cast<std::chrono::duration<uint32, std::nano>>(
199 time_since_epoch_nanos - time_since_epoch_seconds)
211 if (month < 0 || month > 12)
212 LOG(
ERROR) <<
"Invalid month " << month <<
" provided. Skipping set.";
219 if (day < 0 || day > MaximumDayInMonthFor(year_, month_))
220 LOG(
ERROR) <<
"Invalid day " << day <<
" provided for year/month "
221 << year_ <<
"/" << month_ <<
". Skipping set.";
227 if (hour < 0 || hour > 23)
228 LOG(
ERROR) <<
"Invalid hour " << hour
229 <<
" for 24-hour time representation. Skipping set.";
235 if (minute < 0 || minute > 59)
236 LOG(
ERROR) <<
"Invalid minute " << minute <<
" provided. Skipping set.";
242 if (second < 0 || second > 59)
243 LOG(
ERROR) <<
"Invalid second " << second <<
" provided. Skipping set.";
249 if (nanosecond >= kNanoSecondsPerSecond)
250 LOG(
ERROR) <<
"Invalid nanosecond " << nanosecond
251 <<
" provided. Skipping set.";
253 nanosecond_ = nanosecond;
257 if (zone_hours < -12 || zone_hours > 14)
258 LOG(
ERROR) <<
"Invalid time zone hour " << zone_hours
259 <<
" provided. Skipping set.";
261 zone_hours_ = zone_hours;
265 if (zone_minutes < -59 || zone_minutes > 59)
266 LOG(
ERROR) <<
"Invalid time zone minute " << zone_minutes
267 <<
" provided. Skipping set.";
269 zone_minutes_ = zone_minutes;
301 Set(years, months, days, hours, minutes, seconds, zone_hours, zone_minutes);
306 Set(other.year_, other.month_, other.day_, other.hour_, other.minute_,
307 other.second_, other.nanosecond_, other.zone_hours_, other.zone_minutes_);
311 char buf[256] = { 0 };
313 if (hour_ == 0 && minute_ == 0 && second_ == 0 && nanosecond_ == 0 &&
314 zone_hours_ == 0 && zone_minutes_ == 0) {
315 if (month_ == 1 && day_ == 1)
316 snprintf(buf,
sizeof(buf),
"%04" GG_LL_FORMAT
"d", year);
318 snprintf(buf,
sizeof(buf),
"%04" GG_LL_FORMAT
"d-%02d", year, month_);
322 "%04" GG_LL_FORMAT
"d-%02d-%02d",
327 std::string second_string = MakeNanoSecondString(second_, nanosecond_);
328 if (zone_hours_ == 0 && zone_minutes_ == 0) {
331 "%04" GG_LL_FORMAT
"d-%02d-%02dT%02d:%02d:%sZ",
337 second_string.c_str());
340 if (zone_hours_ == 0)
341 sign = zone_minutes_ >= 0 ?
'+' :
'-';
343 sign = zone_hours_ >= 0 ?
'+' :
'-';
346 "%04" GG_LL_FORMAT
"d-%02d-%02dT%02d:%02d:%s%c%02d:%02d",
352 second_string.c_str(),
358 return std::string(buf);
377 static const std::regex re(
395 std::smatch date_regex_match;
396 if (!std::regex_match(str, date_regex_match, re)) {
403 std::stringstream ss(date_regex_match.str(1));
409 if (date_regex_match.str(2) ==
"") {
413 std::stringstream ss(date_regex_match.str(2));
416 result.
SetMonth(static_cast<uint8>(ushort_val));
420 if (date_regex_match.str(3) ==
"") {
424 std::stringstream ss(date_regex_match.str(3));
425 uint16 ushort_val = 0;
427 result.
SetDay(static_cast<uint8>(ushort_val));
433 if (date_regex_match.str(8) !=
"") {
435 std::stringstream ss(date_regex_match.str(9));
438 int8 zone_hours =
static_cast<int8
>(short_val);
441 int8 zone_minutes = 0;
442 if (date_regex_match.str(10) !=
"") {
443 std::stringstream ss(date_regex_match.str(10));
446 zone_minutes =
static_cast<int8
>(short_val);
450 if (date_regex_match.str(8) ==
"-") {
451 zone_hours =
static_cast<int8
>(-zone_hours);
452 zone_minutes =
static_cast<int8
>(-zone_minutes);
462 if (date_regex_match.str(4) ==
"") {
466 std::stringstream ss(date_regex_match.str(4));
467 uint16 ushort_val = 0;
469 result.
SetHour(static_cast<uint8>(ushort_val));
473 if (date_regex_match.str(5) ==
"") {
477 std::stringstream ss(date_regex_match.str(5));
478 uint16 ushort_val = 0;
480 result.
SetMinute(static_cast<uint8>(ushort_val));
484 if (date_regex_match.str(6) ==
"") {
488 std::stringstream ss(date_regex_match.str(6));
489 uint16 ushort_val = 0;
491 result.
SetSecond(static_cast<uint8>(ushort_val));
495 if (date_regex_match.str(7) ==
"") {
500 size_t num_nanosecond_letters = date_regex_match.str(7).length();
501 static const size_t kNumNanoSecondLetters = 9;
503 std::stringstream ss(date_regex_match.str(7));
505 for (
size_t i = num_nanosecond_letters; i < kNumNanoSecondLetters; ++i) {
518 std::streampos pos = in.tellg();
524 in.setstate(std::ios_base::failbit);
530 std::string* out_string)
const {
531 static const char kDayMonthYearFormat[] =
"%d/%d/%s";
532 static const char kMonthYearFormat[] =
"%d/%s";
533 static const int64 kOneBillion = 1000000000LL;
534 static const int64 k100Million = 100000000LL;
535 static const int64 kTenMillion = 10000000LL;
536 static const int64 kOneMillion = 1000000LL;
539 char year_buffer[256];
541 static const char kSingleBCEFormat[] =
"%d BCE";
542 static const char kMillionBCEFormat[] =
"%.2f Million BCE";
543 static const char k10MillionBCEFormat[] =
"%.1f Million BCE";
544 static const char k100MillionBCEFormat[] =
"%d Million BCE";
545 static const char kBillionBCEFormat[] =
"%.2f Billion BCE";
547 if (year_ <= -kOneBillion)
548 snprintf(year_buffer,
sizeof(year_buffer), kBillionBCEFormat,
549 static_cast<double>(-year_) / kOneBillion);
550 else if (year_ <= -k100Million)
552 snprintf(year_buffer,
sizeof(year_buffer), k100MillionBCEFormat,
553 static_cast<int>(-year_ / kOneMillion));
554 else if (year_ <= -kTenMillion)
555 snprintf(year_buffer,
sizeof(year_buffer), k10MillionBCEFormat,
556 static_cast<double>(-year_) / kOneMillion);
557 else if (year_ <= -kOneMillion)
558 snprintf(year_buffer,
sizeof(year_buffer), kMillionBCEFormat,
559 static_cast<double>(-year_) / kOneMillion);
561 snprintf(year_buffer,
sizeof(year_buffer), kSingleBCEFormat,
562 static_cast<int>(-year_));
564 snprintf(year_buffer,
sizeof(year_buffer),
"%4d", static_cast<int>(year_));
566 DCHECK_NE(std::string(
""), std::string(year_buffer));
569 switch (output_date_format) {
573 char out_buffer[256];
574 snprintf(out_buffer,
sizeof(out_buffer), kDayMonthYearFormat,
575 month_, day_, year_buffer);
576 *out_string = std::string(out_buffer);
582 char out_buffer[256];
583 snprintf(out_buffer,
sizeof(out_buffer), kMonthYearFormat,
584 month_, year_buffer);
585 *out_string = std::string(out_buffer);
589 *out_string = std::string(year_buffer);
593 DCHECK(
false) <<
"Invalid DateStringEnum passed to "
594 "DateTime::ComputeDateString()";
599 std::string* out_string)
const {
602 bool pm_flag =
false;
608 hour_value = hour_ - 12;
610 hour_value = hour_ == 0 ? 12 : hour_;
611 pm_flag = hour_ == 12 ?
true :
false;
615 static const char kHMSFormat[] =
" %d:%02d:%02d%s";
616 static const char kHMFormat[] =
" %d:%02d%s";
617 static const char kHFormat[] =
" %d%s";
620 char output_buffer[256];
621 switch (output_time_format) {
623 snprintf(output_buffer,
sizeof(output_buffer), kHMSFormat,
630 snprintf(output_buffer,
sizeof(output_buffer), kHMFormat,
636 snprintf(output_buffer,
sizeof(output_buffer), kHFormat,
641 DCHECK(
false) <<
"Invalid TimeStringEnum passed to "
642 "DateTime::ComputeTimeString()";
644 *out_string = std::string(output_buffer);
650 static const std::string kFormatToUse(
"using am/pm time format");
651 return kFormatToUse ==
"24";
655 static const char kFieldSuffix[] =
"ymdhms";
660 uint8 field_index = 0;
661 while (field_index < static_cast<uint8>(
kNanosecond)
667 if (field_index == static_cast<uint8>(
kNanosecond))
668 return std::string(
"0.0s");
671 char output_buffer[256];
672 int output_chars = 0;
673 memset(output_buffer, static_cast<int>(
'\0'), 256 *
sizeof(
char));
674 uint8 output_field_index;
675 for (output_field_index = 0
676 ; output_field_index < 3 && field_index != static_cast<uint8>(
kSecond)
677 ; ++output_field_index, ++field_index) {
682 output_chars += snprintf(&output_buffer[0] + output_chars,
683 256 - output_chars,
"%llu%c ", value, kFieldSuffix[field_index]);
687 if (field_index == static_cast<uint8>(
kSecond) && output_field_index < 3) {
688 snprintf(&output_buffer[0] + output_chars, 256 - output_chars,
689 output_field_index < 2 ?
"%.1f%c " :
"%.0f%c",
690 static_cast<double>(second_) + fractional_seconds,
691 kFieldSuffix[field_index]);
702 if (norm_this.year_ > norm_other.year_)
704 else if (norm_this.year_ < norm_other.year_)
706 else if (norm_this.month_ > norm_other.month_)
708 else if (norm_this.month_ < norm_other.month_)
710 else if (norm_this.day_ > norm_other.day_)
712 else if (norm_this.day_ < norm_other.day_)
714 else if (norm_this.hour_ > norm_other.hour_)
716 else if (norm_this.hour_ < norm_other.hour_)
718 else if (norm_this.minute_ > norm_other.minute_)
720 else if (norm_this.minute_ < norm_other.minute_)
722 else if (norm_this.second_ > norm_other.second_)
724 else if (norm_this.second_ < norm_other.second_)
726 else if (norm_this.nanosecond_ > norm_other.nanosecond_)
728 else if (norm_this.nanosecond_ < norm_other.nanosecond_)
739 return (norm_this.year_ == norm_other.year_ &&
740 norm_this.month_ == norm_other.month_ &&
741 norm_this.day_ == norm_other.day_ &&
742 norm_this.hour_ == norm_other.hour_ &&
743 norm_this.minute_ == norm_other.minute_ &&
744 norm_this.second_ == norm_other.second_ &&
745 norm_this.nanosecond_ == norm_other.nanosecond_ &&
746 norm_this.zone_hours_ == norm_other.zone_hours_ &&
747 norm_this.zone_minutes_ == norm_other.zone_minutes_);
752 year_ == dtime.year_ && month_ == dtime.month_ && day_ == dtime.day_ &&
753 hour_ == dtime.hour_ && minute_ == dtime.minute_ &&
754 second_ == dtime.second_ && nanosecond_ == dtime.nanosecond_ &&
755 zone_hours_ == dtime.zone_hours_ && zone_minutes_ == dtime.zone_minutes_);
761 int64 posix_seconds = GetPosixSecondsOnly();
762 return std::chrono::system_clock::time_point(
763 std::chrono::duration_cast<std::chrono::system_clock::duration>(
764 std::chrono::seconds(posix_seconds) +
765 std::chrono::nanoseconds(nanosecond_)));
770 int year =
static_cast<int>(year_);
773 if (month_ == 1 || month_ == 2) {
783 double a = floor(year / 100.0);
784 double b = 2.0 - a + floor(a / 4.0);
785 double c = floor(365.25 * (year + 4716.0));
786 double d = floor(30.6001 * (month + 1.0));
787 double day = c + d + day_ + b - 1524.5;
793 double val = nanosecond_;
794 val = val * 1e-9 + second_;
795 val = val / 60.0 + minute_;
796 val = val / 60.0 + hour_;
802 if (new_hours != zone_hours_ || new_mins != zone_minutes_) {
803 uint32 nanoseconds = nanosecond_;
806 SetFromPosixSecondsOnly(GetPosixSecondsOnly(), static_cast<int8>(new_hours),
807 static_cast<int8>(new_mins));
808 nanosecond_ = nanoseconds;
826 ret_val += interp_offset;
833 int64 begin_secs = begin.GetPosixSecondsOnly();
834 int64 end_secs = end.GetPosixSecondsOnly();
839 double duration =
static_cast<double>(end_secs - begin_secs);
842 duration += (
static_cast<int32
>(end.nanosecond_) -
843 static_cast<int32>(begin.nanosecond_)) *
852 int64 a_secs = time_a.GetPosixSecondsOnly();
853 int64 b_secs = time_b.GetPosixSecondsOnly();
854 int64 now_secs = now.GetPosixSecondsOnly();
856 double time_range =
static_cast<double>(b_secs - a_secs);
858 time_range += (
static_cast<int32
>(time_b.nanosecond_) -
859 static_cast<int32>(time_a.nanosecond_)) *
862 if (time_range == 0.0)
865 double time_from_a =
static_cast<double>(now_secs - a_secs);
866 time_from_a += (
static_cast<int32
>(now.nanosecond_) -
867 static_cast<int32>(time_a.nanosecond_)) *
869 return time_from_a / time_range;
873 int64 total_seconds = GetPosixSecondsOnly();
874 int32 total_nanoseconds = nanosecond_;
878 DCHECK_LT(total_nanoseconds, kNanoSecondsPerSecond);
880 double seconds = 0.0;
881 double nanoseconds = kNanoSecondsPerSecond * std::modf(secs, &seconds);
882 total_seconds +=
static_cast<int64
>(seconds);
883 total_nanoseconds +=
static_cast<int32
>(nanoseconds);
884 if (total_nanoseconds >= kNanoSecondsPerSecond) {
886 total_nanoseconds -= kNanoSecondsPerSecond;
887 }
else if (total_nanoseconds < 0) {
889 total_nanoseconds += kNanoSecondsPerSecond;
892 SetFromPosixSecondsOnly(total_seconds, zone_hours_, zone_minutes_);
893 nanosecond_ = total_nanoseconds;
897 if (str.size() == 7) {
898 if (str[4] !=
'-')
return false;
900 if (!isdigit(str[5]))
return false;
901 if (!isdigit(str[6]))
return false;
903 for (
int i = 0; i < 4; ++i) {
904 if (!isdigit(str[i]))
return false;
937 LOG(
ERROR) <<
"Invalid DateTime field provided to GetDateTimeField().";
943 void DateTime::SetFromPosixSecondsOnly(int64 secs, int8 requested_zone_hours,
944 int8 requested_zone_minutes) {
946 Set(0, 1, 1, 0, 0, 0, requested_zone_hours, requested_zone_minutes);
949 int64 zh =
static_cast<int64
>(requested_zone_hours);
950 int64 zm =
static_cast<int64
>(requested_zone_minutes);
951 secs += ((zh * 60) + zm) * 60;
954 int64 days = secs / (24 * 60 * 60);
957 secs -= days * (24 * 60 * 60);
958 second_ =
static_cast<uint8
>(Modulo(secs, 60));
960 int64 mins = Quotient(secs, 60);
961 minute_ =
static_cast<uint8
>(Modulo(mins, 60));
963 int64 hours = Quotient(mins, 60);
964 hour_ =
static_cast<uint8
>(Modulo(hours, 24));
966 days += Quotient(hours, 24);
972 int64 days_left = days;
973 int64 guess_years = 1970;
974 static const double days_to_years = 1. / 365.;
978 while ((years_left = static_cast<int64>(static_cast<double>(days_left) *
979 days_to_years)) != 0) {
981 guess_years += years_left;
983 days_left = days - CumulativeEpochDaysToYear(guess_years);
989 days = days_left + 1;
995 days += MaximumDayInMonthFor(year_, month_ - 1);
997 month_ =
static_cast<uint8
>(Modulo(t, 1, 13));
998 year_ += Quotient(t, 1, 13);
1000 int max_day_in_month;
1001 while (max_day_in_month = MaximumDayInMonthFor(year_, month_),
1002 days > max_day_in_month) {
1004 days -= max_day_in_month;
1006 month_ =
static_cast<uint8
>(Modulo(t, 1, 13));
1007 year_ += Quotient(t, 1, 13);
1009 day_ =
static_cast<uint8
>(days);
1012 int64 DateTime::GetPosixSecondsOnly()
const {
1013 const int64 days_to_year = CumulativeEpochDaysToYear(year_);
1014 const int64 days_to_month_within_year = CumulativeDays(year_, month_);
1016 const int64 days_within_month = (day_ == 0) ? 0 : day_ - 1;
1017 const int64 days_big =
1018 days_to_year + days_to_month_within_year + days_within_month;
1019 const int64 hours_big =
static_cast<int64
>(hour_) - zone_hours_;
1020 const int64 mins_big =
static_cast<int64
>(minute_) - zone_minutes_;
1022 int64 secs_big = second_;
1024 return ((((days_big * 24) + hours_big) * 60) + mins_big) * 60 + secs_big;
static double GetDurationSecs(const DateTime &begin, const DateTime &end)
Compute the duration from the first datetime to the second datetime in seconds, down to nanosecond re...
void SetSecond(uint8 second)
int64 GetDateTimeField(DateTimeField field) const
Returns a specific field value in the DateTime object as defined by DateTimeField field (kYear...
void Normalize()
Converts this DateTime to UTC time (+0:00 time zone).
bool operator==(const DateTime &dtime) const
This operator converts the date times to absolute and compares the absolute times for equality (hence...
static double GetInterpValue(const DateTime &now, const DateTime &time_a, const DateTime &time_b)
Returns a double value representing the interpolation of now with respect to time_a and time_b...
std::string ToString() const
Converts time to user-readable string.
void SetNanosecond(uint32 nanosecond)
#define LOG(severity)
Logs the streamed message unconditionally with a severity of severity.
std::istream & operator>>(std::istream &in, DateTime &dtime)
std::string TrimStartAndEndWhitespace(const std::string &target)
Removes any whitespace characters at the beginning and end of the string.
bool operator>(const DateTime &dtime) const
std::ostream & operator<<(std::ostream &os, const DateTime &dtime)
std::string ComputeDurationString(double fractional_seconds) const
Returns string for 'this', e.g., "2y3m18d", interpreted as a duration.
static bool ParseYMString(const std::string &date, DateTime *date_out)
Checks if given string is in YYYY-MM formatr.
void SetZoneMinutes(int8 zone_minutes)
DateTimeField
Enumeration of the time-value fields of DateTime (used for iteration and numerical access)...
#define DCHECK_NE(val1, val2)
double GetTimeAsDecimal() const
Convert "Standard" time to decimal time (or "French Revolutionary" time).
void SetYear(int64 year)
Mutators for individual fields.
bool IsEqualByComponent(const DateTime &dtime) const
Checks each component of the time object, including time zone.
void ComputeDateString(const DateStringEnum output_date_format, std::string *out_string) const
DateTime represents a particular date and time down to the nanosecond level along with timezone infor...
int32 ION_API StringToInt32(const std::string &str)
Extracts and returns an integral value from str.
double GetJulianDate() const
The Julian Day is the integer number of days that have elapsed since noon on Monday, January 1, 4713 BC.
void SetZoneHours(int8 zone_hours)
#define DCHECK_GE(val1, val2)
void SetMonth(uint8 month)
void SetMinute(uint8 minute)
virtual bool Use24HourTime() const
Determines whether to render 24-hour time strings based on a value set by translators.
void Lerp(const DateTime &origin, const DateTime &target, double t)
Set the current time to the interpolation of the two given times according to the interpolant...
void AdjustTimeZone(int newHours, int newMins)
Converts time to another time zone.
void ComputeTimeString(const TimeStringEnum output_time_format, std::string *out_string) const
Copyright 2016 Google Inc.
uint32 GetNanosecond() const
void Reset()
Set the DateTime to default values (<year>/1/1T00:00:00.0Z00:00, where <year> is set as kUndefinedYea...
DateStringEnum
ComputeDateString() and ComputeTimeString() render the DateTime object to a std::string.
DateTime & operator=(const DateTime &rhs)
#define DCHECK_LE(val1, val2)
static DateTime Interpolate(const DateTime &begin, const DateTime &end, double t)
Returns a linearly-interpolated DateTime between begin and end as defined by parameter t...
void operator+=(int64 secs)
void Set(int64 years, uint8 months, uint8 days, uint8 hours, uint8 minutes, uint8 seconds, int8 zone_hours, int8 zone_minutes)
bool FromString(const std::string &str)
Parses str into this DateTime object.
#define DCHECK_LT(val1, val2)
std::chrono::system_clock::time_point GetTimePoint() const
Return a std::chrono::system_clock::time_point.