time.cc
Go to the documentation of this file.
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 #include <cstring>
37 #include <ctime>
38 #include <limits>
39 
42 
44 
45 namespace absl {
46 
47 namespace {
48 
49 inline cctz::time_point<cctz::seconds> unix_epoch() {
50  return std::chrono::time_point_cast<cctz::seconds>(
51  std::chrono::system_clock::from_time_t(0));
52 }
53 
54 // Floors d to the next unit boundary closer to negative infinity.
55 inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) {
56  absl::Duration rem;
57  int64_t q = absl::IDivDuration(d, unit, &rem);
58  return (q > 0 ||
59  rem >= ZeroDuration() ||
60  q == std::numeric_limits<int64_t>::min()) ? q : q - 1;
61 }
62 
63 inline absl::Time::Breakdown InfiniteFutureBreakdown() {
65  bd.year = std::numeric_limits<int64_t>::max();
66  bd.month = 12;
67  bd.day = 31;
68  bd.hour = 23;
69  bd.minute = 59;
70  bd.second = 59;
72  bd.weekday = 4;
73  bd.yearday = 365;
74  bd.offset = 0;
75  bd.is_dst = false;
76  bd.zone_abbr = "-00";
77  return bd;
78 }
79 
80 inline absl::Time::Breakdown InfinitePastBreakdown() {
81  Time::Breakdown bd;
82  bd.year = std::numeric_limits<int64_t>::min();
83  bd.month = 1;
84  bd.day = 1;
85  bd.hour = 0;
86  bd.minute = 0;
87  bd.second = 0;
88  bd.subsecond = -absl::InfiniteDuration();
89  bd.weekday = 7;
90  bd.yearday = 1;
91  bd.offset = 0;
92  bd.is_dst = false;
93  bd.zone_abbr = "-00";
94  return bd;
95 }
96 
97 inline absl::TimeZone::CivilInfo InfiniteFutureCivilInfo() {
98  TimeZone::CivilInfo ci;
99  ci.cs = CivilSecond::max();
100  ci.subsecond = InfiniteDuration();
101  ci.offset = 0;
102  ci.is_dst = false;
103  ci.zone_abbr = "-00";
104  return ci;
105 }
106 
107 inline absl::TimeZone::CivilInfo InfinitePastCivilInfo() {
108  TimeZone::CivilInfo ci;
109  ci.cs = CivilSecond::min();
110  ci.subsecond = -InfiniteDuration();
111  ci.offset = 0;
112  ci.is_dst = false;
113  ci.zone_abbr = "-00";
114  return ci;
115 }
116 
117 inline absl::TimeConversion InfiniteFutureTimeConversion() {
119  tc.pre = tc.trans = tc.post = absl::InfiniteFuture();
121  tc.normalized = true;
122  return tc;
123 }
124 
125 inline TimeConversion InfinitePastTimeConversion() {
127  tc.pre = tc.trans = tc.post = absl::InfinitePast();
129  tc.normalized = true;
130  return tc;
131 }
132 
133 // Makes a Time from sec, overflowing to InfiniteFuture/InfinitePast as
134 // necessary. If sec is min/max, then consult cs+tz to check for overlow.
135 Time MakeTimeWithOverflow(const cctz::time_point<cctz::seconds>& sec,
136  const cctz::civil_second& cs,
137  const cctz::time_zone& tz,
138  bool* normalized = nullptr) {
139  const auto max = cctz::time_point<cctz::seconds>::max();
140  const auto min = cctz::time_point<cctz::seconds>::min();
141  if (sec == max) {
142  const auto al = tz.lookup(max);
143  if (cs > al.cs) {
144  if (normalized) *normalized = true;
145  return absl::InfiniteFuture();
146  }
147  }
148  if (sec == min) {
149  const auto al = tz.lookup(min);
150  if (cs < al.cs) {
151  if (normalized) *normalized = true;
152  return absl::InfinitePast();
153  }
154  }
155  const auto hi = (sec - unix_epoch()).count();
157 }
158 
159 // Returns Mon=1..Sun=7.
160 inline int MapWeekday(const cctz::weekday& wd) {
161  switch (wd) {
162  case cctz::weekday::monday:
163  return 1;
164  case cctz::weekday::tuesday:
165  return 2;
166  case cctz::weekday::wednesday:
167  return 3;
168  case cctz::weekday::thursday:
169  return 4;
170  case cctz::weekday::friday:
171  return 5;
172  case cctz::weekday::saturday:
173  return 6;
174  case cctz::weekday::sunday:
175  return 7;
176  }
177  return 1;
178 }
179 
180 bool FindTransition(const cctz::time_zone& tz,
181  bool (cctz::time_zone::*find_transition)(
183  cctz::time_zone::civil_transition* trans) const,
184  Time t, TimeZone::CivilTransition* trans) {
185  // Transitions are second-aligned, so we can discard any fractional part.
186  const auto tp = unix_epoch() + cctz::seconds(ToUnixSeconds(t));
187  cctz::time_zone::civil_transition tr;
188  if (!(tz.*find_transition)(tp, &tr)) return false;
189  trans->from = CivilSecond(tr.from);
190  trans->to = CivilSecond(tr.to);
191  return true;
192 }
193 
194 } // namespace
195 
196 //
197 // Time
198 //
199 
201  if (*this == absl::InfiniteFuture()) return InfiniteFutureBreakdown();
202  if (*this == absl::InfinitePast()) return InfinitePastBreakdown();
203 
204  const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(rep_));
205  const auto al = cctz::time_zone(tz).lookup(tp);
206  const auto cs = al.cs;
207  const auto cd = cctz::civil_day(cs);
208 
210  bd.year = cs.year();
211  bd.month = cs.month();
212  bd.day = cs.day();
213  bd.hour = cs.hour();
214  bd.minute = cs.minute();
215  bd.second = cs.second();
217  bd.weekday = MapWeekday(cctz::get_weekday(cd));
218  bd.yearday = cctz::get_yearday(cd);
219  bd.offset = al.offset;
220  bd.is_dst = al.is_dst;
221  bd.zone_abbr = al.abbr;
222  return bd;
223 }
224 
225 //
226 // Conversions from/to other time types.
227 //
228 
229 absl::Time FromUDate(double udate) {
231 }
232 
233 absl::Time FromUniversal(int64_t universal) {
234  return absl::UniversalEpoch() + 100 * absl::Nanoseconds(universal);
235 }
236 
237 int64_t ToUnixNanos(Time t) {
241  1000 * 1000 * 1000) +
243  }
244  return FloorToUnit(time_internal::ToUnixDuration(t), absl::Nanoseconds(1));
245 }
246 
247 int64_t ToUnixMicros(Time t) {
251  1000 * 1000) +
253  }
254  return FloorToUnit(time_internal::ToUnixDuration(t), absl::Microseconds(1));
255 }
256 
257 int64_t ToUnixMillis(Time t) {
262  (4000 * 1000));
263  }
264  return FloorToUnit(time_internal::ToUnixDuration(t), absl::Milliseconds(1));
265 }
266 
267 int64_t ToUnixSeconds(Time t) {
269 }
270 
271 time_t ToTimeT(Time t) { return absl::ToTimespec(t).tv_sec; }
272 
273 double ToUDate(Time t) {
275  absl::Milliseconds(1));
276 }
277 
279  return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100));
280 }
281 
284 }
285 
288 }
289 
290 timespec ToTimespec(Time t) {
291  timespec ts;
294  ts.tv_sec = time_internal::GetRepHi(d);
295  if (ts.tv_sec == time_internal::GetRepHi(d)) { // no time_t narrowing
296  ts.tv_nsec = time_internal::GetRepLo(d) / 4; // floor
297  return ts;
298  }
299  }
300  if (d >= absl::ZeroDuration()) {
301  ts.tv_sec = std::numeric_limits<time_t>::max();
302  ts.tv_nsec = 1000 * 1000 * 1000 - 1;
303  } else {
304  ts.tv_sec = std::numeric_limits<time_t>::min();
305  ts.tv_nsec = 0;
306  }
307  return ts;
308 }
309 
310 timeval ToTimeval(Time t) {
311  timeval tv;
312  timespec ts = absl::ToTimespec(t);
313  tv.tv_sec = ts.tv_sec;
314  if (tv.tv_sec != ts.tv_sec) { // narrowing
315  if (ts.tv_sec < 0) {
316  tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min();
317  tv.tv_usec = 0;
318  } else {
319  tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max();
320  tv.tv_usec = 1000 * 1000 - 1;
321  }
322  return tv;
323  }
324  tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000); // suseconds_t
325  return tv;
326 }
327 
330  tp - std::chrono::system_clock::from_time_t(0)));
331 }
332 
334  using D = std::chrono::system_clock::duration;
335  auto d = time_internal::ToUnixDuration(t);
336  if (d < ZeroDuration()) d = Floor(d, FromChrono(D{1}));
337  return std::chrono::system_clock::from_time_t(0) +
338  time_internal::ToChronoDuration<D>(d);
339 }
340 
341 //
342 // TimeZone
343 //
344 
346  if (t == absl::InfiniteFuture()) return InfiniteFutureCivilInfo();
347  if (t == absl::InfinitePast()) return InfinitePastCivilInfo();
348 
349  const auto ud = time_internal::ToUnixDuration(t);
350  const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(ud));
351  const auto al = cz_.lookup(tp);
352 
354  ci.cs = CivilSecond(al.cs);
356  ci.offset = al.offset;
357  ci.is_dst = al.is_dst;
358  ci.zone_abbr = al.abbr;
359  return ci;
360 }
361 
363  const cctz::civil_second cs(ct);
364  const auto cl = cz_.lookup(cs);
365 
367  switch (cl.kind) {
368  case cctz::time_zone::civil_lookup::UNIQUE:
370  break;
371  case cctz::time_zone::civil_lookup::SKIPPED:
373  break;
374  case cctz::time_zone::civil_lookup::REPEATED:
376  break;
377  }
378  ti.pre = MakeTimeWithOverflow(cl.pre, cs, cz_);
379  ti.trans = MakeTimeWithOverflow(cl.trans, cs, cz_);
380  ti.post = MakeTimeWithOverflow(cl.post, cs, cz_);
381  return ti;
382 }
383 
385  return FindTransition(cz_, &cctz::time_zone::next_transition, t, trans);
386 }
387 
389  return FindTransition(cz_, &cctz::time_zone::prev_transition, t, trans);
390 }
391 
392 //
393 // Conversions involving time zones.
394 //
395 
396 absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
397  int min, int sec, TimeZone tz) {
398  // Avoids years that are too extreme for CivilSecond to normalize.
399  if (year > 300000000000) return InfiniteFutureTimeConversion();
400  if (year < -300000000000) return InfinitePastTimeConversion();
401 
402  const CivilSecond cs(year, mon, day, hour, min, sec);
403  const auto ti = tz.At(cs);
404 
405  TimeConversion tc;
406  tc.pre = ti.pre;
407  tc.trans = ti.trans;
408  tc.post = ti.post;
409  switch (ti.kind) {
412  break;
415  break;
418  break;
419  }
420  tc.normalized = false;
421  if (year != cs.year() || mon != cs.month() || day != cs.day() ||
422  hour != cs.hour() || min != cs.minute() || sec != cs.second()) {
423  tc.normalized = true;
424  }
425  return tc;
426 }
427 
428 absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) {
429  const CivilSecond cs(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
430  tm.tm_hour, tm.tm_min, tm.tm_sec);
431  const auto ti = tz.At(cs);
432  return tm.tm_isdst == 0 ? ti.post : ti.pre;
433 }
434 
435 struct tm ToTM(absl::Time t, absl::TimeZone tz) {
436  struct tm tm = {};
437 
438  const auto ci = tz.At(t);
439  const auto& cs = ci.cs;
440  tm.tm_sec = cs.second();
441  tm.tm_min = cs.minute();
442  tm.tm_hour = cs.hour();
443  tm.tm_mday = cs.day();
444  tm.tm_mon = cs.month() - 1;
445 
446  // Saturates tm.tm_year in cases of over/underflow, accounting for the fact
447  // that tm.tm_year is years since 1900.
448  if (cs.year() < std::numeric_limits<int>::min() + 1900) {
449  tm.tm_year = std::numeric_limits<int>::min();
450  } else if (cs.year() > std::numeric_limits<int>::max()) {
451  tm.tm_year = std::numeric_limits<int>::max() - 1900;
452  } else {
453  tm.tm_year = static_cast<int>(cs.year() - 1900);
454  }
455 
456  const CivilDay cd(cs);
457  switch (GetWeekday(cd)) {
458  case Weekday::sunday:
459  tm.tm_wday = 0;
460  break;
461  case Weekday::monday:
462  tm.tm_wday = 1;
463  break;
464  case Weekday::tuesday:
465  tm.tm_wday = 2;
466  break;
467  case Weekday::wednesday:
468  tm.tm_wday = 3;
469  break;
470  case Weekday::thursday:
471  tm.tm_wday = 4;
472  break;
473  case Weekday::friday:
474  tm.tm_wday = 5;
475  break;
476  case Weekday::saturday:
477  tm.tm_wday = 6;
478  break;
479  }
480  tm.tm_yday = GetYearDay(cd) - 1;
481  tm.tm_isdst = ci.is_dst ? 1 : 0;
482 
483  return tm;
484 }
485 
486 } // namespace absl
CivilInfo At(Time t) const
Definition: time.cc:345
timespec ToTimespec(Duration d)
Definition: duration.cc:598
bool next_transition(const time_point< seconds > &tp, civil_transition *trans) const
CONSTEXPR_F int get_yearday(const civil_day &cd) noexcept
absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour, int min, int sec, TimeZone tz)
Definition: time.cc:396
Weekday GetWeekday(CivilDay cd)
Definition: civil_time.h:380
CONSTEXPR_M int minute() const noexcept
constexpr Time InfiniteFuture()
Definition: time.h:701
absl::Time FromUniversal(int64_t universal)
Definition: time.cc:233
Duration DurationFromTimespec(timespec ts)
Definition: duration.cc:516
constexpr Duration ToUnixDuration(Time t)
Definition: time.h:1369
int64_t ToUnixMillis(Time t)
Definition: time.cc:257
std::chrono::system_clock::time_point ToChronoTime(absl::Time t)
Definition: time.cc:333
int64_t ToUniversal(absl::Time t)
Definition: time.cc:278
const char * zone_abbr
Definition: time.h:869
int GetYearDay(CivilDay cd)
Definition: civil_time.h:432
constexpr Duration Microseconds(int64_t n)
Definition: time.h:1455
Duration Floor(const Duration d, const Duration unit)
Definition: duration.cc:502
int64_t ToUnixMicros(Time t)
Definition: time.cc:247
constexpr Time FromUnixDuration(Duration d)
Definition: time.h:1368
CONSTEXPR_F weekday get_weekday(const civil_day &cd) noexcept
std::chrono::duration< std::int_fast64_t > seconds
Definition: time_zone.h:37
Definition: algorithm.h:29
constexpr Duration Milliseconds(int64_t n)
Definition: time.h:1458
cctz::time_point< cctz::seconds > sec
Definition: format.cc:38
absl::Time FromTM(const struct tm &tm, absl::TimeZone tz)
Definition: time.cc:428
Duration subsecond
Definition: time.h:630
timeval ToTimeval(Duration d)
Definition: duration.cc:628
bool NextTransition(Time t, CivilTransition *trans) const
Definition: time.cc:384
CONSTEXPR_M year_t year() const noexcept
CivilSecond cs
Definition: time.h:859
double ToUDate(Time t)
Definition: time.cc:273
absl::Time TimeFromTimespec(timespec ts)
Definition: time.cc:282
constexpr Duration MakeDuration(int64_t hi, uint32_t lo)
Definition: time.h:1313
bool prev_transition(const time_point< seconds > &tp, civil_transition *trans) const
time_internal::cctz::detail::civil_time< time_internal::second_tag > CivilSecond
Definition: civil_time.h:323
enum absl::TimeZone::TimeInfo::CivilKind kind
absolute_lookup lookup(const time_point< seconds > &tp) const
CONSTEXPR_M int month() const noexcept
constexpr Duration FromChrono(const std::chrono::duration< Rep, Period > &d)
Definition: time.h:1405
int64_t IDivDuration(Duration num, Duration den, Duration *rem)
Definition: time.h:263
int64_t ToUnixSeconds(Time t)
Definition: time.cc:267
constexpr Time UniversalEpoch()
Definition: time.h:692
absl::Time FromUDate(double udate)
Definition: time.cc:229
bool PrevTransition(Time t, CivilTransition *trans) const
Definition: time.cc:388
Duration rep_
Definition: time.h:666
std::chrono::time_point< std::chrono::system_clock, D > time_point
Definition: time_zone.h:36
constexpr uint32_t GetRepLo(Duration d)
Definition: time.h:1344
const char * zone_abbr
Definition: time.h:641
CONSTEXPR_M int second() const noexcept
struct tm ToTM(absl::Time t, absl::TimeZone tz)
Definition: time.cc:435
double FDivDuration(Duration num, Duration den)
Definition: duration.cc:476
constexpr int64_t GetRepHi(Duration d)
Definition: time.h:1343
Duration DurationFromTimeval(timeval tv)
Definition: duration.cc:524
constexpr Duration Nanoseconds(int64_t n)
Definition: time.h:1452
time_t ToTimeT(Time t)
Definition: time.cc:271
Breakdown In(TimeZone tz) const
Definition: time.cc:200
constexpr Duration InfiniteDuration()
Definition: time.h:1513
constexpr Duration ZeroDuration()
Definition: time.h:286
int64_t ToUnixNanos(Time t)
Definition: time.cc:237
absl::Time TimeFromTimeval(timeval tv)
Definition: time.cc:286
constexpr Time InfinitePast()
Definition: time.h:709
Time FromChrono(const std::chrono::system_clock::time_point &tp)
Definition: time.cc:328
constexpr bool IsInfiniteDuration(Duration d)
Definition: time.h:1347


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:19:58