civil_time_detail.h
Go to the documentation of this file.
1 // Copyright 2016 Google Inc. All Rights Reserved.
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 #ifndef ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_
16 #define ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_
17 
18 #include <cstdint>
19 #include <limits>
20 #include <ostream>
21 #include <type_traits>
22 
23 // Disable constexpr support unless we are in C++14 mode.
24 #if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
25 #define CONSTEXPR_D constexpr // data
26 #define CONSTEXPR_F constexpr // function
27 #define CONSTEXPR_M constexpr // member
28 #else
29 #define CONSTEXPR_D const
30 #define CONSTEXPR_F inline
31 #define CONSTEXPR_M
32 #endif
33 
34 namespace absl {
35 namespace time_internal {
36 namespace cctz {
37 
38 // Support years that at least span the range of 64-bit time_t values.
39 using year_t = std::int_fast64_t;
40 
41 // Type alias that indicates an argument is not normalized (e.g., the
42 // constructor parameters and operands/results of addition/subtraction).
43 using diff_t = std::int_fast64_t;
44 
45 namespace detail {
46 
47 // Type aliases that indicate normalized argument values.
48 using month_t = std::int_fast8_t; // [1:12]
49 using day_t = std::int_fast8_t; // [1:31]
50 using hour_t = std::int_fast8_t; // [0:23]
51 using minute_t = std::int_fast8_t; // [0:59]
52 using second_t = std::int_fast8_t; // [0:59]
53 
54 // Normalized civil-time fields: Y-M-D HH:MM:SS.
55 struct fields {
57  hour_t hour, minute_t minute, second_t second)
58  : y(year), m(month), d(day), hh(hour), mm(minute), ss(second) {}
59  std::int_least64_t y;
60  std::int_least8_t m;
61  std::int_least8_t d;
62  std::int_least8_t hh;
63  std::int_least8_t mm;
64  std::int_least8_t ss;
65 };
66 
67 struct second_tag {};
68 struct minute_tag : second_tag {};
69 struct hour_tag : minute_tag {};
70 struct day_tag : hour_tag {};
71 struct month_tag : day_tag {};
72 struct year_tag : month_tag {};
73 
75 
76 // Field normalization (without avoidable overflow).
77 
78 namespace impl {
79 
80 CONSTEXPR_F bool is_leap_year(year_t y) noexcept {
81  return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0);
82 }
84  return (static_cast<int>((y + (m > 2)) % 400) + 400) % 400;
85 }
87  const int yi = year_index(y, m);
88  return 36524 + (yi == 0 || yi > 300);
89 }
91  const int yi = year_index(y, m);
92  return 1460 + (yi == 0 || yi > 300 || (yi - 1) % 100 < 96);
93 }
95  return is_leap_year(y + (m > 2)) ? 366 : 365;
96 }
98  CONSTEXPR_D int k_days_per_month[1 + 12] = {
99  -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 // non leap year
100  };
101  return k_days_per_month[m] + (m == 2 && is_leap_year(y));
102 }
103 
105  hour_t hh, minute_t mm, second_t ss) noexcept {
106  y += (cd / 146097) * 400;
107  cd %= 146097;
108  if (cd < 0) {
109  y -= 400;
110  cd += 146097;
111  }
112  y += (d / 146097) * 400;
113  d = d % 146097 + cd;
114  if (d > 0) {
115  if (d > 146097) {
116  y += 400;
117  d -= 146097;
118  }
119  } else {
120  if (d > -365) {
121  // We often hit the previous year when stepping a civil time backwards,
122  // so special case it to avoid counting up by 100/4/1-year chunks.
123  y -= 1;
124  d += days_per_year(y, m);
125  } else {
126  y -= 400;
127  d += 146097;
128  }
129  }
130  if (d > 365) {
131  for (int n = days_per_century(y, m); d > n; n = days_per_century(y, m)) {
132  d -= n;
133  y += 100;
134  }
135  for (int n = days_per_4years(y, m); d > n; n = days_per_4years(y, m)) {
136  d -= n;
137  y += 4;
138  }
139  for (int n = days_per_year(y, m); d > n; n = days_per_year(y, m)) {
140  d -= n;
141  ++y;
142  }
143  }
144  if (d > 28) {
145  for (int n = days_per_month(y, m); d > n; n = days_per_month(y, m)) {
146  d -= n;
147  if (++m > 12) {
148  ++y;
149  m = 1;
150  }
151  }
152  }
153  return fields(y, m, static_cast<day_t>(d), hh, mm, ss);
154 }
156  hour_t hh, minute_t mm, second_t ss) noexcept {
157  if (m != 12) {
158  y += m / 12;
159  m %= 12;
160  if (m <= 0) {
161  y -= 1;
162  m += 12;
163  }
164  }
165  return n_day(y, static_cast<month_t>(m), d, cd, hh, mm, ss);
166 }
168  diff_t hh, minute_t mm, second_t ss) noexcept {
169  cd += hh / 24;
170  hh %= 24;
171  if (hh < 0) {
172  cd -= 1;
173  hh += 24;
174  }
175  return n_mon(y, m, d, cd, static_cast<hour_t>(hh), mm, ss);
176 }
178  diff_t mm, second_t ss) noexcept {
179  ch += mm / 60;
180  mm %= 60;
181  if (mm < 0) {
182  ch -= 1;
183  mm += 60;
184  }
185  return n_hour(y, m, d, hh / 24 + ch / 24, hh % 24 + ch % 24,
186  static_cast<minute_t>(mm), ss);
187 }
189  diff_t ss) noexcept {
190  // Optimization for when (non-constexpr) fields are already normalized.
191  if (0 <= ss && ss < 60) {
192  const second_t nss = static_cast<second_t>(ss);
193  if (0 <= mm && mm < 60) {
194  const minute_t nmm = static_cast<minute_t>(mm);
195  if (0 <= hh && hh < 24) {
196  const hour_t nhh = static_cast<hour_t>(hh);
197  if (1 <= d && d <= 28 && 1 <= m && m <= 12) {
198  const day_t nd = static_cast<day_t>(d);
199  const month_t nm = static_cast<month_t>(m);
200  return fields(y, nm, nd, nhh, nmm, nss);
201  }
202  return n_mon(y, m, d, 0, nhh, nmm, nss);
203  }
204  return n_hour(y, m, d, hh / 24, hh % 24, nmm, nss);
205  }
206  return n_min(y, m, d, hh, mm / 60, mm % 60, nss);
207  }
208  diff_t cm = ss / 60;
209  ss %= 60;
210  if (ss < 0) {
211  cm -= 1;
212  ss += 60;
213  }
214  return n_min(y, m, d, hh, mm / 60 + cm / 60, mm % 60 + cm % 60,
215  static_cast<second_t>(ss));
216 }
217 
218 } // namespace impl
219 
221 
222 // Increments the indicated (normalized) field by "n".
224  return impl::n_sec(f.y, f.m, f.d, f.hh, f.mm + n / 60, f.ss + n % 60);
225 }
227  return impl::n_min(f.y, f.m, f.d, f.hh + n / 60, 0, f.mm + n % 60, f.ss);
228 }
230  return impl::n_hour(f.y, f.m, f.d + n / 24, 0, f.hh + n % 24, f.mm, f.ss);
231 }
233  return impl::n_day(f.y, f.m, f.d, n, f.hh, f.mm, f.ss);
234 }
236  return impl::n_mon(f.y + n / 12, f.m + n % 12, f.d, 0, f.hh, f.mm, f.ss);
237 }
239  return fields(f.y + n, f.m, f.d, f.hh, f.mm, f.ss);
240 }
241 
243 
244 namespace impl {
245 
246 // Returns (v * f + a) but avoiding intermediate overflow when possible.
248  return (v < 0) ? ((v + 1) * f + a) - f : ((v - 1) * f + a) + f;
249 }
250 
251 // Map a (normalized) Y/M/D to the number of days before/after 1970-01-01.
252 // Probably overflows for years outside [-292277022656:292277026595].
254  const diff_t eyear = (m <= 2) ? y - 1 : y;
255  const diff_t era = (eyear >= 0 ? eyear : eyear - 399) / 400;
256  const diff_t yoe = eyear - era * 400;
257  const diff_t doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;
258  const diff_t doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
259  return era * 146097 + doe - 719468;
260 }
261 
262 // Returns the difference in days between two normalized Y-M-D tuples.
263 // ymd_ord() will encounter integer overflow given extreme year values,
264 // yet the difference between two such extreme values may actually be
265 // small, so we take a little care to avoid overflow when possible by
266 // exploiting the 146097-day cycle.
268  year_t y2, month_t m2, day_t d2) noexcept {
269  const diff_t a_c4_off = y1 % 400;
270  const diff_t b_c4_off = y2 % 400;
271  diff_t c4_diff = (y1 - a_c4_off) - (y2 - b_c4_off);
272  diff_t delta = ymd_ord(a_c4_off, m1, d1) - ymd_ord(b_c4_off, m2, d2);
273  if (c4_diff > 0 && delta < 0) {
274  delta += 2 * 146097;
275  c4_diff -= 2 * 400;
276  } else if (c4_diff < 0 && delta > 0) {
277  delta -= 2 * 146097;
278  c4_diff += 2 * 400;
279  }
280  return (c4_diff / 400 * 146097) + delta;
281 }
282 
283 } // namespace impl
284 
285 // Returns the difference between fields structs using the indicated unit.
287  return f1.y - f2.y;
288 }
290  return impl::scale_add(difference(year_tag{}, f1, f2), 12, (f1.m - f2.m));
291 }
293  return impl::day_difference(f1.y, f1.m, f1.d, f2.y, f2.m, f2.d);
294 }
296  return impl::scale_add(difference(day_tag{}, f1, f2), 24, (f1.hh - f2.hh));
297 }
299  return impl::scale_add(difference(hour_tag{}, f1, f2), 60, (f1.mm - f2.mm));
300 }
302  return impl::scale_add(difference(minute_tag{}, f1, f2), 60, f1.ss - f2.ss);
303 }
304 
306 
307 // Aligns the (normalized) fields struct to the indicated field.
309  return f;
310 }
312  return fields{f.y, f.m, f.d, f.hh, f.mm, 0};
313 }
315  return fields{f.y, f.m, f.d, f.hh, 0, 0};
316 }
318  return fields{f.y, f.m, f.d, 0, 0, 0};
319 }
321  return fields{f.y, f.m, 1, 0, 0, 0};
322 }
324  return fields{f.y, 1, 1, 0, 0, 0};
325 }
326 
328 
329 namespace impl {
330 
331 template <typename H>
333  return H::combine(std::move(h), f.y, f.m, f.d, f.hh, f.mm, f.ss);
334 }
335 template <typename H>
337  return H::combine(std::move(h), f.y, f.m, f.d, f.hh, f.mm);
338 }
339 template <typename H>
341  return H::combine(std::move(h), f.y, f.m, f.d, f.hh);
342 }
343 template <typename H>
345  return H::combine(std::move(h), f.y, f.m, f.d);
346 }
347 template <typename H>
349  return H::combine(std::move(h), f.y, f.m);
350 }
351 template <typename H>
353  return H::combine(std::move(h), f.y);
354 }
355 
356 } // namespace impl
357 
359 
360 template <typename T>
361 class civil_time {
362  public:
364  diff_t hh = 0, diff_t mm = 0,
365  diff_t ss = 0) noexcept
366  : civil_time(impl::n_sec(y, m, d, hh, mm, ss)) {}
367 
368  CONSTEXPR_M civil_time() noexcept : f_{1970, 1, 1, 0, 0, 0} {}
369  civil_time(const civil_time&) = default;
370  civil_time& operator=(const civil_time&) = default;
371 
372  // Conversion between civil times of different alignment. Conversion to
373  // a more precise alignment is allowed implicitly (e.g., day -> hour),
374  // but conversion where information is discarded must be explicit
375  // (e.g., second -> minute).
376  template <typename U, typename S>
377  using preserves_data =
379  template <typename U>
381  preserves_data<T, U>* = nullptr) noexcept
382  : civil_time(ct.f_) {}
383  template <typename U>
385  preserves_data<U, T>* = nullptr) noexcept
386  : civil_time(ct.f_) {}
387 
388  // Factories for the maximum/minimum representable civil_time.
389  static CONSTEXPR_F civil_time (max)() {
390  const auto max_year = (std::numeric_limits<std::int_least64_t>::max)();
391  return civil_time(max_year, 12, 31, 23, 59, 59);
392  }
393  static CONSTEXPR_F civil_time (min)() {
394  const auto min_year = (std::numeric_limits<std::int_least64_t>::min)();
395  return civil_time(min_year, 1, 1, 0, 0, 0);
396  }
397 
398  // Field accessors. Note: All but year() return an int.
399  CONSTEXPR_M year_t year() const noexcept { return f_.y; }
400  CONSTEXPR_M int month() const noexcept { return f_.m; }
401  CONSTEXPR_M int day() const noexcept { return f_.d; }
402  CONSTEXPR_M int hour() const noexcept { return f_.hh; }
403  CONSTEXPR_M int minute() const noexcept { return f_.mm; }
404  CONSTEXPR_M int second() const noexcept { return f_.ss; }
405 
406  // Assigning arithmetic.
408  f_ = step(T{}, f_, n);
409  return *this;
410  }
412  if (n != (std::numeric_limits<diff_t>::min)()) {
413  f_ = step(T{}, f_, -n);
414  } else {
415  f_ = step(T{}, step(T{}, f_, -(n + 1)), 1);
416  }
417  return *this;
418  }
420  return *this += 1;
421  }
423  const civil_time a = *this;
424  ++*this;
425  return a;
426  }
428  return *this -= 1;
429  }
431  const civil_time a = *this;
432  --*this;
433  return a;
434  }
435 
436  // Binary arithmetic operators.
438  return a += n;
439  }
441  return a += n;
442  }
444  return a -= n;
445  }
446  friend CONSTEXPR_F diff_t operator-(civil_time lhs, civil_time rhs) noexcept {
447  return difference(T{}, lhs.f_, rhs.f_);
448  }
449 
450  template <typename H>
451  friend H AbslHashValue(H h, civil_time a) {
452  return impl::AbslHashValueImpl(T{}, std::move(h), a.f_);
453  }
454 
455  private:
456  // All instantiations of this template are allowed to call the following
457  // private constructor and access the private fields member.
458  template <typename U>
459  friend class civil_time;
460 
461  // The designated constructor that all others eventually call.
462  explicit CONSTEXPR_M civil_time(fields f) noexcept : f_(align(T{}, f)) {}
463 
465 };
466 
467 // Disallows difference between differently aligned types.
468 // auto n = civil_day(...) - civil_hour(...); // would be confusing.
469 template <typename T, typename U>
471 
478 
480 
481 // Relational operators that work with differently aligned objects.
482 // Always compares all six fields.
483 template <typename T1, typename T2>
484 CONSTEXPR_F bool operator<(const civil_time<T1>& lhs,
485  const civil_time<T2>& rhs) noexcept {
486  return (lhs.year() < rhs.year() ||
487  (lhs.year() == rhs.year() &&
488  (lhs.month() < rhs.month() ||
489  (lhs.month() == rhs.month() &&
490  (lhs.day() < rhs.day() ||
491  (lhs.day() == rhs.day() &&
492  (lhs.hour() < rhs.hour() ||
493  (lhs.hour() == rhs.hour() &&
494  (lhs.minute() < rhs.minute() ||
495  (lhs.minute() == rhs.minute() &&
496  (lhs.second() < rhs.second())))))))))));
497 }
498 template <typename T1, typename T2>
499 CONSTEXPR_F bool operator<=(const civil_time<T1>& lhs,
500  const civil_time<T2>& rhs) noexcept {
501  return !(rhs < lhs);
502 }
503 template <typename T1, typename T2>
505  const civil_time<T2>& rhs) noexcept {
506  return !(lhs < rhs);
507 }
508 template <typename T1, typename T2>
510  const civil_time<T2>& rhs) noexcept {
511  return rhs < lhs;
512 }
513 template <typename T1, typename T2>
515  const civil_time<T2>& rhs) noexcept {
516  return lhs.year() == rhs.year() && lhs.month() == rhs.month() &&
517  lhs.day() == rhs.day() && lhs.hour() == rhs.hour() &&
518  lhs.minute() == rhs.minute() && lhs.second() == rhs.second();
519 }
520 template <typename T1, typename T2>
522  const civil_time<T2>& rhs) noexcept {
523  return !(lhs == rhs);
524 }
525 
527 
528 enum class weekday {
529  monday,
530  tuesday,
531  wednesday,
532  thursday,
533  friday,
534  saturday,
535  sunday,
536 };
537 
539  CONSTEXPR_D weekday k_weekday_by_mon_off[13] = {
545  };
546  CONSTEXPR_D int k_weekday_offsets[1 + 12] = {
547  -1, 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4,
548  };
549  year_t wd = 2400 + (cd.year() % 400) - (cd.month() < 3);
550  wd += wd / 4 - wd / 100 + wd / 400;
551  wd += k_weekday_offsets[cd.month()] + cd.day();
552  return k_weekday_by_mon_off[wd % 7 + 6];
553 }
554 
556 
558  CONSTEXPR_D weekday k_weekdays_forw[14] = {
564  };
565  weekday base = get_weekday(cd);
566  for (int i = 0;; ++i) {
567  if (base == k_weekdays_forw[i]) {
568  for (int j = i + 1;; ++j) {
569  if (wd == k_weekdays_forw[j]) {
570  return cd + (j - i);
571  }
572  }
573  }
574  }
575 }
576 
578  CONSTEXPR_D weekday k_weekdays_back[14] = {
584  };
585  weekday base = get_weekday(cd);
586  for (int i = 0;; ++i) {
587  if (base == k_weekdays_back[i]) {
588  for (int j = i + 1;; ++j) {
589  if (wd == k_weekdays_back[j]) {
590  return cd - (j - i);
591  }
592  }
593  }
594  }
595 }
596 
597 CONSTEXPR_F int get_yearday(const civil_day& cd) noexcept {
598  CONSTEXPR_D int k_month_offsets[1 + 12] = {
599  -1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
600  };
601  const int feb29 = (cd.month() > 2 && impl::is_leap_year(cd.year()));
602  return k_month_offsets[cd.month()] + feb29 + cd.day();
603 }
604 
606 
607 std::ostream& operator<<(std::ostream& os, const civil_year& y);
608 std::ostream& operator<<(std::ostream& os, const civil_month& m);
609 std::ostream& operator<<(std::ostream& os, const civil_day& d);
610 std::ostream& operator<<(std::ostream& os, const civil_hour& h);
611 std::ostream& operator<<(std::ostream& os, const civil_minute& m);
612 std::ostream& operator<<(std::ostream& os, const civil_second& s);
613 std::ostream& operator<<(std::ostream& os, weekday wd);
614 
615 } // namespace detail
616 } // namespace cctz
617 } // namespace time_internal
618 } // namespace absl
619 
620 #undef CONSTEXPR_M
621 #undef CONSTEXPR_F
622 #undef CONSTEXPR_D
623 
624 #endif // ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_
int v
Definition: variant_test.cc:81
CONSTEXPR_F bool operator!=(const civil_time< T1 > &lhs, const civil_time< T2 > &rhs) noexcept
CONSTEXPR_F bool operator==(const civil_time< T1 > &lhs, const civil_time< T2 > &rhs) noexcept
CONSTEXPR_F int get_yearday(const civil_day &cd) noexcept
CONSTEXPR_M civil_time operator++(int) noexcept
CONSTEXPR_M civil_time(const civil_time< U > &ct, preserves_data< U, T > *=nullptr) noexcept
CONSTEXPR_M int minute() const noexcept
CONSTEXPR_M civil_time operator--(int) noexcept
H AbslHashValueImpl(second_tag, H h, fields f)
CONSTEXPR_F diff_t day_difference(year_t y1, month_t m1, day_t d1, year_t y2, month_t m2, day_t d2) noexcept
CONSTEXPR_F bool operator>(const civil_time< T1 > &lhs, const civil_time< T2 > &rhs) noexcept
CONSTEXPR_F fields n_hour(year_t y, diff_t m, diff_t d, diff_t cd, diff_t hh, minute_t mm, second_t ss) noexcept
CONSTEXPR_F fields step(second_tag, fields f, diff_t n) noexcept
friend CONSTEXPR_F diff_t operator-(civil_time lhs, civil_time rhs) noexcept
CONSTEXPR_F civil_day next_weekday(civil_day cd, weekday wd) noexcept
CONSTEXPR_F weekday get_weekday(const civil_day &cd) noexcept
CONSTEXPR_M civil_time & operator--() noexcept
CONSTEXPR_F fields align(second_tag, fields f) noexcept
Definition: algorithm.h:29
CONSTEXPR_F diff_t difference(year_tag, fields f1, fields f2) noexcept
friend CONSTEXPR_F civil_time operator-(civil_time a, diff_t n) noexcept
CONSTEXPR_F bool operator>=(const civil_time< T1 > &lhs, const civil_time< T2 > &rhs) noexcept
CONSTEXPR_M civil_time & operator+=(diff_t n) noexcept
CONSTEXPR_M civil_time(year_t y, diff_t m=1, diff_t d=1, diff_t hh=0, diff_t mm=0, diff_t ss=0) noexcept
CONSTEXPR_M year_t year() const noexcept
CONSTEXPR_F fields n_mon(year_t y, diff_t m, diff_t d, diff_t cd, hour_t hh, minute_t mm, second_t ss) noexcept
CONSTEXPR_F fields n_min(year_t y, diff_t m, diff_t d, diff_t hh, diff_t ch, diff_t mm, second_t ss) noexcept
CONSTEXPR_F int year_index(year_t y, month_t m) noexcept
typename std::enable_if< std::is_base_of< U, S >::value >::type preserves_data
CONSTEXPR_F int days_per_year(year_t y, month_t m) noexcept
size_t value
CONSTEXPR_F int days_per_century(year_t y, month_t m) noexcept
#define CONSTEXPR_M
CONSTEXPR_M int month() const noexcept
CONSTEXPR_F civil_day prev_weekday(civil_day cd, weekday wd) noexcept
CONSTEXPR_F diff_t operator-(civil_time< T >, civil_time< U >)=delete
friend CONSTEXPR_F civil_time operator+(diff_t n, civil_time a) noexcept
CONSTEXPR_F diff_t scale_add(diff_t v, diff_t f, diff_t a) noexcept
#define CONSTEXPR_F
CONSTEXPR_F fields n_day(year_t y, month_t m, diff_t d, diff_t cd, hour_t hh, minute_t mm, second_t ss) noexcept
CONSTEXPR_F int days_per_4years(year_t y, month_t m) noexcept
H AbslHashValueImpl(year_tag, H h, fields f)
CONSTEXPR_M int second() const noexcept
CONSTEXPR_M fields(year_t year, month_t month, day_t day, hour_t hour, minute_t minute, second_t second)
CONSTEXPR_M civil_time(const civil_time< U > &ct, preserves_data< T, U > *=nullptr) noexcept
CONSTEXPR_M civil_time & operator-=(diff_t n) noexcept
CONSTEXPR_F fields n_sec(year_t y, diff_t m, diff_t d, diff_t hh, diff_t mm, diff_t ss) noexcept
friend CONSTEXPR_F civil_time operator+(civil_time a, diff_t n) noexcept
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: utility.h:219
CONSTEXPR_F int days_per_month(year_t y, month_t m) noexcept
#define CONSTEXPR_D
CONSTEXPR_M civil_time & operator++() noexcept
CONSTEXPR_F diff_t ymd_ord(year_t y, month_t m, day_t d) noexcept
std::ostream & operator<<(std::ostream &os, const civil_year &y)
CONSTEXPR_F bool is_leap_year(year_t y) noexcept


abseil_cpp
Author(s):
autogenerated on Mon Feb 28 2022 21:31:18