OmniSciDB  fe05a0c208
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ExtractFromTime.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 /*
18  * Thank you Howard Hinnant for public domain date algorithms
19  * http://howardhinnant.github.io/date_algorithms.html
20  */
21 
22 #include "ExtractFromTime.h"
23 
24 #ifndef __CUDACC__
25 #include <cstdlib> // abort()
26 #endif
27 
28 namespace {
29 
30 // Number of days until Wednesday (because 2000-03-01 is a Wednesday.)
31 constexpr unsigned MONDAY = 2;
32 constexpr unsigned SUNDAY = 3;
33 constexpr unsigned SATURDAY = 4;
34 
35 // If OFFSET=MONDAY,
36 // then return day-of-era of the Monday of ISO 8601 week 1 in the given year-of-era.
37 // Similarly for SUNDAY and SATURDAY. In all cases, week 1 always contains Jan 4.
38 template <unsigned OFFSET>
39 DEVICE unsigned week_start_from_yoe(unsigned const yoe) {
40  unsigned const march1 = yoe * 365 + yoe / 4 - yoe / 100;
41  unsigned const jan4 = march1 + (MARJAN + 3);
42  unsigned const jan4dow = (jan4 + OFFSET) % 7;
43  return jan4 - jan4dow;
44 }
45 
46 } // namespace
47 
48 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
49 extract_hour(const int64_t lcltime) {
50  return unsigned_mod(lcltime, kSecsPerDay) / kSecsPerHour;
51 }
52 
53 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
54 extract_minute(const int64_t lcltime) {
55  return unsigned_mod(lcltime, kSecsPerHour) / kSecsPerMin;
56 }
57 
58 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
59 extract_second(const int64_t lcltime) {
60  return unsigned_mod(lcltime, kSecsPerMin);
61 }
62 
63 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
64 extract_millisecond(const int64_t lcltime) {
65  return unsigned_mod(lcltime, kSecsPerMin * kMilliSecsPerSec);
66 }
67 
68 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
69 extract_microsecond(const int64_t lcltime) {
70  return unsigned_mod(lcltime, kSecsPerMin * kMicroSecsPerSec);
71 }
72 
73 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
74 extract_nanosecond(const int64_t lcltime) {
75  return unsigned_mod(lcltime, kSecsPerMin * kNanoSecsPerSec);
76 }
77 
78 // First day of epoch is Thursday, so + 4 to have Sunday=0.
79 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
80 extract_dow(const int64_t lcltime) {
81  int64_t const days_past_epoch = floor_div(lcltime, kSecsPerDay);
82  return unsigned_mod(days_past_epoch + 4, kDaysPerWeek);
83 }
84 
85 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
86 extract_quarterday(const int64_t lcltime) {
87  return unsigned_mod(lcltime, kSecsPerDay) / kSecsPerQuarterDay + 1;
88 }
89 
90 DEVICE int32_t extract_month_fast(const int64_t lcltime) {
91  STATIC_QUAL const uint32_t cumulative_month_epoch_starts[kMonsPerYear] = {0,
92  2678400,
93  5270400,
94  7948800,
95  10540800,
96  13219200,
97  15897600,
98  18489600,
99  21168000,
100  23760000,
101  26438400,
102  29116800};
103  uint32_t seconds_march_1900 = lcltime + kEpochOffsetYear1900 - kSecsJanToMar1900;
104  uint32_t seconds_past_4year_period = seconds_march_1900 % kSecondsPer4YearCycle;
105  uint32_t year_seconds_past_4year_period =
106  (seconds_past_4year_period / kSecondsPerNonLeapYear) * kSecondsPerNonLeapYear;
107  if (seconds_past_4year_period >=
108  kSecondsPer4YearCycle - kUSecsPerDay) { // if we are in Feb 29th
109  year_seconds_past_4year_period -= kSecondsPerNonLeapYear;
110  }
111  uint32_t seconds_past_march =
112  seconds_past_4year_period - year_seconds_past_4year_period;
113  uint32_t month =
114  seconds_past_march / (30 * kUSecsPerDay); // Will make the correct month either be
115  // the guessed month or month before
116  month = month <= 11 ? month : 11;
117  if (cumulative_month_epoch_starts[month] > seconds_past_march) {
118  month--;
119  }
120  return (month + 2) % 12 + 1;
121 }
122 
123 DEVICE int32_t extract_quarter_fast(const int64_t lcltime) {
124  STATIC_QUAL const uint32_t cumulative_quarter_epoch_starts[4] = {
125  0, 7776000, 15638400, 23587200};
126  STATIC_QUAL const uint32_t cumulative_quarter_epoch_starts_leap_year[4] = {
127  0, 7862400, 15724800, 23673600};
128  uint32_t seconds_1900 = lcltime + kEpochOffsetYear1900;
129  uint32_t leap_years = (seconds_1900 - kSecsJanToMar1900) / kSecondsPer4YearCycle;
130  uint32_t year = (seconds_1900 - leap_years * kSecsPerDay) / kSecondsPerNonLeapYear;
131  uint32_t base_year_leap_years = (year - 1) / 4;
132  uint32_t base_year_seconds =
133  year * kSecondsPerNonLeapYear + base_year_leap_years * kUSecsPerDay;
134  bool is_leap_year = year % 4 == 0 && year != 0;
135  const uint32_t* quarter_offsets = is_leap_year
136  ? cumulative_quarter_epoch_starts_leap_year
137  : cumulative_quarter_epoch_starts;
138  uint32_t partial_year_seconds = seconds_1900 % base_year_seconds;
139  uint32_t quarter = partial_year_seconds / (90 * kUSecsPerDay);
140  quarter = quarter <= 3 ? quarter : 3;
141  if (quarter_offsets[quarter] > partial_year_seconds) {
142  quarter--;
143  }
144  return quarter + 1;
145 }
146 
147 DEVICE int32_t extract_year_fast(const int64_t lcltime) {
148  const uint32_t seconds_1900 = lcltime + kEpochOffsetYear1900;
149  const uint32_t leap_years = (seconds_1900 - kSecsJanToMar1900) / kSecondsPer4YearCycle;
150  const uint32_t year =
151  (seconds_1900 - leap_years * kUSecsPerDay) / kSecondsPerNonLeapYear + 1900;
152  return year;
153 }
154 
155 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
156 extract_epoch(const int64_t timeval) {
157  return timeval;
158 }
159 
160 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
161 extract_dateepoch(const int64_t timeval) {
162  return timeval - unsigned_mod(timeval, kSecsPerDay);
163 }
164 
165 // First day of epoch is Thursday, so + 3 to have Monday=0, then + 1 at the end.
166 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
167 extract_isodow(const int64_t timeval) {
168  int64_t const days_past_epoch = floor_div(timeval, kSecsPerDay);
169  return unsigned_mod(days_past_epoch + 3, kDaysPerWeek) + 1;
170 }
171 
172 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
173 extract_day(const int64_t timeval) {
174  int64_t const day = floor_div(timeval, kSecsPerDay);
175  unsigned const doe = unsigned_mod(day - kEpochAdjustedDays, kDaysPer400Years);
176  unsigned const yoe = (doe - doe / 1460 + doe / 36524 - (doe == 146096)) / 365;
177  unsigned const doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
178  unsigned const moy = (5 * doy + 2) / 153;
179  return doy - (153 * moy + 2) / 5 + 1;
180 }
181 
182 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
183 extract_day_of_year(const int64_t timeval) {
184  int64_t const day = floor_div(timeval, kSecsPerDay);
185  unsigned const doe = unsigned_mod(day - kEpochAdjustedDays, kDaysPer400Years);
186  unsigned const yoe = (doe - doe / 1460 + doe / 36524 - (doe == 146096)) / 365;
187  unsigned const doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
188  return doy + (doy < MARJAN ? 1 + JANMAR + (yoe % 4 == 0 && (yoe % 100 != 0 || yoe == 0))
189  : 1 - MARJAN);
190 }
191 
192 template <unsigned OFFSET>
193 ALWAYS_INLINE DEVICE int64_t extract_week(const int64_t timeval) {
194  int64_t const day = floor_div(timeval, kSecsPerDay);
195  unsigned const doe = unsigned_mod(day - kEpochAdjustedDays, kDaysPer400Years);
196  unsigned const yoe = (doe - doe / 1460 + doe / 36524 - (doe == 146096)) / 365;
197  unsigned week_start = week_start_from_yoe<OFFSET>(yoe);
198  if (doe < week_start) {
199  if (yoe == 0) {
200  // 2000-03-01 is OFFSET days from start of week, week + 9.
201  return (doe + OFFSET) / 7 + 9;
202  } else {
203  week_start = week_start_from_yoe<OFFSET>(yoe - 1);
204  }
205  }
206  return (doe - week_start) / 7 + 1;
207 }
208 
209 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
210 extract_week_monday(const int64_t timeval) {
211  return extract_week<MONDAY>(timeval);
212 }
213 
214 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
215 extract_week_sunday(const int64_t timeval) {
216  return extract_week<SUNDAY>(timeval);
217 }
218 
219 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
220 extract_week_saturday(const int64_t timeval) {
221  return extract_week<SATURDAY>(timeval);
222 }
223 
224 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
225 extract_month(const int64_t timeval) {
226  if (timeval >= 0LL && timeval <= UINT32_MAX - kEpochOffsetYear1900) {
227  return extract_month_fast(timeval);
228  }
229  int64_t const day = floor_div(timeval, kSecsPerDay);
230  unsigned const doe = unsigned_mod(day - kEpochAdjustedDays, kDaysPer400Years);
231  unsigned const yoe = (doe - doe / 1460 + doe / 36524 - (doe == 146096)) / 365;
232  unsigned const doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
233  unsigned const moy = (5 * doy + 2) / 153;
234  return moy + (moy < 10 ? 3 : -9);
235 }
236 
237 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
238 extract_quarter(const int64_t timeval) {
239  if (timeval >= 0LL && timeval <= UINT32_MAX - kEpochOffsetYear1900) {
240  return extract_quarter_fast(timeval);
241  }
242  constexpr int64_t quarter[12]{1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 1, 1};
243  int64_t const day = floor_div(timeval, kSecsPerDay);
244  unsigned const doe = unsigned_mod(day - kEpochAdjustedDays, kDaysPer400Years);
245  unsigned const yoe = (doe - doe / 1460 + doe / 36524 - (doe == 146096)) / 365;
246  unsigned const doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
247  unsigned const moy = (5 * doy + 2) / 153;
248  return quarter[moy];
249 }
250 
251 extern "C" RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t
252 extract_year(const int64_t timeval) {
253  if (timeval >= 0LL && timeval <= UINT32_MAX - kEpochOffsetYear1900) {
254  return extract_year_fast(timeval);
255  }
256  int64_t const day = floor_div(timeval, kSecsPerDay);
257  int64_t const era = floor_div(day - kEpochAdjustedDays, kDaysPer400Years);
258  unsigned const doe = day - kEpochAdjustedDays - era * kDaysPer400Years;
259  unsigned const yoe = (doe - doe / 1460 + doe / 36524 - (doe == 146096)) / 365;
260  unsigned const doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
261  return 2000 + era * 400 + yoe + (MARJAN <= doy);
262 }
263 
264 /*
265  * @brief support the SQL EXTRACT function
266  */
267 DEVICE int64_t ExtractFromTime(ExtractField field, const int64_t timeval) {
268  switch (field) {
269  case kEPOCH:
270  return extract_epoch(timeval);
271  case kDATEEPOCH:
272  return extract_dateepoch(timeval);
273  case kQUARTERDAY:
274  return extract_quarterday(timeval);
275  case kHOUR:
276  return extract_hour(timeval);
277  case kMINUTE:
278  return extract_minute(timeval);
279  case kSECOND:
280  return extract_second(timeval);
281  case kMILLISECOND:
282  return extract_millisecond(timeval);
283  case kMICROSECOND:
284  return extract_microsecond(timeval);
285  case kNANOSECOND:
286  return extract_nanosecond(timeval);
287  case kDOW:
288  return extract_dow(timeval);
289  case kISODOW:
290  return extract_isodow(timeval);
291  case kDAY:
292  return extract_day(timeval);
293  case kWEEK:
294  return extract_week_monday(timeval);
295  case kWEEK_SUNDAY:
296  return extract_week_sunday(timeval);
297  case kWEEK_SATURDAY:
298  return extract_week_saturday(timeval);
299  case kDOY:
300  return extract_day_of_year(timeval);
301  case kMONTH:
302  return extract_month(timeval);
303  case kQUARTER:
304  return extract_quarter(timeval);
305  case kYEAR:
306  return extract_year(timeval);
307  }
308 
309 #ifdef __CUDACC__
310  return -1;
311 #else
312  abort();
313 #endif
314 }
static constexpr int64_t kSecsPerDay
static constexpr uint32_t kSecsJanToMar1900
static constexpr uint32_t kUSecsPerDay
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_year(const int64_t timeval)
DEVICE int32_t extract_quarter_fast(const int64_t lcltime)
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_second(const int64_t lcltime)
static constexpr int64_t kSecsPerHour
static constexpr int64_t kSecsPerMin
static constexpr int64_t kNanoSecsPerSec
constexpr unsigned JANMAR
ALWAYS_INLINE DEVICE int64_t extract_week(const int64_t timeval)
static constexpr int64_t kSecsPerQuarterDay
#define STATIC_QUAL
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_minute(const int64_t lcltime)
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_month(const int64_t timeval)
DEVICE int64_t floor_div(int64_t const dividend, int64_t const divisor)
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_nanosecond(const int64_t lcltime)
#define OFFSET
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_millisecond(const int64_t lcltime)
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
DEVICE unsigned week_start_from_yoe(unsigned const yoe)
static constexpr int32_t kEpochAdjustedDays
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_week_sunday(const int64_t timeval)
static constexpr int32_t kDaysPerWeek
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_quarter(const int64_t timeval)
static constexpr uint32_t kSecondsPer4YearCycle
#define RUNTIME_EXPORT
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_week_monday(const int64_t timeval)
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_dateepoch(const int64_t timeval)
static constexpr int64_t kDaysPer400Years
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_day(const int64_t timeval)
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_epoch(const int64_t timeval)
constexpr unsigned MARJAN
DEVICE int64_t unsigned_mod(int64_t const dividend, int64_t const divisor)
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_dow(const int64_t lcltime)
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_hour(const int64_t lcltime)
DEVICE int64_t ExtractFromTime(ExtractField field, const int64_t timeval)
ExtractField
DEVICE int32_t extract_month_fast(const int64_t lcltime)
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_week_saturday(const int64_t timeval)
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_isodow(const int64_t timeval)
static constexpr uint32_t kSecondsPerNonLeapYear
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_microsecond(const int64_t lcltime)
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_quarterday(const int64_t lcltime)
#define ALWAYS_INLINE
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int64_t extract_day_of_year(const int64_t timeval)
#define UINT32_MAX
static constexpr int64_t kMicroSecsPerSec
static constexpr int32_t kMonsPerYear
DEVICE int32_t extract_year_fast(const int64_t lcltime)