Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
datetime.cc
Go to the documentation of this file.
1 
18 #include "ion/base/datetime.h"
20 
21 #include <cstring> // For memset.
22 #include <regex> // NOLINT
23 
24 #include "base/macros.h"
25 #include "ion/base/logging.h"
26 #include "ion/base/stringutils.h"
27 
28 namespace ion {
29 namespace base {
30 
31 namespace {
32 
33 static const int kNanoSecondsPerSecond = 1000000000;
34 
35 std::string MakeNanoSecondString(uint8 second, uint32 nanosecond) {
37  DCHECK_LT(second, 60);
38 
41  static const std::string kSecondReplString = "%02u";
42  char seconds_buffer[3];
43  snprintf(seconds_buffer, sizeof(seconds_buffer), kSecondReplString.c_str(),
44  second);
45 
46  if (nanosecond == 0) {
47  return std::string(seconds_buffer);
48  } else {
51  DCHECK_LT(nanosecond, static_cast<uint32>(kNanoSecondsPerSecond));
52  nanosecond = nanosecond % kNanoSecondsPerSecond;
53 
55  while (nanosecond % 10 == 0)
56  nanosecond /= 10;
57 
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);
63  }
64 }
65 } // anonymous namespace
66 
67 static inline int64 Quotient(int64 a, int64 b) {
68  return static_cast<int64>(
69  floor(static_cast<double>(a) / static_cast<double>(b)));
70 }
71 
72 static inline int64 Quotient(int64 a, int64 low, int64 high) {
73  return Quotient(a - low, high - low);
74 }
75 
76 static inline int64 Modulo(int64 a, int64 b) { return a - Quotient(a, b) * b; }
77 
78 static inline int64 Modulo(int64 a, int64 low, int64 high) {
79  return Modulo(a - low, high - low) + low;
80 }
81 
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);
85  switch (m) {
86  case 1:
87  case 3:
88  case 5:
89  case 7:
90  case 8:
91  case 10:
92  case 12:
93  return 31;
94  break;
95  case 4:
96  case 6:
97  case 9:
98  case 11:
99  return 30;
100  break;
101  case 2:
102  if ((Modulo(y, 400) == 0 || Modulo(y, 100) != 0) && Modulo(y, 4) == 0)
103  return 29;
104  return 28;
105  default:
106  DCHECK(0);
107  break;
108  }
109  return -1;
110 }
111 
112 static inline bool IsLeapYear(int64 y) {
113  return (Modulo(y, 4) == 0 && (Modulo(y, 400) == 0 || Modulo(y, 100) != 0));
114 }
115 
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,
119  334, 365};
120 
124  if (m < 1)
125  m = 1;
126  DCHECK_LT(m, 13); // m should always be less than 13
127  return month_days[m - 1] + (m > 2 && IsLeapYear(y));
128 }
129 
137 static inline int64 CumulativeEpochDaysToYear(int64 year) {
147  int64 days_since_year_0 = 0;
148  if (year > 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;
157  days_since_year_0 =
158  -(num_leap_years * 366 + (pos_years - num_leap_years) * 365);
159  } else {
160  days_since_year_0 = 0;
161  }
162 
164  return days_since_year_0 - 719528;
165 }
166 
168 
170  Set(kUndefinedYear, 1, 1, 0, 0, 0, 0, 0, 0);
171 }
172 
174  Set(rhs);
175 }
176 
177 DateTime::DateTime(int64 year, uint8 month, uint8 day, uint8 hour,
178  uint8 minute, uint8 second, uint32 nanosecond,
179  int8 zone_hours, int8 zone_minutes) {
180  Reset();
181  Set(year, month, day, hour, minute, second, nanosecond, zone_hours,
182  zone_minutes);
183 }
184 
185 DateTime::DateTime(std::chrono::system_clock::time_point time, int8 zone_hours,
186  int8 zone_minutes) {
187  Reset();
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,
196  zone_minutes);
197  nanosecond_ =
198  std::chrono::duration_cast<std::chrono::duration<uint32, std::nano>>(
199  time_since_epoch_nanos - time_since_epoch_seconds)
200  .count();
201 }
202 
203 void DateTime::SetYear(int64 year) {
206  year_ = year;
207 }
208 
209 void DateTime::SetMonth(uint8 month) {
211  if (month < 0 || month > 12)
212  LOG(ERROR) << "Invalid month " << month << " provided. Skipping set.";
213  else
214  month_ = month;
215 }
216 
217 void DateTime::SetDay(uint8 day) {
219  if (day < 0 || day > MaximumDayInMonthFor(year_, month_))
220  LOG(ERROR) << "Invalid day " << day << " provided for year/month "
221  << year_ << "/" << month_ << ". Skipping set.";
222  else
223  day_ = day;
224 }
225 
226 void DateTime::SetHour(uint8 hour) {
227  if (hour < 0 || hour > 23)
228  LOG(ERROR) << "Invalid hour " << hour
229  << " for 24-hour time representation. Skipping set.";
230  else
231  hour_ = hour;
232 }
233 
234 void DateTime::SetMinute(uint8 minute) {
235  if (minute < 0 || minute > 59)
236  LOG(ERROR) << "Invalid minute " << minute << " provided. Skipping set.";
237  else
238  minute_ = minute;
239 }
240 
241 void DateTime::SetSecond(uint8 second) {
242  if (second < 0 || second > 59)
243  LOG(ERROR) << "Invalid second " << second << " provided. Skipping set.";
244  else
245  second_ = second;
246 }
247 
248 void DateTime::SetNanosecond(uint32 nanosecond) {
249  if (nanosecond >= kNanoSecondsPerSecond)
250  LOG(ERROR) << "Invalid nanosecond " << nanosecond
251  << " provided. Skipping set.";
252  else
253  nanosecond_ = nanosecond;
254 }
255 
256 void DateTime::SetZoneHours(int8 zone_hours) {
257  if (zone_hours < -12 || zone_hours > 14)
258  LOG(ERROR) << "Invalid time zone hour " << zone_hours
259  << " provided. Skipping set.";
260  else
261  zone_hours_ = zone_hours;
262 }
263 
264 void DateTime::SetZoneMinutes(int8 zone_minutes) {
265  if (zone_minutes < -59 || zone_minutes > 59)
266  LOG(ERROR) << "Invalid time zone minute " << zone_minutes
267  << " provided. Skipping set.";
268  else
269  zone_minutes_ = zone_minutes;
270 }
271 
272 
273 void DateTime::Set(int64 years,
274  uint8 months,
275  uint8 days,
276  uint8 hours,
277  uint8 minutes,
278  uint8 seconds,
279  int8 zone_hours,
280  int8 zone_minutes) {
281  SetYear(years);
282  SetMonth(months);
283  SetDay(days);
284  SetHour(hours);
285  SetMinute(minutes);
286  SetSecond(seconds);
287  SetZoneHours(zone_hours);
288  SetZoneMinutes(zone_minutes);
289  SetNanosecond(0);
290 }
291 
292 void DateTime::Set(int64 years,
293  uint8 months,
294  uint8 days,
295  uint8 hours,
296  uint8 minutes,
297  uint8 seconds,
298  uint32 nanosecond,
299  int8 zone_hours,
300  int8 zone_minutes) {
301  Set(years, months, days, hours, minutes, seconds, zone_hours, zone_minutes);
302  SetNanosecond(nanosecond);
303 }
304 
305 void DateTime::Set(const DateTime& other) {
306  Set(other.year_, other.month_, other.day_, other.hour_, other.minute_,
307  other.second_, other.nanosecond_, other.zone_hours_, other.zone_minutes_);
308 }
309 
310 std::string DateTime::ToString() const {
311  char buf[256] = { 0 };
312  int64 year = year_;
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);
317  else if (day_ == 1)
318  snprintf(buf, sizeof(buf), "%04" GG_LL_FORMAT "d-%02d", year, month_);
319  else
320  snprintf(buf,
321  sizeof(buf),
322  "%04" GG_LL_FORMAT "d-%02d-%02d",
323  year,
324  month_,
325  day_);
326  } else {
327  std::string second_string = MakeNanoSecondString(second_, nanosecond_);
328  if (zone_hours_ == 0 && zone_minutes_ == 0) {
329  snprintf(buf,
330  256,
331  "%04" GG_LL_FORMAT "d-%02d-%02dT%02d:%02d:%sZ",
332  year,
333  month_,
334  day_,
335  hour_,
336  minute_,
337  second_string.c_str());
338  } else {
339  char sign;
340  if (zone_hours_ == 0)
341  sign = zone_minutes_ >= 0 ? '+' : '-';
342  else
343  sign = zone_hours_ >= 0 ? '+' : '-';
344  snprintf(buf,
345  256,
346  "%04" GG_LL_FORMAT "d-%02d-%02dT%02d:%02d:%s%c%02d:%02d",
347  year,
348  month_,
349  day_,
350  hour_,
351  minute_,
352  second_string.c_str(),
353  sign,
354  abs(zone_hours_),
355  abs(zone_minutes_));
356  }
357  }
358  return std::string(buf);
359 }
360 
361 std::ostream& operator<<(std::ostream& os, const DateTime& dtime) {
362  os << dtime.ToString();
363  return os;
364 }
365 
366 bool DateTime::FromString(const std::string& str) {
367  DateTime result;
370  result.Reset();
371 
375 
377  static const std::regex re(
378  "((?:-)?\\d+)" // year (mandatory). Optional "-" sign.
380  "(?:-(\\d{2})" // "-" month (optional). Cap 2 is the month digits.
381  "(?:-(\\d{2})" // "-" day (optional). Cap 3 is the day digits.
382  "(?:T" // Time Delimiter (optional).
383  "(\\d{2})" // Hour (Mandatory after "T"). Cap 4 is hour digits.
384  "(?::(\\d{2})" // ":" minutes (optional). Cap 5 is minute digits.
385  "(?::(\\d{2})" // ":" seconds (optional). Cap 6 is second digits.
386  "(?:\\.(\\d+))?" // Decimal seconds. Cap 7 is sec. digits after ".".
387  ")?)?)?" // Closing optional time string.
388  "(?:(?:Z)|(?:([+-])" // Opening of TimeZone string "Z" "+" or "-".
390  "(\\d{2})" // Zone Hours. Capture 9 is zone-hours digits.
391  "(?::(\\d{2}))?" // ":" + Zone Minutes. Cap10 is the minute digits.
392  ")?" // Closing TimeZone group.
393  ")?)?)?"); // Closing all optional tags.
394 
395  std::smatch date_regex_match;
396  if (!std::regex_match(str, date_regex_match, re)) {
397  LOG(WARNING) << "Couldn't parse DateTime\n";
398  return false;
399  }
400  DCHECK_GE(date_regex_match.size(), 11);
401  {
402  int64 year;
403  std::stringstream ss(date_regex_match.str(1));
404  ss >> year;
405  result.SetYear(year);
406  }
407 
409  if (date_regex_match.str(2) == "") {
410  this->Set(result);
411  return true;
412  } else {
413  std::stringstream ss(date_regex_match.str(2));
414  uint16 ushort_val;
415  ss >> ushort_val;
416  result.SetMonth(static_cast<uint8>(ushort_val));
417  }
418 
420  if (date_regex_match.str(3) == "") {
421  this->Set(result);
422  return true;
423  } else {
424  std::stringstream ss(date_regex_match.str(3));
425  uint16 ushort_val = 0;
426  ss >> ushort_val;
427  result.SetDay(static_cast<uint8>(ushort_val));
428  }
429 
433  if (date_regex_match.str(8) != "") { // "+" or "-".
435  std::stringstream ss(date_regex_match.str(9));
436  int16 short_val = 0;
437  ss >> short_val;
438  int8 zone_hours = static_cast<int8>(short_val);
439 
441  int8 zone_minutes = 0;
442  if (date_regex_match.str(10) != "") {
443  std::stringstream ss(date_regex_match.str(10));
444  int16 short_val = 0;
445  ss >> short_val;
446  zone_minutes = static_cast<int8>(short_val);
447  }
448 
450  if (date_regex_match.str(8) == "-") {
451  zone_hours = static_cast<int8>(-zone_hours);
452  zone_minutes = static_cast<int8>(-zone_minutes);
453  DCHECK_LE(zone_hours, 0);
454  DCHECK_LE(zone_minutes, 0);
455  }
456 
457  result.SetZoneHours(zone_hours);
458  result.SetZoneMinutes(zone_minutes);
459  }
460 
462  if (date_regex_match.str(4) == "") {
463  this->Set(result);
464  return true;
465  } else {
466  std::stringstream ss(date_regex_match.str(4));
467  uint16 ushort_val = 0;
468  ss >> ushort_val;
469  result.SetHour(static_cast<uint8>(ushort_val));
470  }
471 
473  if (date_regex_match.str(5) == "") {
474  this->Set(result);
475  return true;
476  } else {
477  std::stringstream ss(date_regex_match.str(5));
478  uint16 ushort_val = 0;
479  ss >> ushort_val;
480  result.SetMinute(static_cast<uint8>(ushort_val));
481  }
482 
484  if (date_regex_match.str(6) == "") {
485  this->Set(result);
486  return true;
487  } else {
488  std::stringstream ss(date_regex_match.str(6));
489  uint16 ushort_val = 0;
490  ss >> ushort_val;
491  result.SetSecond(static_cast<uint8>(ushort_val));
492  }
493 
495  if (date_regex_match.str(7) == "") {
496  this->Set(result);
497  return true;
498  } else {
499  int32 nanosecond;
500  size_t num_nanosecond_letters = date_regex_match.str(7).length();
501  static const size_t kNumNanoSecondLetters = 9;
502 
503  std::stringstream ss(date_regex_match.str(7));
504  ss >> nanosecond;
505  for (size_t i = num_nanosecond_letters; i < kNumNanoSecondLetters; ++i) {
506  nanosecond *= 10;
507  }
508  result.SetNanosecond(nanosecond);
509  }
510 
511  DCHECK_LE(result.GetNanosecond(), static_cast<uint32>(kNanoSecondsPerSecond));
512  this->Set(result);
513  return true;
514 }
515 
516 std::istream& operator>>(std::istream& in, DateTime& dtime) {
518  std::streampos pos = in.tellg();
519  std::string s;
520  in >> s;
521  if (!dtime.FromString(s)) {
523  in.seekg(pos);
524  in.setstate(std::ios_base::failbit);
525  }
526  return in;
527 }
528 
529 void DateTime::ComputeDateString(const DateStringEnum output_date_format,
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;
537 
539  char year_buffer[256];
540  if (year_ < 0) {
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";
546 
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);
560  else
561  snprintf(year_buffer, sizeof(year_buffer), kSingleBCEFormat,
562  static_cast<int>(-year_));
563  } else {
564  snprintf(year_buffer, sizeof(year_buffer), "%4d", static_cast<int>(year_));
565  }
566  DCHECK_NE(std::string(""), std::string(year_buffer));
567 
569  switch (output_date_format) {
570  case kRenderDayMonthYear: {
571  DCHECK_GE(month_, 1);
572  DCHECK_LE(month_, 12);
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);
577  break;
578  }
579  case kRenderMonthYear: {
580  DCHECK_GE(month_, 1);
581  DCHECK_LE(month_, 12);
582  char out_buffer[256];
583  snprintf(out_buffer, sizeof(out_buffer), kMonthYearFormat,
584  month_, year_buffer);
585  *out_string = std::string(out_buffer);
586  break;
587  }
588  case kRenderYearOnly: {
589  *out_string = std::string(year_buffer);
590  break;
591  }
592  default:
593  DCHECK(false) << "Invalid DateStringEnum passed to "
594  "DateTime::ComputeDateString()";
595  }
596 }
597 
598 void DateTime::ComputeTimeString(const TimeStringEnum output_time_format,
599  std::string* out_string) const {
601  int hour_value;
602  bool pm_flag = false;
603  if (Use24HourTime()) {
604  hour_value = hour_;
605  } else {
606  if (hour_ > 12) {
607  pm_flag = true;
608  hour_value = hour_ - 12;
609  } else {
610  hour_value = hour_ == 0 ? 12 : hour_;
611  pm_flag = hour_ == 12 ? true : false;
612  }
613  }
614 
615  static const char kHMSFormat[] = " %d:%02d:%02d%s";
616  static const char kHMFormat[] = " %d:%02d%s";
617  static const char kHFormat[] = " %d%s";
618 
620  char output_buffer[256];
621  switch (output_time_format) {
623  snprintf(output_buffer, sizeof(output_buffer), kHMSFormat,
624  hour_value,
625  minute_,
626  second_,
627  Use24HourTime() ? "" : (pm_flag ? " pm" : " am"));
628  break;
629  case kRenderHoursMinutes:
630  snprintf(output_buffer, sizeof(output_buffer), kHMFormat,
631  hour_value,
632  minute_,
633  Use24HourTime() ? "" : (pm_flag ? " pm" : " am"));
634  break;
635  case kRenderHoursOnly:
636  snprintf(output_buffer, sizeof(output_buffer), kHFormat,
637  hour_value,
638  Use24HourTime() ? "" : (pm_flag ? " pm" : " am"));
639  break;
640  default:
641  DCHECK(false) << "Invalid TimeStringEnum passed to "
642  "DateTime::ComputeTimeString()";
643  }
644  *out_string = std::string(output_buffer);
645 }
646 
650  static const std::string kFormatToUse("using am/pm time format");
651  return kFormatToUse == "24";
652 }
653 
654 std::string DateTime::ComputeDurationString(double fractional_seconds) const {
655  static const char kFieldSuffix[] = "ymdhms";
656 
660  uint8 field_index = 0;
661  while (field_index < static_cast<uint8>(kNanosecond)
662  && GetDateTimeField(field_index) == 0) {
663  ++field_index;
664  }
665 
667  if (field_index == static_cast<uint8>(kNanosecond))
668  return std::string("0.0s");
669 
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) {
678  int64 value = GetDateTimeField(field_index);
679  if (value == 0)
680  continue;
681 
682  output_chars += snprintf(&output_buffer[0] + output_chars,
683  256 - output_chars, "%llu%c ", value, kFieldSuffix[field_index]);
684  }
685 
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]);
692  }
693 
694  return ion::base::TrimStartAndEndWhitespace(std::string(output_buffer));
695 }
696 
697 bool DateTime::operator>(const DateTime& dtime) const {
698  DateTime norm_this(*this);
699  norm_this.Normalize();
700  DateTime norm_other(dtime);
701  norm_other.Normalize();
702  if (norm_this.year_ > norm_other.year_)
703  return 1;
704  else if (norm_this.year_ < norm_other.year_)
705  return 0;
706  else if (norm_this.month_ > norm_other.month_)
707  return 1;
708  else if (norm_this.month_ < norm_other.month_)
709  return 0;
710  else if (norm_this.day_ > norm_other.day_)
711  return 1;
712  else if (norm_this.day_ < norm_other.day_)
713  return 0;
714  else if (norm_this.hour_ > norm_other.hour_)
715  return 1;
716  else if (norm_this.hour_ < norm_other.hour_)
717  return 0;
718  else if (norm_this.minute_ > norm_other.minute_)
719  return 1;
720  else if (norm_this.minute_ < norm_other.minute_)
721  return 0;
722  else if (norm_this.second_ > norm_other.second_)
723  return 1;
724  else if (norm_this.second_ < norm_other.second_)
725  return 0;
726  else if (norm_this.nanosecond_ > norm_other.nanosecond_)
727  return 1;
728  else if (norm_this.nanosecond_ < norm_other.nanosecond_)
729  return 0;
730 
731  return 0;
732 }
733 
734 bool DateTime::operator==(const DateTime& dtime) const {
735  DateTime norm_this(*this);
736  DateTime norm_other(dtime);
737  norm_this.Normalize();
738  norm_other.Normalize();
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_);
748 }
749 
750 bool DateTime::IsEqualByComponent(const DateTime& dtime) const {
751  return (
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_);
756 }
757 
758 std::chrono::system_clock::time_point DateTime::GetTimePoint() const {
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_)));
766 }
767 
768 double DateTime::GetJulianDate() const {
769  int month = month_;
770  int year = static_cast<int>(year_);
773  if (month_ == 1 || month_ == 2) {
774  year -= 1;
775  month += 12;
776  }
777 
779  double time = GetTimeAsDecimal();
780 
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;
788 
789  return day + time;
790 }
791 
793  double val = nanosecond_;
794  val = val * 1e-9 + second_;
795  val = val / 60.0 + minute_;
796  val = val / 60.0 + hour_;
797  val = val / 24.0;
798  return val;
799 }
800 
801 void DateTime::AdjustTimeZone(int new_hours, int new_mins) {
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; // Preserve old nanoseconds.
809  }
810 }
811 
813  if (this != &rhs) {
814  Set(rhs);
815  }
816  return *this;
817 }
818 
820  const DateTime& end,
821  double t) {
822  if (t == 1.0)
823  return end;
824  double interp_offset = GetDurationSecs(begin, end) * t;
825  DateTime ret_val = begin;
826  ret_val += interp_offset;
827  return ret_val;
828 }
829 
830 double DateTime::GetDurationSecs(const DateTime& begin, const DateTime& end) {
833  int64 begin_secs = begin.GetPosixSecondsOnly();
834  int64 end_secs = end.GetPosixSecondsOnly();
835 
839  double duration = static_cast<double>(end_secs - begin_secs);
840 
842  duration += (static_cast<int32>(end.nanosecond_) -
843  static_cast<int32>(begin.nanosecond_)) *
844  1e-9;
845  return duration;
846 }
847 
849  const DateTime& time_a,
850  const DateTime& time_b) {
852  int64 a_secs = time_a.GetPosixSecondsOnly();
853  int64 b_secs = time_b.GetPosixSecondsOnly();
854  int64 now_secs = now.GetPosixSecondsOnly();
855 
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_)) *
860  1e-9;
861 
862  if (time_range == 0.0)
863  return 0.0;
864 
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_)) *
868  1e-9;
869  return time_from_a / time_range;
870 }
871 
872 void DateTime::operator+=(double secs) {
873  int64 total_seconds = GetPosixSecondsOnly();
874  int32 total_nanoseconds = nanosecond_;
878  DCHECK_LT(total_nanoseconds, kNanoSecondsPerSecond);
879 
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) {
885  total_seconds += 1;
886  total_nanoseconds -= kNanoSecondsPerSecond;
887  } else if (total_nanoseconds < 0) {
888  total_seconds -= 1;
889  total_nanoseconds += kNanoSecondsPerSecond;
890  }
891 
892  SetFromPosixSecondsOnly(total_seconds, zone_hours_, zone_minutes_);
893  nanosecond_ = total_nanoseconds;
894 }
895 
896 bool DateTime::ParseYMString(const std::string& str, DateTime* date_out) {
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;
905  }
906  if (date_out)
907  date_out->Set(
908  ion::base::StringToInt32(str.substr(0, 4)),
909  static_cast<uint8>(ion::base::StringToInt32(str.substr(5, 2))), 0, 0,
910  0, 0, 0, 0);
911  return true;
912  }
913  return false;
914 }
915 
916 void DateTime::Lerp(const DateTime& origin, const DateTime& target, double t) {
917  *this = Interpolate(origin, target, t);
918 }
919 
921  switch (field) {
922  case kYear:
923  return year_;
924  case kMonth:
925  return month_;
926  case kDay:
927  return day_;
928  case kHour:
929  return hour_;
930  case kMinute:
931  return minute_;
932  case kSecond:
933  return second_;
934  case kNanosecond:
935  return nanosecond_;
936  default: {
937  LOG(ERROR) << "Invalid DateTime field provided to GetDateTimeField().";
938  return -1;
939  }
940  }
941 }
942 
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);
947 
949  int64 zh = static_cast<int64>(requested_zone_hours);
950  int64 zm = static_cast<int64>(requested_zone_minutes);
951  secs += ((zh * 60) + zm) * 60;
952 
954  int64 days = secs / (24 * 60 * 60);
955 
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);
967 
972  int64 days_left = days;
973  int64 guess_years = 1970; // Guessed number of years.
974  static const double days_to_years = 1. / 365.;
977  int64 years_left;
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);
984  }
987  DCHECK_GE(days_left, -366);
988  DCHECK_LE(days_left, 366);
989  days = days_left + 1; // Days are one-indexed.
990  year_ = guess_years;
991 
993  while (days < 1) {
995  days += MaximumDayInMonthFor(year_, month_ - 1);
996  int t = month_ - 1;
997  month_ = static_cast<uint8>(Modulo(t, 1, 13));
998  year_ += Quotient(t, 1, 13);
999  }
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;
1005  int t = month_ + 1;
1006  month_ = static_cast<uint8>(Modulo(t, 1, 13));
1007  year_ += Quotient(t, 1, 13);
1008  }
1009  day_ = static_cast<uint8>(days);
1010 }
1011 
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_;
1021 
1022  int64 secs_big = second_;
1023 
1024  return ((((days_big * 24) + hours_big) * 60) + mins_big) * 60 + secs_big;
1025 }
1026 
1027 } // namespace base
1028 } // namespace ion
const std::string & str
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...
Definition: datetime.cc:830
void SetSecond(uint8 second)
Definition: datetime.cc:241
int64 GetDateTimeField(DateTimeField field) const
Returns a specific field value in the DateTime object as defined by DateTimeField field (kYear...
Definition: datetime.cc:920
void Normalize()
Converts this DateTime to UTC time (+0:00 time zone).
Definition: datetime.h:188
bool operator==(const DateTime &dtime) const
This operator converts the date times to absolute and compares the absolute times for equality (hence...
Definition: datetime.cc:734
#define DCHECK(expr)
Definition: logging.h:331
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...
Definition: datetime.cc:848
double value
std::string ToString() const
Converts time to user-readable string.
Definition: datetime.cc:310
void SetNanosecond(uint32 nanosecond)
Definition: datetime.cc:248
#define LOG(severity)
Logs the streamed message unconditionally with a severity of severity.
Definition: logging.h:216
std::istream & operator>>(std::istream &in, DateTime &dtime)
Definition: datetime.cc:516
std::string TrimStartAndEndWhitespace(const std::string &target)
Removes any whitespace characters at the beginning and end of the string.
Definition: stringutils.h:155
bool operator>(const DateTime &dtime) const
Definition: datetime.cc:697
void SetDay(uint8 day)
Definition: datetime.cc:217
std::ostream & operator<<(std::ostream &os, const DateTime &dtime)
Definition: datetime.cc:361
std::string ComputeDurationString(double fractional_seconds) const
Returns string for 'this', e.g., "2y3m18d", interpreted as a duration.
Definition: datetime.cc:654
static bool ParseYMString(const std::string &date, DateTime *date_out)
Checks if given string is in YYYY-MM formatr.
Definition: datetime.cc:896
void SetZoneMinutes(int8 zone_minutes)
Definition: datetime.cc:264
DateTimeField
Enumeration of the time-value fields of DateTime (used for iteration and numerical access)...
Definition: datetime.h:51
#define DCHECK_NE(val1, val2)
Definition: logging.h:333
double GetTimeAsDecimal() const
Convert "Standard" time to decimal time (or "French Revolutionary" time).
Definition: datetime.cc:792
void SetYear(int64 year)
Mutators for individual fields.
Definition: datetime.cc:203
bool IsEqualByComponent(const DateTime &dtime) const
Checks each component of the time object, including time zone.
Definition: datetime.cc:750
void ComputeDateString(const DateStringEnum output_date_format, std::string *out_string) const
Definition: datetime.cc:529
DateTime represents a particular date and time down to the nanosecond level along with timezone infor...
Definition: datetime.h:45
int32 ION_API StringToInt32(const std::string &str)
Extracts and returns an integral value from str.
Definition: stringutils.cc:328
double GetJulianDate() const
The Julian Day is the integer number of days that have elapsed since noon on Monday, January 1, 4713 BC.
Definition: datetime.cc:768
void SetZoneHours(int8 zone_hours)
Definition: datetime.cc:256
#define DCHECK_GE(val1, val2)
Definition: logging.h:336
void SetMonth(uint8 month)
Definition: datetime.cc:209
void SetMinute(uint8 minute)
Definition: datetime.cc:234
virtual bool Use24HourTime() const
Determines whether to render 24-hour time strings based on a value set by translators.
Definition: datetime.cc:647
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...
Definition: datetime.cc:916
void AdjustTimeZone(int newHours, int newMins)
Converts time to another time zone.
Definition: datetime.cc:801
void ComputeTimeString(const TimeStringEnum output_time_format, std::string *out_string) const
Definition: datetime.cc:598
Copyright 2016 Google Inc.
uint32 GetNanosecond() const
Definition: datetime.h:147
void Reset()
Set the DateTime to default values (<year>/1/1T00:00:00.0Z00:00, where <year> is set as kUndefinedYea...
Definition: datetime.cc:169
DateStringEnum
ComputeDateString() and ComputeTimeString() render the DateTime object to a std::string.
Definition: datetime.h:238
DateTime & operator=(const DateTime &rhs)
Definition: datetime.cc:812
#define DCHECK_LE(val1, val2)
Definition: logging.h:334
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...
Definition: datetime.cc:819
void operator+=(int64 secs)
Definition: datetime.h:291
void Set(int64 years, uint8 months, uint8 days, uint8 hours, uint8 minutes, uint8 seconds, int8 zone_hours, int8 zone_minutes)
Definition: datetime.cc:273
bool FromString(const std::string &str)
Parses str into this DateTime object.
Definition: datetime.cc:366
void SetHour(uint8 hour)
Definition: datetime.cc:226
#define DCHECK_LT(val1, val2)
Definition: logging.h:335
std::chrono::system_clock::time_point GetTimePoint() const
Return a std::chrono::system_clock::time_point.
Definition: datetime.cc:758