• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // The implementation of the absl::Time class, which is declared in
16 // //absl/time.h.
17 //
18 // The representation for an absl::Time is an absl::Duration offset from the
19 // epoch.  We use the traditional Unix epoch (1970-01-01 00:00:00 +0000)
20 // for convenience, but this is not exposed in the API and could be changed.
21 //
22 // NOTE: To keep type verbosity to a minimum, the following variable naming
23 // conventions are used throughout this file.
24 //
25 // tz: An absl::TimeZone
26 // ci: An absl::TimeZone::CivilInfo
27 // ti: An absl::TimeZone::TimeInfo
28 // cd: An absl::CivilDay or a cctz::civil_day
29 // cs: An absl::CivilSecond or a cctz::civil_second
30 // bd: An absl::Time::Breakdown
31 // cl: A cctz::time_zone::civil_lookup
32 // al: A cctz::time_zone::absolute_lookup
33 
34 #include "absl/time/time.h"
35 
36 #if defined(_MSC_VER)
37 #include <winsock2.h>  // for timeval
38 #endif
39 
40 #include <cstring>
41 #include <ctime>
42 #include <limits>
43 
44 #include "absl/time/internal/cctz/include/cctz/civil_time.h"
45 #include "absl/time/internal/cctz/include/cctz/time_zone.h"
46 
47 namespace cctz = absl::time_internal::cctz;
48 
49 namespace absl {
50 ABSL_NAMESPACE_BEGIN
51 
52 namespace {
53 
unix_epoch()54 inline cctz::time_point<cctz::seconds> unix_epoch() {
55   return std::chrono::time_point_cast<cctz::seconds>(
56       std::chrono::system_clock::from_time_t(0));
57 }
58 
59 // Floors d to the next unit boundary closer to negative infinity.
FloorToUnit(absl::Duration d,absl::Duration unit)60 inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) {
61   absl::Duration rem;
62   int64_t q = absl::IDivDuration(d, unit, &rem);
63   return (q > 0 ||
64           rem >= ZeroDuration() ||
65           q == std::numeric_limits<int64_t>::min()) ? q : q - 1;
66 }
67 
InfiniteFutureBreakdown()68 inline absl::Time::Breakdown InfiniteFutureBreakdown() {
69   absl::Time::Breakdown bd;
70   bd.year = std::numeric_limits<int64_t>::max();
71   bd.month = 12;
72   bd.day = 31;
73   bd.hour = 23;
74   bd.minute = 59;
75   bd.second = 59;
76   bd.subsecond = absl::InfiniteDuration();
77   bd.weekday = 4;
78   bd.yearday = 365;
79   bd.offset = 0;
80   bd.is_dst = false;
81   bd.zone_abbr = "-00";
82   return bd;
83 }
84 
InfinitePastBreakdown()85 inline absl::Time::Breakdown InfinitePastBreakdown() {
86   Time::Breakdown bd;
87   bd.year = std::numeric_limits<int64_t>::min();
88   bd.month = 1;
89   bd.day = 1;
90   bd.hour = 0;
91   bd.minute = 0;
92   bd.second = 0;
93   bd.subsecond = -absl::InfiniteDuration();
94   bd.weekday = 7;
95   bd.yearday = 1;
96   bd.offset = 0;
97   bd.is_dst = false;
98   bd.zone_abbr = "-00";
99   return bd;
100 }
101 
InfiniteFutureCivilInfo()102 inline absl::TimeZone::CivilInfo InfiniteFutureCivilInfo() {
103   TimeZone::CivilInfo ci;
104   ci.cs = CivilSecond::max();
105   ci.subsecond = InfiniteDuration();
106   ci.offset = 0;
107   ci.is_dst = false;
108   ci.zone_abbr = "-00";
109   return ci;
110 }
111 
InfinitePastCivilInfo()112 inline absl::TimeZone::CivilInfo InfinitePastCivilInfo() {
113   TimeZone::CivilInfo ci;
114   ci.cs = CivilSecond::min();
115   ci.subsecond = -InfiniteDuration();
116   ci.offset = 0;
117   ci.is_dst = false;
118   ci.zone_abbr = "-00";
119   return ci;
120 }
121 
InfiniteFutureTimeConversion()122 inline absl::TimeConversion InfiniteFutureTimeConversion() {
123   absl::TimeConversion tc;
124   tc.pre = tc.trans = tc.post = absl::InfiniteFuture();
125   tc.kind = absl::TimeConversion::UNIQUE;
126   tc.normalized = true;
127   return tc;
128 }
129 
InfinitePastTimeConversion()130 inline TimeConversion InfinitePastTimeConversion() {
131   absl::TimeConversion tc;
132   tc.pre = tc.trans = tc.post = absl::InfinitePast();
133   tc.kind = absl::TimeConversion::UNIQUE;
134   tc.normalized = true;
135   return tc;
136 }
137 
138 // Makes a Time from sec, overflowing to InfiniteFuture/InfinitePast as
139 // necessary. If sec is min/max, then consult cs+tz to check for overlow.
MakeTimeWithOverflow(const cctz::time_point<cctz::seconds> & sec,const cctz::civil_second & cs,const cctz::time_zone & tz,bool * normalized=nullptr)140 Time MakeTimeWithOverflow(const cctz::time_point<cctz::seconds>& sec,
141                           const cctz::civil_second& cs,
142                           const cctz::time_zone& tz,
143                           bool* normalized = nullptr) {
144   const auto max = cctz::time_point<cctz::seconds>::max();
145   const auto min = cctz::time_point<cctz::seconds>::min();
146   if (sec == max) {
147     const auto al = tz.lookup(max);
148     if (cs > al.cs) {
149       if (normalized) *normalized = true;
150       return absl::InfiniteFuture();
151     }
152   }
153   if (sec == min) {
154     const auto al = tz.lookup(min);
155     if (cs < al.cs) {
156       if (normalized) *normalized = true;
157       return absl::InfinitePast();
158     }
159   }
160   const auto hi = (sec - unix_epoch()).count();
161   return time_internal::FromUnixDuration(time_internal::MakeDuration(hi));
162 }
163 
164 // Returns Mon=1..Sun=7.
MapWeekday(const cctz::weekday & wd)165 inline int MapWeekday(const cctz::weekday& wd) {
166   switch (wd) {
167     case cctz::weekday::monday:
168       return 1;
169     case cctz::weekday::tuesday:
170       return 2;
171     case cctz::weekday::wednesday:
172       return 3;
173     case cctz::weekday::thursday:
174       return 4;
175     case cctz::weekday::friday:
176       return 5;
177     case cctz::weekday::saturday:
178       return 6;
179     case cctz::weekday::sunday:
180       return 7;
181   }
182   return 1;
183 }
184 
FindTransition(const cctz::time_zone & tz,bool (cctz::time_zone::* find_transition)(const cctz::time_point<cctz::seconds> & tp,cctz::time_zone::civil_transition * trans)const,Time t,TimeZone::CivilTransition * trans)185 bool FindTransition(const cctz::time_zone& tz,
186                     bool (cctz::time_zone::*find_transition)(
187                         const cctz::time_point<cctz::seconds>& tp,
188                         cctz::time_zone::civil_transition* trans) const,
189                     Time t, TimeZone::CivilTransition* trans) {
190   // Transitions are second-aligned, so we can discard any fractional part.
191   const auto tp = unix_epoch() + cctz::seconds(ToUnixSeconds(t));
192   cctz::time_zone::civil_transition tr;
193   if (!(tz.*find_transition)(tp, &tr)) return false;
194   trans->from = CivilSecond(tr.from);
195   trans->to = CivilSecond(tr.to);
196   return true;
197 }
198 
199 }  // namespace
200 
201 //
202 // Time
203 //
204 
In(absl::TimeZone tz) const205 absl::Time::Breakdown Time::In(absl::TimeZone tz) const {
206   if (*this == absl::InfiniteFuture()) return InfiniteFutureBreakdown();
207   if (*this == absl::InfinitePast()) return InfinitePastBreakdown();
208 
209   const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(rep_));
210   const auto al = cctz::time_zone(tz).lookup(tp);
211   const auto cs = al.cs;
212   const auto cd = cctz::civil_day(cs);
213 
214   absl::Time::Breakdown bd;
215   bd.year = cs.year();
216   bd.month = cs.month();
217   bd.day = cs.day();
218   bd.hour = cs.hour();
219   bd.minute = cs.minute();
220   bd.second = cs.second();
221   bd.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(rep_));
222   bd.weekday = MapWeekday(cctz::get_weekday(cd));
223   bd.yearday = cctz::get_yearday(cd);
224   bd.offset = al.offset;
225   bd.is_dst = al.is_dst;
226   bd.zone_abbr = al.abbr;
227   return bd;
228 }
229 
230 //
231 // Conversions from/to other time types.
232 //
233 
FromUDate(double udate)234 absl::Time FromUDate(double udate) {
235   return time_internal::FromUnixDuration(absl::Milliseconds(udate));
236 }
237 
FromUniversal(int64_t universal)238 absl::Time FromUniversal(int64_t universal) {
239   return absl::UniversalEpoch() + 100 * absl::Nanoseconds(universal);
240 }
241 
ToUnixNanos(Time t)242 int64_t ToUnixNanos(Time t) {
243   if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
244       time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 33 == 0) {
245     return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *
246             1000 * 1000 * 1000) +
247            (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4);
248   }
249   return FloorToUnit(time_internal::ToUnixDuration(t), absl::Nanoseconds(1));
250 }
251 
ToUnixMicros(Time t)252 int64_t ToUnixMicros(Time t) {
253   if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
254       time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 43 == 0) {
255     return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *
256             1000 * 1000) +
257            (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4000);
258   }
259   return FloorToUnit(time_internal::ToUnixDuration(t), absl::Microseconds(1));
260 }
261 
ToUnixMillis(Time t)262 int64_t ToUnixMillis(Time t) {
263   if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
264       time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 53 == 0) {
265     return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * 1000) +
266            (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) /
267             (4000 * 1000));
268   }
269   return FloorToUnit(time_internal::ToUnixDuration(t), absl::Milliseconds(1));
270 }
271 
ToUnixSeconds(Time t)272 int64_t ToUnixSeconds(Time t) {
273   return time_internal::GetRepHi(time_internal::ToUnixDuration(t));
274 }
275 
ToTimeT(Time t)276 time_t ToTimeT(Time t) { return absl::ToTimespec(t).tv_sec; }
277 
ToUDate(Time t)278 double ToUDate(Time t) {
279   return absl::FDivDuration(time_internal::ToUnixDuration(t),
280                             absl::Milliseconds(1));
281 }
282 
ToUniversal(absl::Time t)283 int64_t ToUniversal(absl::Time t) {
284   return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100));
285 }
286 
TimeFromTimespec(timespec ts)287 absl::Time TimeFromTimespec(timespec ts) {
288   return time_internal::FromUnixDuration(absl::DurationFromTimespec(ts));
289 }
290 
TimeFromTimeval(timeval tv)291 absl::Time TimeFromTimeval(timeval tv) {
292   return time_internal::FromUnixDuration(absl::DurationFromTimeval(tv));
293 }
294 
ToTimespec(Time t)295 timespec ToTimespec(Time t) {
296   timespec ts;
297   absl::Duration d = time_internal::ToUnixDuration(t);
298   if (!time_internal::IsInfiniteDuration(d)) {
299     ts.tv_sec = time_internal::GetRepHi(d);
300     if (ts.tv_sec == time_internal::GetRepHi(d)) {  // no time_t narrowing
301       ts.tv_nsec = time_internal::GetRepLo(d) / 4;  // floor
302       return ts;
303     }
304   }
305   if (d >= absl::ZeroDuration()) {
306     ts.tv_sec = std::numeric_limits<time_t>::max();
307     ts.tv_nsec = 1000 * 1000 * 1000 - 1;
308   } else {
309     ts.tv_sec = std::numeric_limits<time_t>::min();
310     ts.tv_nsec = 0;
311   }
312   return ts;
313 }
314 
ToTimeval(Time t)315 timeval ToTimeval(Time t) {
316   timeval tv;
317   timespec ts = absl::ToTimespec(t);
318   tv.tv_sec = ts.tv_sec;
319   if (tv.tv_sec != ts.tv_sec) {  // narrowing
320     if (ts.tv_sec < 0) {
321       tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min();
322       tv.tv_usec = 0;
323     } else {
324       tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max();
325       tv.tv_usec = 1000 * 1000 - 1;
326     }
327     return tv;
328   }
329   tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000);  // suseconds_t
330   return tv;
331 }
332 
FromChrono(const std::chrono::system_clock::time_point & tp)333 Time FromChrono(const std::chrono::system_clock::time_point& tp) {
334   return time_internal::FromUnixDuration(time_internal::FromChrono(
335       tp - std::chrono::system_clock::from_time_t(0)));
336 }
337 
ToChronoTime(absl::Time t)338 std::chrono::system_clock::time_point ToChronoTime(absl::Time t) {
339   using D = std::chrono::system_clock::duration;
340   auto d = time_internal::ToUnixDuration(t);
341   if (d < ZeroDuration()) d = Floor(d, FromChrono(D{1}));
342   return std::chrono::system_clock::from_time_t(0) +
343          time_internal::ToChronoDuration<D>(d);
344 }
345 
346 //
347 // TimeZone
348 //
349 
At(Time t) const350 absl::TimeZone::CivilInfo TimeZone::At(Time t) const {
351   if (t == absl::InfiniteFuture()) return InfiniteFutureCivilInfo();
352   if (t == absl::InfinitePast()) return InfinitePastCivilInfo();
353 
354   const auto ud = time_internal::ToUnixDuration(t);
355   const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(ud));
356   const auto al = cz_.lookup(tp);
357 
358   TimeZone::CivilInfo ci;
359   ci.cs = CivilSecond(al.cs);
360   ci.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(ud));
361   ci.offset = al.offset;
362   ci.is_dst = al.is_dst;
363   ci.zone_abbr = al.abbr;
364   return ci;
365 }
366 
At(CivilSecond ct) const367 absl::TimeZone::TimeInfo TimeZone::At(CivilSecond ct) const {
368   const cctz::civil_second cs(ct);
369   const auto cl = cz_.lookup(cs);
370 
371   TimeZone::TimeInfo ti;
372   switch (cl.kind) {
373     case cctz::time_zone::civil_lookup::UNIQUE:
374       ti.kind = TimeZone::TimeInfo::UNIQUE;
375       break;
376     case cctz::time_zone::civil_lookup::SKIPPED:
377       ti.kind = TimeZone::TimeInfo::SKIPPED;
378       break;
379     case cctz::time_zone::civil_lookup::REPEATED:
380       ti.kind = TimeZone::TimeInfo::REPEATED;
381       break;
382   }
383   ti.pre = MakeTimeWithOverflow(cl.pre, cs, cz_);
384   ti.trans = MakeTimeWithOverflow(cl.trans, cs, cz_);
385   ti.post = MakeTimeWithOverflow(cl.post, cs, cz_);
386   return ti;
387 }
388 
NextTransition(Time t,CivilTransition * trans) const389 bool TimeZone::NextTransition(Time t, CivilTransition* trans) const {
390   return FindTransition(cz_, &cctz::time_zone::next_transition, t, trans);
391 }
392 
PrevTransition(Time t,CivilTransition * trans) const393 bool TimeZone::PrevTransition(Time t, CivilTransition* trans) const {
394   return FindTransition(cz_, &cctz::time_zone::prev_transition, t, trans);
395 }
396 
397 //
398 // Conversions involving time zones.
399 //
400 
ConvertDateTime(int64_t year,int mon,int day,int hour,int min,int sec,TimeZone tz)401 absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
402                                      int min, int sec, TimeZone tz) {
403   // Avoids years that are too extreme for CivilSecond to normalize.
404   if (year > 300000000000) return InfiniteFutureTimeConversion();
405   if (year < -300000000000) return InfinitePastTimeConversion();
406 
407   const CivilSecond cs(year, mon, day, hour, min, sec);
408   const auto ti = tz.At(cs);
409 
410   TimeConversion tc;
411   tc.pre = ti.pre;
412   tc.trans = ti.trans;
413   tc.post = ti.post;
414   switch (ti.kind) {
415     case TimeZone::TimeInfo::UNIQUE:
416       tc.kind = TimeConversion::UNIQUE;
417       break;
418     case TimeZone::TimeInfo::SKIPPED:
419       tc.kind = TimeConversion::SKIPPED;
420       break;
421     case TimeZone::TimeInfo::REPEATED:
422       tc.kind = TimeConversion::REPEATED;
423       break;
424   }
425   tc.normalized = false;
426   if (year != cs.year() || mon != cs.month() || day != cs.day() ||
427       hour != cs.hour() || min != cs.minute() || sec != cs.second()) {
428     tc.normalized = true;
429   }
430   return tc;
431 }
432 
FromTM(const struct tm & tm,absl::TimeZone tz)433 absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) {
434   civil_year_t tm_year = tm.tm_year;
435   // Avoids years that are too extreme for CivilSecond to normalize.
436   if (tm_year > 300000000000ll) return InfiniteFuture();
437   if (tm_year < -300000000000ll) return InfinitePast();
438   int tm_mon = tm.tm_mon;
439   if (tm_mon == std::numeric_limits<int>::max()) {
440     tm_mon -= 12;
441     tm_year += 1;
442   }
443   const auto ti = tz.At(CivilSecond(tm_year + 1900, tm_mon + 1, tm.tm_mday,
444                                     tm.tm_hour, tm.tm_min, tm.tm_sec));
445   return tm.tm_isdst == 0 ? ti.post : ti.pre;
446 }
447 
ToTM(absl::Time t,absl::TimeZone tz)448 struct tm ToTM(absl::Time t, absl::TimeZone tz) {
449   struct tm tm = {};
450 
451   const auto ci = tz.At(t);
452   const auto& cs = ci.cs;
453   tm.tm_sec = cs.second();
454   tm.tm_min = cs.minute();
455   tm.tm_hour = cs.hour();
456   tm.tm_mday = cs.day();
457   tm.tm_mon = cs.month() - 1;
458 
459   // Saturates tm.tm_year in cases of over/underflow, accounting for the fact
460   // that tm.tm_year is years since 1900.
461   if (cs.year() < std::numeric_limits<int>::min() + 1900) {
462     tm.tm_year = std::numeric_limits<int>::min();
463   } else if (cs.year() > std::numeric_limits<int>::max()) {
464     tm.tm_year = std::numeric_limits<int>::max() - 1900;
465   } else {
466     tm.tm_year = static_cast<int>(cs.year() - 1900);
467   }
468 
469   switch (GetWeekday(cs)) {
470     case Weekday::sunday:
471       tm.tm_wday = 0;
472       break;
473     case Weekday::monday:
474       tm.tm_wday = 1;
475       break;
476     case Weekday::tuesday:
477       tm.tm_wday = 2;
478       break;
479     case Weekday::wednesday:
480       tm.tm_wday = 3;
481       break;
482     case Weekday::thursday:
483       tm.tm_wday = 4;
484       break;
485     case Weekday::friday:
486       tm.tm_wday = 5;
487       break;
488     case Weekday::saturday:
489       tm.tm_wday = 6;
490       break;
491   }
492   tm.tm_yday = GetYearDay(cs) - 1;
493   tm.tm_isdst = ci.is_dst ? 1 : 0;
494 
495   return tm;
496 }
497 
498 ABSL_NAMESPACE_END
499 }  // namespace absl
500