OmniSciDB  dfae7c3b14
DateTruncate.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017 MapD Technologies, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /*
17  * Thank you Howard Hinnant for public domain date algorithms
18  * http://howardhinnant.github.io/date_algorithms.html
19  */
20 
21 #include "DateTruncate.h"
22 #include "ExtractFromTime.h"
23 
24 #ifndef __CUDACC__
25 #include <cstdlib> // abort()
26 #endif
27 
28 #include <cmath>
29 #include <ctime>
30 #include <iostream>
31 #include <limits>
32 
33 extern "C" ALWAYS_INLINE DEVICE int64_t datetrunc_minute(int64_t timeval) {
34  return timeval - unsigned_mod(timeval, kSecsPerMin);
35 }
36 
37 extern "C" ALWAYS_INLINE DEVICE int64_t datetrunc_hour(int64_t timeval) {
38  return timeval - unsigned_mod(timeval, kSecsPerHour);
39 }
40 
41 extern "C" ALWAYS_INLINE DEVICE int64_t datetrunc_quarterday(int64_t timeval) {
42  return timeval - unsigned_mod(timeval, kSecsPerQuarterDay);
43 }
44 
45 extern "C" ALWAYS_INLINE DEVICE int64_t datetrunc_day(int64_t timeval) {
46  return timeval - unsigned_mod(timeval, kSecsPerDay);
47 }
48 
49 extern "C" ALWAYS_INLINE DEVICE int64_t datetrunc_week(int64_t timeval) {
50  // Truncate to Monday. 1 Jan 1970 is a Thursday (+3*kSecsPerDay).
51  return timeval - unsigned_mod(timeval + 3 * kSecsPerDay, 7 * kSecsPerDay);
52 }
53 
54 extern "C" ALWAYS_INLINE DEVICE int64_t datetrunc_month(int64_t timeval) {
55  if (timeval >= 0L && timeval <= UINT32_MAX - (kEpochOffsetYear1900)) {
56  STATIC_QUAL const uint32_t cumulative_month_epoch_starts[kMonsPerYear] = {0,
57  2678400,
58  5270400,
59  7948800,
60  10540800,
61  13219200,
62  15897600,
63  18489600,
64  21168000,
65  23760000,
66  26438400,
67  29116800};
68  // Handles times from Thu 01 Jan 1970 00:00:00 - Thu 07 Feb 2036 06:28:15.
69  uint32_t seconds_march_1900 = timeval + kEpochOffsetYear1900 - kSecsJanToMar1900;
70  uint32_t seconds_past_4year_period = seconds_march_1900 % kSecondsPer4YearCycle;
71  uint32_t four_year_period_seconds =
72  (seconds_march_1900 / kSecondsPer4YearCycle) * kSecondsPer4YearCycle;
73  uint32_t year_seconds_past_4year_period =
74  (seconds_past_4year_period / kSecondsPerNonLeapYear) * kSecondsPerNonLeapYear;
75  if (seconds_past_4year_period >=
76  kSecondsPer4YearCycle - kUSecsPerDay) { // if we are in Feb 29th
77  year_seconds_past_4year_period -= kSecondsPerNonLeapYear;
78  }
79  uint32_t seconds_past_march =
80  seconds_past_4year_period - year_seconds_past_4year_period;
81  uint32_t month =
82  seconds_past_march / (30 * kUSecsPerDay); // Will make the correct month either
83  // be the guessed month or month before
84  month = month <= 11 ? month : 11;
85  if (cumulative_month_epoch_starts[month] > seconds_past_march) {
86  month--;
87  }
88  return (static_cast<int64_t>(four_year_period_seconds) +
89  year_seconds_past_4year_period + cumulative_month_epoch_starts[month] -
91  } else {
92  int64_t const day = floor_div(timeval, kSecsPerDay);
93  unsigned const doe = unsigned_mod(day - kEpochAdjustedDays, kDaysPer400Years);
94  unsigned const yoe = (doe - doe / 1460 + doe / 36524 - (doe == 146096)) / 365;
95  unsigned const doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
96  unsigned const moy = (5 * doy + 2) / 153;
97  unsigned const dom = doy - (153 * moy + 2) / 5;
98  return (day - dom) * kSecsPerDay;
99  }
100 }
101 
102 extern "C" ALWAYS_INLINE DEVICE int64_t datetrunc_quarter(int64_t timeval) {
103  if (timeval >= 0L && timeval <= UINT32_MAX - kEpochOffsetYear1900) {
104  STATIC_QUAL const uint32_t cumulative_quarter_epoch_starts[4] = {
105  0, 7776000, 15638400, 23587200};
106  STATIC_QUAL const uint32_t cumulative_quarter_epoch_starts_leap_year[4] = {
107  0, 7862400, 15724800, 23673600};
108  // Handles times from Thu 01 Jan 1970 00:00:00 - Thu 07 Feb 2036 06:28:15.
109  uint32_t seconds_1900 = timeval + kEpochOffsetYear1900;
110  uint32_t leap_years = (seconds_1900 - kSecsJanToMar1900) / kSecondsPer4YearCycle;
111  uint32_t year = (seconds_1900 - leap_years * kUSecsPerDay) / kSecondsPerNonLeapYear;
112  uint32_t base_year_leap_years = (year - 1) / 4;
113  uint32_t base_year_seconds =
114  year * kSecondsPerNonLeapYear + base_year_leap_years * kUSecsPerDay;
115  const bool is_leap_year = year % 4 == 0 && year != 0;
116  const uint32_t* quarter_offsets = is_leap_year
117  ? cumulative_quarter_epoch_starts_leap_year
118  : cumulative_quarter_epoch_starts;
119  uint32_t partial_year_seconds = seconds_1900 % base_year_seconds;
120  uint32_t quarter = partial_year_seconds / (90 * kUSecsPerDay);
121  quarter = quarter <= 3 ? quarter : 3;
122  if (quarter_offsets[quarter] > partial_year_seconds) {
123  quarter--;
124  }
125  return (static_cast<int64_t>(base_year_seconds) + quarter_offsets[quarter] -
127  } else {
128  int64_t const day = floor_div(timeval, kSecsPerDay);
129  unsigned const doe = unsigned_mod(day - kEpochAdjustedDays, kDaysPer400Years);
130  unsigned const yoe = (doe - doe / 1460 + doe / 36524 - (doe == 146096)) / 365;
131  unsigned const doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
132  constexpr unsigned apr1 = 31; // Days in march
133  unsigned doq; // Day-of-quarter = Days since last Apr1, Jul1, Oct1, Jan1.
134  if (doy < apr1) {
135  bool const leap = yoe % 4 == 0 && (yoe % 100 != 0 || yoe == 0);
136  doq = JANMAR + leap + doy; // Q1
137  } else {
138  unsigned const q = (3 * (doy - apr1) + 2) / 275; // quarter = 0, 1, 2
139  doq = doy - (apr1 + q * 92 - (q != 0)); // Q2, Q3, Q4
140  }
141  return (day - doq) * kSecsPerDay;
142  }
143 }
144 
145 extern "C" ALWAYS_INLINE DEVICE int64_t datetrunc_year(int64_t timeval) {
146  if (timeval >= 0L && timeval <= UINT32_MAX - kEpochOffsetYear1900) {
147  // Handles times from Thu 01 Jan 1970 00:00:00 - Thu 07 Feb 2036 06:28:15.
148  uint32_t seconds_1900 = static_cast<uint32_t>(timeval) + kEpochOffsetYear1900;
149  uint32_t leap_years = (seconds_1900 - kSecsJanToMar1900) / kSecondsPer4YearCycle;
150  uint32_t year = (seconds_1900 - leap_years * kUSecsPerDay) / kSecondsPerNonLeapYear;
151  uint32_t base_year_leap_years = (year - 1) / 4;
152  return (static_cast<int64_t>(year) * kSecondsPerNonLeapYear +
153  base_year_leap_years * kUSecsPerDay - kEpochOffsetYear1900);
154  } else {
155  int64_t const day = floor_div(timeval, kSecsPerDay);
156  unsigned const doe = unsigned_mod(day - kEpochAdjustedDays, kDaysPer400Years);
157  unsigned const yoe = (doe - doe / 1460 + doe / 36524 - (doe == 146096)) / 365;
158  unsigned const doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
159  unsigned docy; // Day-of-calendar-year = Days since last Jan1.
160  if (doy < MARJAN) {
161  bool const leap = yoe % 4 == 0 && (yoe == 0 || yoe % 100 != 0);
162  docy = JANMAR + leap + doy;
163  } else {
164  docy = doy - MARJAN;
165  }
166  return (day - docy) * kSecsPerDay;
167  }
168 }
169 
170 extern "C" ALWAYS_INLINE DEVICE int64_t datetrunc_decade(int64_t timeval) {
171  // Number of days from x00301 to (x+1)00101. Always includes exactly two leap days.
172  constexpr unsigned decmarjan = MARJAN + 9 * 365 + 2;
173  int64_t const day = floor_div(timeval, kSecsPerDay);
174  unsigned const doe = unsigned_mod(day - kEpochAdjustedDays, kDaysPer400Years);
175  unsigned const yoe = (doe - doe / 1460 + doe / 36524 - (doe == 146096)) / 365;
176  unsigned const decoe = yoe - yoe % 10; // Decade-of-era
177  // Initialize to days after mar1 of decade, then adjust to after jan1 below.
178  unsigned days_after_decade = doe - (365 * decoe + decoe / 4 - decoe / 100);
179  if (days_after_decade < decmarjan) {
180  bool const leap = decoe % 4 == 0 && (decoe == 0 || decoe % 100 != 0);
181  days_after_decade += JANMAR + leap;
182  } else {
183  days_after_decade -= decmarjan;
184  }
185  return (day - days_after_decade) * kSecsPerDay;
186 }
187 
188 extern "C" ALWAYS_INLINE DEVICE int64_t datetrunc_century(int64_t timeval) {
189  int64_t const day = floor_div(timeval, kSecsPerDay);
190  unsigned const doe = unsigned_mod(day - kEpochAdjustedDays, kDaysPer400Years);
191  // Day-of-century = Days since last 010101 (Jan 1 1901, 2001, 2101, etc.)
192  unsigned const doc = doe < MARJAN ? doe + (36525 - MARJAN) : (doe - MARJAN) % 36524;
193  return (day - doc) * kSecsPerDay;
194 }
195 
196 extern "C" ALWAYS_INLINE DEVICE int64_t datetrunc_millennium(int64_t timeval) {
197  constexpr unsigned millennium2001 = 365242; // Days from Jan 1 2001 to 3001.
198  int64_t const day = floor_div(timeval, kSecsPerDay);
199  // lcm(400, 1000) = 2000 so use 5*400-year eras at a time.
200  unsigned dom = unsigned_mod(day - kEpochAdjustedDays, 5 * kDaysPer400Years);
201  if (dom < MARJAN) {
202  dom += millennium2001 + 1 - MARJAN;
203  } else if (dom < MARJAN + millennium2001) {
204  dom -= MARJAN;
205  } else {
206  dom -= MARJAN + millennium2001;
207  }
208  return (day - dom) * kSecsPerDay;
209 }
210 
211 /*
212  * @brief support the SQL DATE_TRUNC function
213  */
214 int64_t DateTruncate(DatetruncField field, const int64_t timeval) {
215  switch (field) {
216  case dtNANOSECOND:
217  case dtMICROSECOND:
218  case dtMILLISECOND:
219  case dtSECOND:
220  return timeval;
221  case dtMINUTE:
222  return datetrunc_minute(timeval);
223  case dtHOUR:
224  return datetrunc_hour(timeval);
225  case dtQUARTERDAY:
226  return datetrunc_quarterday(timeval);
227  case dtDAY:
228  return datetrunc_day(timeval);
229  case dtWEEK:
230  return datetrunc_week(timeval);
231  case dtMONTH:
232  return datetrunc_month(timeval);
233  case dtQUARTER:
234  return datetrunc_quarter(timeval);
235  case dtYEAR:
236  return datetrunc_year(timeval);
237  case dtDECADE:
238  return datetrunc_decade(timeval);
239  case dtCENTURY:
240  return datetrunc_century(timeval);
241  case dtMILLENNIUM:
242  return datetrunc_millennium(timeval);
243  default:
244 #ifdef __CUDACC__
245  return std::numeric_limits<int64_t>::min();
246 #else
247  abort();
248 #endif
249  }
250 }
251 
252 // scale is 10^{3,6,9}
253 extern "C" ALWAYS_INLINE DEVICE int64_t
254 DateTruncateHighPrecisionToDate(const int64_t timeval, const int64_t scale) {
255  return floor_div(timeval, scale * kSecsPerDay) * kSecsPerDay;
256 }
257 
258 extern "C" ALWAYS_INLINE DEVICE int64_t
260  const int64_t scale,
261  const int64_t null_val) {
262  if (timeval == null_val) {
263  return null_val;
264  }
265  return DateTruncateHighPrecisionToDate(timeval, scale);
266 }
267 
268 namespace {
269 
270 struct EraTime {
271  int64_t const era;
272  int const yoe; // year-of-era
273  int const moy; // month-of-year (March = 0)
274  int const dom; // day-of-month
275  int const sod; // second-of-day
276 
277  DEVICE static EraTime make(int64_t const time) {
278  int64_t const day = floor_div(time, kSecsPerDay);
279  int64_t const era = floor_div(day - kEpochAdjustedDays, kDaysPer400Years);
280  int const sod = time - day * kSecsPerDay;
281  int const doe = day - kEpochAdjustedDays - era * kDaysPer400Years;
282  int const yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
283  int const doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
284  int const moy = (5 * doy + 2) / 153;
285  int const dom = doy - (153 * moy + 2) / 5;
286  return {era, yoe, moy, dom, sod};
287  }
288 
289  DEVICE EraTime operator-() const { return {-era, -yoe, -moy, -dom, -sod}; }
290 
292  return {era - rhs.era, yoe - rhs.yoe, moy - rhs.moy, dom - rhs.dom, sod - rhs.sod};
293  }
294 
295  enum Field { ERA, YOE, MOY, DOM, SOD };
296  // Sign of EraTime starting at field.
297  DEVICE int sign(Field const field) const {
298  switch (field) {
299  case ERA:
300  if (era != 0) {
301  return era < 0 ? -1 : 1;
302  }
303  case YOE:
304  if (yoe != 0) {
305  return yoe < 0 ? -1 : 1;
306  }
307  case MOY:
308  if (moy != 0) {
309  return moy < 0 ? -1 : 1;
310  }
311  case DOM:
312  if (dom != 0) {
313  return dom < 0 ? -1 : 1;
314  }
315  case SOD:
316  if (sod != 0) {
317  return sod < 0 ? -1 : 1;
318  }
319  default:
320  return 0;
321  }
322  }
323 
324  DEVICE int64_t count(DatetruncField const field) const {
325  int const sgn = sign(ERA);
326  EraTime const ut = sgn == -1 ? -*this : *this; // Unsigned time
327  switch (field) {
328  case dtMONTH:
329  return sgn * (12 * (400 * ut.era + ut.yoe) + ut.moy - (ut.sign(DOM) == -1));
330  case dtQUARTER: {
331  int const quarters = ut.moy / 3;
332  int const rem = ut.moy % 3;
333  return sgn * (4 * (400 * ut.era + ut.yoe) + quarters -
334  (rem < 0 || (rem == 0 && ut.sign(DOM) == -1)));
335  }
336  case dtYEAR:
337  return sgn * (400 * ut.era + ut.yoe - (ut.sign(MOY) == -1));
338  case dtDECADE: {
339  uint64_t const decades = (400 * ut.era + ut.yoe) / 10;
340  unsigned const rem = (400 * ut.era + ut.yoe) % 10;
341  return sgn * (decades - (rem == 0 && ut.sign(MOY) == -1));
342  }
343  case dtCENTURY: {
344  uint64_t const centuries = (400 * ut.era + ut.yoe) / 100;
345  unsigned const rem = (400 * ut.era + ut.yoe) % 100;
346  return sgn * (centuries - (rem == 0 && ut.sign(MOY) == -1));
347  }
348  case dtMILLENNIUM: {
349  uint64_t const millennia = (400 * ut.era + ut.yoe) / 1000;
350  unsigned const rem = (400 * ut.era + ut.yoe) % 1000;
351  return sgn * (millennia - (rem == 0 && ut.sign(MOY) == -1));
352  }
353  default:
354 #ifdef __CUDACC__
355  return std::numeric_limits<int64_t>::min();
356 #else
357  abort();
358 #endif
359  }
360  }
361 };
362 
363 } // namespace
364 
365 extern "C" DEVICE int64_t DateDiff(const DatetruncField datepart,
366  const int64_t startdate,
367  const int64_t enddate) {
368  switch (datepart) {
369  case dtNANOSECOND:
370  return (enddate - startdate) * kNanoSecsPerSec;
371  case dtMICROSECOND:
372  return (enddate - startdate) * kMicroSecsPerSec;
373  case dtMILLISECOND:
374  return (enddate - startdate) * kMilliSecsPerSec;
375  case dtSECOND:
376  return enddate - startdate;
377  case dtMINUTE:
378  return (enddate - startdate) / kSecsPerMin;
379  case dtHOUR:
380  return (enddate - startdate) / kSecsPerHour;
381  case dtQUARTERDAY:
382  return (enddate - startdate) / (kSecsPerDay / 4);
383  case dtDAY:
384  return (enddate - startdate) / kSecsPerDay;
385  case dtWEEK:
386  return (enddate - startdate) / (7 * kSecsPerDay);
387  default:
388  return (EraTime::make(enddate) - EraTime::make(startdate)).count(datepart);
389  }
390 }
391 
392 extern "C" DEVICE int64_t DateDiffHighPrecision(const DatetruncField datepart,
393  const int64_t startdate,
394  const int64_t enddate,
395  const int32_t start_dim,
396  const int32_t end_dim) {
397  // Return pow(10,i). Only valid for i = 0, 3, 6, 9.
398  constexpr int pow10[10]{1, 0, 0, 1000, 0, 0, 1000 * 1000, 0, 0, 1000 * 1000 * 1000};
399  switch (datepart) {
400  case dtNANOSECOND:
401  case dtMICROSECOND:
402  case dtMILLISECOND: {
403  static_assert(dtMILLISECOND + 1 == dtMICROSECOND, "Please keep these consecutive.");
404  static_assert(dtMICROSECOND + 1 == dtNANOSECOND, "Please keep these consecutive.");
405  int const target_dim = (datepart - (dtMILLISECOND - 1)) * 3; // 3, 6, or 9.
406  int const delta_dim = end_dim - start_dim; // in [-9,9] multiple of 3
407  int const adj_dim = target_dim - (delta_dim < 0 ? start_dim : end_dim);
408  int64_t const numerator = delta_dim < 0 ? enddate * pow10[-delta_dim] - startdate
409  : enddate - startdate * pow10[delta_dim];
410  return adj_dim < 0 ? numerator / pow10[-adj_dim] : numerator * pow10[adj_dim];
411  }
412  default:
413  int64_t const end_seconds = floor_div(enddate, pow10[end_dim]);
414  int delta_ns = (enddate - end_seconds * pow10[end_dim]) * pow10[9 - end_dim];
415  int64_t const start_seconds = floor_div(startdate, pow10[start_dim]);
416  delta_ns -= (startdate - start_seconds * pow10[start_dim]) * pow10[9 - start_dim];
417  int64_t const delta_s = end_seconds - start_seconds;
418  // sub-second values must be accounted for when calling DateDiff. Examples:
419  // 2000-02-15 12:00:00.006 to 2000-03-15 12:00:00.005 is 0 months.
420  // 2000-02-15 12:00:00.006 to 2000-03-15 12:00:00.006 is 1 month.
421  int const adj_sec =
422  0 < delta_s && delta_ns < 0 ? -1 : delta_s < 0 && 0 < delta_ns ? 1 : 0;
423  return DateDiff(datepart, start_seconds, end_seconds + adj_sec);
424  }
425 }
426 
427 extern "C" DEVICE int64_t DateDiffNullable(const DatetruncField datepart,
428  const int64_t startdate,
429  const int64_t enddate,
430  const int64_t null_val) {
431  if (startdate == null_val || enddate == null_val) {
432  return null_val;
433  }
434  return DateDiff(datepart, startdate, enddate);
435 }
436 
437 extern "C" DEVICE int64_t DateDiffHighPrecisionNullable(const DatetruncField datepart,
438  const int64_t startdate,
439  const int64_t enddate,
440  const int32_t start_dim,
441  const int32_t end_dim,
442  const int64_t null_val) {
443  if (startdate == null_val || enddate == null_val) {
444  return null_val;
445  }
446  return DateDiffHighPrecision(datepart, startdate, enddate, start_dim, end_dim);
447 }
static constexpr int64_t kSecsPerDay
static constexpr uint32_t kSecsJanToMar1900
static constexpr uint32_t kUSecsPerDay
DEVICE int sign(Field const field) const
DEVICE int64_t count(DatetruncField const field) const
ALWAYS_INLINE DEVICE int64_t datetrunc_week(int64_t timeval)
ALWAYS_INLINE DEVICE int64_t datetrunc_quarter(int64_t timeval)
int64_t DateTruncate(DatetruncField field, const int64_t timeval)
static constexpr int64_t kSecsPerHour
static constexpr int64_t kSecsPerMin
static constexpr int64_t kNanoSecsPerSec
ALWAYS_INLINE DEVICE int64_t datetrunc_millennium(int64_t timeval)
constexpr unsigned JANMAR
static constexpr int64_t kSecsPerQuarterDay
static DEVICE EraTime make(int64_t const time)
ALWAYS_INLINE DEVICE int64_t datetrunc_quarterday(int64_t timeval)
DEVICE int64_t DateDiffNullable(const DatetruncField datepart, const int64_t startdate, const int64_t enddate, const int64_t null_val)
#define STATIC_QUAL
DEVICE int64_t DateDiffHighPrecisionNullable(const DatetruncField datepart, const int64_t startdate, const int64_t enddate, const int32_t start_dim, const int32_t end_dim, const int64_t null_val)
ALWAYS_INLINE DEVICE int64_t datetrunc_decade(int64_t timeval)
DEVICE int64_t floor_div(int64_t const dividend, int64_t const divisor)
ALWAYS_INLINE DEVICE int64_t datetrunc_hour(int64_t timeval)
static constexpr uint32_t kEpochOffsetYear1900
#define DEVICE
static constexpr int64_t kMilliSecsPerSec
const rapidjson::Value & field(const rapidjson::Value &obj, const char field[]) noexcept
Definition: JsonAccessors.h:31
static constexpr int32_t kEpochAdjustedDays
DatetruncField
Definition: DateTruncate.h:27
DEVICE EraTime operator-(EraTime const &rhs)
ALWAYS_INLINE DEVICE int64_t DateTruncateHighPrecisionToDateNullable(const int64_t timeval, const int64_t scale, const int64_t null_val)
ALWAYS_INLINE DEVICE int64_t datetrunc_year(int64_t timeval)
static constexpr uint32_t kSecondsPer4YearCycle
static constexpr int64_t kDaysPer400Years
constexpr unsigned MARJAN
DEVICE int64_t unsigned_mod(int64_t const dividend, int64_t const divisor)
DEVICE int64_t DateDiff(const DatetruncField datepart, const int64_t startdate, const int64_t enddate)
ALWAYS_INLINE DEVICE int64_t datetrunc_month(int64_t timeval)
ALWAYS_INLINE DEVICE int64_t datetrunc_century(int64_t timeval)
DEVICE int64_t DateDiffHighPrecision(const DatetruncField datepart, const int64_t startdate, const int64_t enddate, const int32_t start_dim, const int32_t end_dim)
ALWAYS_INLINE DEVICE int64_t datetrunc_minute(int64_t timeval)
ALWAYS_INLINE DEVICE int64_t datetrunc_day(int64_t timeval)
ALWAYS_INLINE DEVICE int64_t DateTruncateHighPrecisionToDate(const int64_t timeval, const int64_t scale)
static constexpr uint32_t kSecondsPerNonLeapYear
#define ALWAYS_INLINE
static constexpr int64_t kMicroSecsPerSec
static constexpr int32_t kMonsPerYear