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 || rem >= ZeroDuration() ||
64 q == std::numeric_limits<int64_t>::min())
65 ? q
66 : q - 1;
67 }
68
69 ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
InfiniteFutureBreakdown()70 inline absl::Time::Breakdown InfiniteFutureBreakdown() {
71 absl::Time::Breakdown bd;
72 bd.year = std::numeric_limits<int64_t>::max();
73 bd.month = 12;
74 bd.day = 31;
75 bd.hour = 23;
76 bd.minute = 59;
77 bd.second = 59;
78 bd.subsecond = absl::InfiniteDuration();
79 bd.weekday = 4;
80 bd.yearday = 365;
81 bd.offset = 0;
82 bd.is_dst = false;
83 bd.zone_abbr = "-00";
84 return bd;
85 }
86
InfinitePastBreakdown()87 inline absl::Time::Breakdown InfinitePastBreakdown() {
88 Time::Breakdown bd;
89 bd.year = std::numeric_limits<int64_t>::min();
90 bd.month = 1;
91 bd.day = 1;
92 bd.hour = 0;
93 bd.minute = 0;
94 bd.second = 0;
95 bd.subsecond = -absl::InfiniteDuration();
96 bd.weekday = 7;
97 bd.yearday = 1;
98 bd.offset = 0;
99 bd.is_dst = false;
100 bd.zone_abbr = "-00";
101 return bd;
102 }
103 ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
104
InfiniteFutureCivilInfo()105 inline absl::TimeZone::CivilInfo InfiniteFutureCivilInfo() {
106 TimeZone::CivilInfo ci;
107 ci.cs = CivilSecond::max();
108 ci.subsecond = InfiniteDuration();
109 ci.offset = 0;
110 ci.is_dst = false;
111 ci.zone_abbr = "-00";
112 return ci;
113 }
114
InfinitePastCivilInfo()115 inline absl::TimeZone::CivilInfo InfinitePastCivilInfo() {
116 TimeZone::CivilInfo ci;
117 ci.cs = CivilSecond::min();
118 ci.subsecond = -InfiniteDuration();
119 ci.offset = 0;
120 ci.is_dst = false;
121 ci.zone_abbr = "-00";
122 return ci;
123 }
124
125 ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
InfiniteFutureTimeConversion()126 inline absl::TimeConversion InfiniteFutureTimeConversion() {
127 absl::TimeConversion tc;
128 tc.pre = tc.trans = tc.post = absl::InfiniteFuture();
129 tc.kind = absl::TimeConversion::UNIQUE;
130 tc.normalized = true;
131 return tc;
132 }
133
InfinitePastTimeConversion()134 inline TimeConversion InfinitePastTimeConversion() {
135 absl::TimeConversion tc;
136 tc.pre = tc.trans = tc.post = absl::InfinitePast();
137 tc.kind = absl::TimeConversion::UNIQUE;
138 tc.normalized = true;
139 return tc;
140 }
141 ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
142
143 // Makes a Time from sec, overflowing to InfiniteFuture/InfinitePast as
144 // necessary. If sec is min/max, then consult cs+tz to check for overflow.
MakeTimeWithOverflow(const cctz::time_point<cctz::seconds> & sec,const cctz::civil_second & cs,const cctz::time_zone & tz,bool * normalized=nullptr)145 Time MakeTimeWithOverflow(const cctz::time_point<cctz::seconds>& sec,
146 const cctz::civil_second& cs,
147 const cctz::time_zone& tz,
148 bool* normalized = nullptr) {
149 const auto max = cctz::time_point<cctz::seconds>::max();
150 const auto min = cctz::time_point<cctz::seconds>::min();
151 if (sec == max) {
152 const auto al = tz.lookup(max);
153 if (cs > al.cs) {
154 if (normalized) *normalized = true;
155 return absl::InfiniteFuture();
156 }
157 }
158 if (sec == min) {
159 const auto al = tz.lookup(min);
160 if (cs < al.cs) {
161 if (normalized) *normalized = true;
162 return absl::InfinitePast();
163 }
164 }
165 const auto hi = (sec - unix_epoch()).count();
166 return time_internal::FromUnixDuration(time_internal::MakeDuration(hi));
167 }
168
169 // Returns Mon=1..Sun=7.
MapWeekday(const cctz::weekday & wd)170 inline int MapWeekday(const cctz::weekday& wd) {
171 switch (wd) {
172 case cctz::weekday::monday:
173 return 1;
174 case cctz::weekday::tuesday:
175 return 2;
176 case cctz::weekday::wednesday:
177 return 3;
178 case cctz::weekday::thursday:
179 return 4;
180 case cctz::weekday::friday:
181 return 5;
182 case cctz::weekday::saturday:
183 return 6;
184 case cctz::weekday::sunday:
185 return 7;
186 }
187 return 1;
188 }
189
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)190 bool FindTransition(const cctz::time_zone& tz,
191 bool (cctz::time_zone::*find_transition)(
192 const cctz::time_point<cctz::seconds>& tp,
193 cctz::time_zone::civil_transition* trans) const,
194 Time t, TimeZone::CivilTransition* trans) {
195 // Transitions are second-aligned, so we can discard any fractional part.
196 const auto tp = unix_epoch() + cctz::seconds(ToUnixSeconds(t));
197 cctz::time_zone::civil_transition tr;
198 if (!(tz.*find_transition)(tp, &tr)) return false;
199 trans->from = CivilSecond(tr.from);
200 trans->to = CivilSecond(tr.to);
201 return true;
202 }
203
204 } // namespace
205
206 //
207 // Time
208 //
209
210 ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
In(absl::TimeZone tz) const211 absl::Time::Breakdown Time::In(absl::TimeZone tz) const {
212 if (*this == absl::InfiniteFuture()) return InfiniteFutureBreakdown();
213 if (*this == absl::InfinitePast()) return InfinitePastBreakdown();
214
215 const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(rep_));
216 const auto al = cctz::time_zone(tz).lookup(tp);
217 const auto cs = al.cs;
218 const auto cd = cctz::civil_day(cs);
219
220 absl::Time::Breakdown bd;
221 bd.year = cs.year();
222 bd.month = cs.month();
223 bd.day = cs.day();
224 bd.hour = cs.hour();
225 bd.minute = cs.minute();
226 bd.second = cs.second();
227 bd.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(rep_));
228 bd.weekday = MapWeekday(cctz::get_weekday(cd));
229 bd.yearday = cctz::get_yearday(cd);
230 bd.offset = al.offset;
231 bd.is_dst = al.is_dst;
232 bd.zone_abbr = al.abbr;
233 return bd;
234 }
235 ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
236
237 //
238 // Conversions from/to other time types.
239 //
240
FromUDate(double udate)241 absl::Time FromUDate(double udate) {
242 return time_internal::FromUnixDuration(absl::Milliseconds(udate));
243 }
244
FromUniversal(int64_t universal)245 absl::Time FromUniversal(int64_t universal) {
246 return absl::UniversalEpoch() + 100 * absl::Nanoseconds(universal);
247 }
248
ToUnixNanos(Time t)249 int64_t ToUnixNanos(Time t) {
250 if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
251 time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 33 == 0) {
252 return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *
253 1000 * 1000 * 1000) +
254 (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4);
255 }
256 return FloorToUnit(time_internal::ToUnixDuration(t), absl::Nanoseconds(1));
257 }
258
ToUnixMicros(Time t)259 int64_t ToUnixMicros(Time t) {
260 if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
261 time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 43 == 0) {
262 return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *
263 1000 * 1000) +
264 (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4000);
265 }
266 return FloorToUnit(time_internal::ToUnixDuration(t), absl::Microseconds(1));
267 }
268
ToUnixMillis(Time t)269 int64_t ToUnixMillis(Time t) {
270 if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
271 time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 53 == 0) {
272 return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * 1000) +
273 (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) /
274 (4000 * 1000));
275 }
276 return FloorToUnit(time_internal::ToUnixDuration(t), absl::Milliseconds(1));
277 }
278
ToUnixSeconds(Time t)279 int64_t ToUnixSeconds(Time t) {
280 return time_internal::GetRepHi(time_internal::ToUnixDuration(t));
281 }
282
ToTimeT(Time t)283 time_t ToTimeT(Time t) { return absl::ToTimespec(t).tv_sec; }
284
ToUDate(Time t)285 double ToUDate(Time t) {
286 return absl::FDivDuration(time_internal::ToUnixDuration(t),
287 absl::Milliseconds(1));
288 }
289
ToUniversal(absl::Time t)290 int64_t ToUniversal(absl::Time t) {
291 return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100));
292 }
293
TimeFromTimespec(timespec ts)294 absl::Time TimeFromTimespec(timespec ts) {
295 return time_internal::FromUnixDuration(absl::DurationFromTimespec(ts));
296 }
297
TimeFromTimeval(timeval tv)298 absl::Time TimeFromTimeval(timeval tv) {
299 return time_internal::FromUnixDuration(absl::DurationFromTimeval(tv));
300 }
301
ToTimespec(Time t)302 timespec ToTimespec(Time t) {
303 timespec ts;
304 absl::Duration d = time_internal::ToUnixDuration(t);
305 if (!time_internal::IsInfiniteDuration(d)) {
306 ts.tv_sec = static_cast<decltype(ts.tv_sec)>(time_internal::GetRepHi(d));
307 if (ts.tv_sec == time_internal::GetRepHi(d)) { // no time_t narrowing
308 ts.tv_nsec = time_internal::GetRepLo(d) / 4; // floor
309 return ts;
310 }
311 }
312 if (d >= absl::ZeroDuration()) {
313 ts.tv_sec = std::numeric_limits<time_t>::max();
314 ts.tv_nsec = 1000 * 1000 * 1000 - 1;
315 } else {
316 ts.tv_sec = std::numeric_limits<time_t>::min();
317 ts.tv_nsec = 0;
318 }
319 return ts;
320 }
321
ToTimeval(Time t)322 timeval ToTimeval(Time t) {
323 timeval tv;
324 timespec ts = absl::ToTimespec(t);
325 tv.tv_sec = static_cast<decltype(tv.tv_sec)>(ts.tv_sec);
326 if (tv.tv_sec != ts.tv_sec) { // narrowing
327 if (ts.tv_sec < 0) {
328 tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min();
329 tv.tv_usec = 0;
330 } else {
331 tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max();
332 tv.tv_usec = 1000 * 1000 - 1;
333 }
334 return tv;
335 }
336 tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000); // suseconds_t
337 return tv;
338 }
339
FromChrono(const std::chrono::system_clock::time_point & tp)340 Time FromChrono(const std::chrono::system_clock::time_point& tp) {
341 return time_internal::FromUnixDuration(time_internal::FromChrono(
342 tp - std::chrono::system_clock::from_time_t(0)));
343 }
344
ToChronoTime(absl::Time t)345 std::chrono::system_clock::time_point ToChronoTime(absl::Time t) {
346 using D = std::chrono::system_clock::duration;
347 auto d = time_internal::ToUnixDuration(t);
348 if (d < ZeroDuration()) d = Floor(d, FromChrono(D{1}));
349 return std::chrono::system_clock::from_time_t(0) +
350 time_internal::ToChronoDuration<D>(d);
351 }
352
353 //
354 // TimeZone
355 //
356
At(Time t) const357 absl::TimeZone::CivilInfo TimeZone::At(Time t) const {
358 if (t == absl::InfiniteFuture()) return InfiniteFutureCivilInfo();
359 if (t == absl::InfinitePast()) return InfinitePastCivilInfo();
360
361 const auto ud = time_internal::ToUnixDuration(t);
362 const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(ud));
363 const auto al = cz_.lookup(tp);
364
365 TimeZone::CivilInfo ci;
366 ci.cs = CivilSecond(al.cs);
367 ci.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(ud));
368 ci.offset = al.offset;
369 ci.is_dst = al.is_dst;
370 ci.zone_abbr = al.abbr;
371 return ci;
372 }
373
At(CivilSecond ct) const374 absl::TimeZone::TimeInfo TimeZone::At(CivilSecond ct) const {
375 const cctz::civil_second cs(ct);
376 const auto cl = cz_.lookup(cs);
377
378 TimeZone::TimeInfo ti;
379 switch (cl.kind) {
380 case cctz::time_zone::civil_lookup::UNIQUE:
381 ti.kind = TimeZone::TimeInfo::UNIQUE;
382 break;
383 case cctz::time_zone::civil_lookup::SKIPPED:
384 ti.kind = TimeZone::TimeInfo::SKIPPED;
385 break;
386 case cctz::time_zone::civil_lookup::REPEATED:
387 ti.kind = TimeZone::TimeInfo::REPEATED;
388 break;
389 }
390 ti.pre = MakeTimeWithOverflow(cl.pre, cs, cz_);
391 ti.trans = MakeTimeWithOverflow(cl.trans, cs, cz_);
392 ti.post = MakeTimeWithOverflow(cl.post, cs, cz_);
393 return ti;
394 }
395
NextTransition(Time t,CivilTransition * trans) const396 bool TimeZone::NextTransition(Time t, CivilTransition* trans) const {
397 return FindTransition(cz_, &cctz::time_zone::next_transition, t, trans);
398 }
399
PrevTransition(Time t,CivilTransition * trans) const400 bool TimeZone::PrevTransition(Time t, CivilTransition* trans) const {
401 return FindTransition(cz_, &cctz::time_zone::prev_transition, t, trans);
402 }
403
404 //
405 // Conversions involving time zones.
406 //
407 ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
ConvertDateTime(int64_t year,int mon,int day,int hour,int min,int sec,TimeZone tz)408 absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
409 int min, int sec, TimeZone tz) {
410 // Avoids years that are too extreme for CivilSecond to normalize.
411 if (year > 300000000000) return InfiniteFutureTimeConversion();
412 if (year < -300000000000) return InfinitePastTimeConversion();
413
414 const CivilSecond cs(year, mon, day, hour, min, sec);
415 const auto ti = tz.At(cs);
416
417 TimeConversion tc;
418 tc.pre = ti.pre;
419 tc.trans = ti.trans;
420 tc.post = ti.post;
421 switch (ti.kind) {
422 case TimeZone::TimeInfo::UNIQUE:
423 tc.kind = TimeConversion::UNIQUE;
424 break;
425 case TimeZone::TimeInfo::SKIPPED:
426 tc.kind = TimeConversion::SKIPPED;
427 break;
428 case TimeZone::TimeInfo::REPEATED:
429 tc.kind = TimeConversion::REPEATED;
430 break;
431 }
432 tc.normalized = false;
433 if (year != cs.year() || mon != cs.month() || day != cs.day() ||
434 hour != cs.hour() || min != cs.minute() || sec != cs.second()) {
435 tc.normalized = true;
436 }
437 return tc;
438 }
439 ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
440
FromTM(const struct tm & tm,absl::TimeZone tz)441 absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) {
442 civil_year_t tm_year = tm.tm_year;
443 // Avoids years that are too extreme for CivilSecond to normalize.
444 if (tm_year > 300000000000ll) return InfiniteFuture();
445 if (tm_year < -300000000000ll) return InfinitePast();
446 int tm_mon = tm.tm_mon;
447 if (tm_mon == std::numeric_limits<int>::max()) {
448 tm_mon -= 12;
449 tm_year += 1;
450 }
451 const auto ti = tz.At(CivilSecond(tm_year + 1900, tm_mon + 1, tm.tm_mday,
452 tm.tm_hour, tm.tm_min, tm.tm_sec));
453 return tm.tm_isdst == 0 ? ti.post : ti.pre;
454 }
455
ToTM(absl::Time t,absl::TimeZone tz)456 struct tm ToTM(absl::Time t, absl::TimeZone tz) {
457 struct tm tm = {};
458
459 const auto ci = tz.At(t);
460 const auto& cs = ci.cs;
461 tm.tm_sec = cs.second();
462 tm.tm_min = cs.minute();
463 tm.tm_hour = cs.hour();
464 tm.tm_mday = cs.day();
465 tm.tm_mon = cs.month() - 1;
466
467 // Saturates tm.tm_year in cases of over/underflow, accounting for the fact
468 // that tm.tm_year is years since 1900.
469 if (cs.year() < std::numeric_limits<int>::min() + 1900) {
470 tm.tm_year = std::numeric_limits<int>::min();
471 } else if (cs.year() > std::numeric_limits<int>::max()) {
472 tm.tm_year = std::numeric_limits<int>::max() - 1900;
473 } else {
474 tm.tm_year = static_cast<int>(cs.year() - 1900);
475 }
476
477 switch (GetWeekday(cs)) {
478 case Weekday::sunday:
479 tm.tm_wday = 0;
480 break;
481 case Weekday::monday:
482 tm.tm_wday = 1;
483 break;
484 case Weekday::tuesday:
485 tm.tm_wday = 2;
486 break;
487 case Weekday::wednesday:
488 tm.tm_wday = 3;
489 break;
490 case Weekday::thursday:
491 tm.tm_wday = 4;
492 break;
493 case Weekday::friday:
494 tm.tm_wday = 5;
495 break;
496 case Weekday::saturday:
497 tm.tm_wday = 6;
498 break;
499 }
500 tm.tm_yday = GetYearDay(cs) - 1;
501 tm.tm_isdst = ci.is_dst ? 1 : 0;
502
503 return tm;
504 }
505
506 ABSL_NAMESPACE_END
507 } // namespace absl
508