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