OmniSciDB  72c90bc290
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DateAdd.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, 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 #include "DateAdd.h"
18 
19 #ifdef EXECUTE_INCLUDE
20 
21 #ifndef __CUDACC__
22 #include <cstdlib> // abort()
23 #endif
24 
25 namespace {
26 
27 // Represent time as number of months + day-of-month + seconds since 2000 March 1.
28 class MonthDaySecond {
29  int64_t months; // Number of months since 2000 March 1.
30  unsigned dom; // day-of-month (0-based)
31  unsigned sod; // second-of-day
32 
33  // Clamp day-of-month to max day of the month. E.g. April 31 -> 30.
34  DEVICE static unsigned clampDom(unsigned yoe, unsigned moy, unsigned dom) {
35  constexpr unsigned max_days[11]{30, 29, 30, 29, 30, 30, 29, 30, 29, 30, 30};
36  if (dom < 28) {
37  return dom;
38  } else {
39  unsigned const max_day =
40  moy == 11 ? 27 + (++yoe % 4 == 0 && (yoe % 100 != 0 || yoe == 400))
41  : max_days[moy];
42  return dom < max_day ? dom : max_day;
43  }
44  }
45 
46  public:
47  DEVICE MonthDaySecond(int64_t const timeval) {
48  int64_t const day = floor_div(timeval, kSecsPerDay);
49  int64_t const era = floor_div(day - kEpochAdjustedDays, kDaysPer400Years);
50  sod = timeval - day * kSecsPerDay;
51  unsigned const doe = day - kEpochAdjustedDays - era * kDaysPer400Years;
52  unsigned const yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
53  unsigned const doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
54  unsigned const moy = (5 * doy + 2) / 153;
55  dom = doy - (153 * moy + 2) / 5;
56  months = (era * 400 + yoe) * 12 + moy;
57  }
58 
59  DEVICE MonthDaySecond const& addMonths(int64_t const months) {
60  this->months += months;
61  return *this;
62  }
63 
64  // Return number of seconds since 1 January 1970.
65  DEVICE int64_t unixtime() const {
66  int64_t const era = floor_div(months, 12 * 400);
67  unsigned const moe = months - era * (12 * 400);
68  unsigned const yoe = moe / 12;
69  unsigned const moy = moe % 12;
70  unsigned const doy = (153 * moy + 2) / 5 + clampDom(yoe, moy, dom);
71  unsigned const doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
72  return (kEpochAdjustedDays + era * kDaysPer400Years + doe) * kSecsPerDay + sod;
73  }
74 };
75 
76 } // namespace
77 
78 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t DateAdd(DateaddField field,
79  const int64_t number,
80  const int64_t timeval) {
81  switch (field) {
82  case daSECOND:
83  return timeval + number;
84  case daMINUTE:
85  return timeval + number * kSecsPerMin;
86  case daHOUR:
87  return timeval + number * kSecsPerHour;
88  case daWEEKDAY:
89  case daDAYOFYEAR:
90  case daDAY:
91  return timeval + number * kSecsPerDay;
92  case daWEEK:
93  return timeval + number * (7 * kSecsPerDay);
94  case daMONTH:
95  return MonthDaySecond(timeval).addMonths(number).unixtime();
96  case daQUARTER:
97  return MonthDaySecond(timeval).addMonths(number * 3).unixtime();
98  case daYEAR:
99  return MonthDaySecond(timeval).addMonths(number * 12).unixtime();
100  case daDECADE:
101  return MonthDaySecond(timeval).addMonths(number * 120).unixtime();
102  case daCENTURY:
103  return MonthDaySecond(timeval).addMonths(number * 1200).unixtime();
104  case daMILLENNIUM:
105  return MonthDaySecond(timeval).addMonths(number * 12000).unixtime();
106  default:
107 #ifdef __CUDACC__
108  return -1;
109 #else
110  abort();
111 #endif
112  }
113 }
114 
115 // The dimension of the return value is always equal to the timeval dimension.
116 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
117 DateAddHighPrecision(DateaddField field,
118  const int64_t number,
119  const int64_t timeval,
120  const int32_t dim) {
121  // Valid only for i=0, 3, 6, 9.
122  constexpr unsigned pow10[10]{
123  1, 0, 0, 1000, 0, 0, 1000 * 1000, 0, 0, 1000 * 1000 * 1000};
124  switch (field) {
125  case daNANOSECOND:
126  case daMICROSECOND:
127  case daMILLISECOND: {
128  static_assert(daMILLISECOND + 1 == daMICROSECOND, "Please keep these consecutive.");
129  static_assert(daMICROSECOND + 1 == daNANOSECOND, "Please keep these consecutive.");
130  unsigned const field_dim = (field - (daMILLISECOND - 1)) * 3;
131  int const adj_dim = dim - field_dim;
132  if (adj_dim < 0) {
133  return timeval + floor_div(number, pow10[-adj_dim]);
134  } else {
135  return timeval + number * pow10[adj_dim];
136  }
137  }
138  default:
139  unsigned const scale = pow10[dim];
140  return DateAdd(field, number, floor_div(timeval, scale)) * scale +
141  unsigned_mod(timeval, scale);
142  }
143 }
144 
145 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
146 DateAddNullable(const DateaddField field,
147  const int64_t number,
148  const int64_t timeval,
149  const int64_t null_val) {
150  if (timeval == null_val) {
151  return null_val;
152  }
153  return DateAdd(field, number, timeval);
154 }
155 
156 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
158  const int64_t number,
159  const int64_t timeval,
160  const int32_t dim,
161  const int64_t null_val) {
162  if (timeval == null_val) {
163  return null_val;
164  }
165  return DateAddHighPrecision(field, number, timeval, dim);
166 }
167 
168 #endif // EXECUTE_INCLUDE
static constexpr int64_t kSecsPerDay
static constexpr int64_t kSecsPerHour
static constexpr int64_t kSecsPerMin
DEVICE int64_t floor_div(int64_t const dividend, int64_t const divisor)
RUNTIME_EXPORT DEVICE int64_t DateAddHighPrecisionNullable(const DateaddField field, const int64_t number, const int64_t timeval, const int32_t dim, const int64_t null_val)
Definition: DateAdd.h:47
#define DEVICE
const rapidjson::Value & field(const rapidjson::Value &obj, const char field[]) noexcept
Definition: JsonAccessors.h:33
Definition: DateAdd.h:43
static constexpr int32_t kEpochAdjustedDays
DateaddField
Definition: DateAdd.h:42
Definition: DateAdd.h:56
#define RUNTIME_EXPORT
static constexpr int64_t kDaysPer400Years
DEVICE int64_t unsigned_mod(int64_t const dividend, int64_t const divisor)
Definition: DateAdd.h:46
#define ALWAYS_INLINE