OmniSciDB  95562058bd
 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 #include "../Shared/funcannotations.h"
24 
25 #ifndef __CUDACC__
26 #include <cstdlib> // abort()
27 #endif
28 
29 namespace {
30 
31 // Return day-of-era of the Monday of ISO 8601 week 1 in the given yoe.
32 // Week 1 always contains Jan 4.
33 DEVICE unsigned iso_week_start_from_yoe(unsigned const yoe) {
34  unsigned const march1 = yoe * 365 + yoe / 4 - yoe / 100;
35  unsigned const jan4 = march1 + (31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 + 3);
36  unsigned const jan4dow = (jan4 + 2) % 7; // 2000-03-01 is Wed so + 2 to get Mon = 0.
37  return jan4 - jan4dow;
38 }
39 
40 } // namespace
41 
42 extern "C" ALWAYS_INLINE DEVICE int64_t extract_hour(const int64_t lcltime) {
43  return unsigned_mod(lcltime, kSecsPerDay) / kSecsPerHour;
44 }
45 
46 extern "C" ALWAYS_INLINE DEVICE int64_t extract_minute(const int64_t lcltime) {
47  return unsigned_mod(lcltime, kSecsPerHour) / kSecsPerMin;
48 }
49 
50 extern "C" ALWAYS_INLINE DEVICE int64_t extract_second(const int64_t lcltime) {
51  return unsigned_mod(lcltime, kSecsPerMin);
52 }
53 
54 extern "C" ALWAYS_INLINE DEVICE int64_t extract_millisecond(const int64_t lcltime) {
55  return unsigned_mod(lcltime, kSecsPerMin * kMilliSecsPerSec);
56 }
57 
58 extern "C" ALWAYS_INLINE DEVICE int64_t extract_microsecond(const int64_t lcltime) {
59  return unsigned_mod(lcltime, kSecsPerMin * kMicroSecsPerSec);
60 }
61 
62 extern "C" ALWAYS_INLINE DEVICE int64_t extract_nanosecond(const int64_t lcltime) {
63  return unsigned_mod(lcltime, kSecsPerMin * kNanoSecsPerSec);
64 }
65 
66 // First day of epoch is Thursday, so + 4 to have Sunday=0.
67 extern "C" ALWAYS_INLINE DEVICE int64_t extract_dow(const int64_t lcltime) {
68  int64_t const days_past_epoch = floor_div(lcltime, kSecsPerDay);
69  return unsigned_mod(days_past_epoch + 4, kDaysPerWeek);
70 }
71 
72 extern "C" ALWAYS_INLINE DEVICE int64_t extract_quarterday(const int64_t lcltime) {
73  return unsigned_mod(lcltime, kSecsPerDay) / kSecsPerQuarterDay + 1;
74 }
75 
76 DEVICE int32_t extract_month_fast(const int64_t lcltime) {
77  STATIC_QUAL const uint32_t cumulative_month_epoch_starts[kMonsPerYear] = {0,
78  2678400,
79  5270400,
80  7948800,
81  10540800,
82  13219200,
83  15897600,
84  18489600,
85  21168000,
86  23760000,
87  26438400,
88  29116800};
89  uint32_t seconds_march_1900 = lcltime + kEpochOffsetYear1900 - kSecsJanToMar1900;
90  uint32_t seconds_past_4year_period = seconds_march_1900 % kSecondsPer4YearCycle;
91  uint32_t year_seconds_past_4year_period =
92  (seconds_past_4year_period / kSecondsPerNonLeapYear) * kSecondsPerNonLeapYear;
93  if (seconds_past_4year_period >=
94  kSecondsPer4YearCycle - kUSecsPerDay) { // if we are in Feb 29th
95  year_seconds_past_4year_period -= kSecondsPerNonLeapYear;
96  }
97  uint32_t seconds_past_march =
98  seconds_past_4year_period - year_seconds_past_4year_period;
99  uint32_t month =
100  seconds_past_march / (30 * kUSecsPerDay); // Will make the correct month either be
101  // the guessed month or month before
102  month = month <= 11 ? month : 11;
103  if (cumulative_month_epoch_starts[month] > seconds_past_march) {
104  month--;
105  }
106  return (month + 2) % 12 + 1;
107 }
108 
109 DEVICE int32_t extract_quarter_fast(const int64_t lcltime) {
110  STATIC_QUAL const uint32_t cumulative_quarter_epoch_starts[4] = {
111  0, 7776000, 15638400, 23587200};
112  STATIC_QUAL const uint32_t cumulative_quarter_epoch_starts_leap_year[4] = {
113  0, 7862400, 15724800, 23673600};
114  uint32_t seconds_1900 = lcltime + kEpochOffsetYear1900;
115  uint32_t leap_years = (seconds_1900 - kSecsJanToMar1900) / kSecondsPer4YearCycle;
116  uint32_t year = (seconds_1900 - leap_years * kSecsPerDay) / kSecondsPerNonLeapYear;
117  uint32_t base_year_leap_years = (year - 1) / 4;
118  uint32_t base_year_seconds =
119  year * kSecondsPerNonLeapYear + base_year_leap_years * kUSecsPerDay;
120  bool is_leap_year = year % 4 == 0 && year != 0;
121  const uint32_t* quarter_offsets = is_leap_year
122  ? cumulative_quarter_epoch_starts_leap_year
123  : cumulative_quarter_epoch_starts;
124  uint32_t partial_year_seconds = seconds_1900 % base_year_seconds;
125  uint32_t quarter = partial_year_seconds / (90 * kUSecsPerDay);
126  quarter = quarter <= 3 ? quarter : 3;
127  if (quarter_offsets[quarter] > partial_year_seconds) {
128  quarter--;
129  }
130  return quarter + 1;
131 }
132 
133 DEVICE int32_t extract_year_fast(const int64_t lcltime) {
134  const uint32_t seconds_1900 = lcltime + kEpochOffsetYear1900;
135  const uint32_t leap_years = (seconds_1900 - kSecsJanToMar1900) / kSecondsPer4YearCycle;
136  const uint32_t year =
137  (seconds_1900 - leap_years * kUSecsPerDay) / kSecondsPerNonLeapYear + 1900;
138  return year;
139 }
140 
141 extern "C" ALWAYS_INLINE DEVICE int64_t extract_epoch(const int64_t timeval) {
142  return timeval;
143 }
144 
145 extern "C" ALWAYS_INLINE DEVICE int64_t extract_dateepoch(const int64_t timeval) {
146  return timeval - unsigned_mod(timeval, kSecsPerDay);
147 }
148 
149 // First day of epoch is Thursday, so + 3 to have Monday=0, then + 1 at the end.
150 extern "C" ALWAYS_INLINE DEVICE int64_t extract_isodow(const int64_t timeval) {
151  int64_t const days_past_epoch = floor_div(timeval, kSecsPerDay);
152  return unsigned_mod(days_past_epoch + 3, kDaysPerWeek) + 1;
153 }
154 
155 extern "C" ALWAYS_INLINE DEVICE int64_t extract_day(const int64_t timeval) {
156  int64_t const day = floor_div(timeval, kSecsPerDay);
157  unsigned const doe = unsigned_mod(day - kEpochAdjustedDays, kDaysPer400Years);
158  unsigned const yoe = (doe - doe / 1460 + doe / 36524 - (doe == 146096)) / 365;
159  unsigned const doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
160  unsigned const moy = (5 * doy + 2) / 153;
161  return doy - (153 * moy + 2) / 5 + 1;
162 }
163 
164 extern "C" ALWAYS_INLINE DEVICE int64_t extract_day_of_year(const int64_t timeval) {
165  int64_t const day = floor_div(timeval, kSecsPerDay);
166  unsigned const doe = unsigned_mod(day - kEpochAdjustedDays, kDaysPer400Years);
167  unsigned const yoe = (doe - doe / 1460 + doe / 36524 - (doe == 146096)) / 365;
168  unsigned const doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
169  return doy + (doy < MARJAN ? 1 + JANMAR + (yoe % 4 == 0 && (yoe % 100 != 0 || yoe == 0))
170  : 1 - MARJAN);
171 }
172 
173 extern "C" ALWAYS_INLINE DEVICE int64_t extract_week(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 iso_week_start = iso_week_start_from_yoe(yoe);
178  if (doe < iso_week_start) {
179  if (yoe == 0) {
180  return (doe + 2) / 7 + 9; // 2000-03-01 is +2 days from Mon, week +9.
181  } else {
182  iso_week_start = iso_week_start_from_yoe(yoe - 1);
183  }
184  }
185  return (doe - iso_week_start) / 7 + 1;
186 }
187 
188 extern "C" ALWAYS_INLINE DEVICE int64_t extract_month(const int64_t timeval) {
189  if (timeval >= 0L && timeval <= UINT32_MAX - kEpochOffsetYear1900) {
190  return extract_month_fast(timeval);
191  }
192  int64_t const day = floor_div(timeval, kSecsPerDay);
193  unsigned const doe = unsigned_mod(day - kEpochAdjustedDays, kDaysPer400Years);
194  unsigned const yoe = (doe - doe / 1460 + doe / 36524 - (doe == 146096)) / 365;
195  unsigned const doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
196  unsigned const moy = (5 * doy + 2) / 153;
197  return moy + (moy < 10 ? 3 : -9);
198 }
199 
200 extern "C" ALWAYS_INLINE DEVICE int64_t extract_quarter(const int64_t timeval) {
201  if (timeval >= 0L && timeval <= UINT32_MAX - kEpochOffsetYear1900) {
202  return extract_quarter_fast(timeval);
203  }
204  constexpr int64_t quarter[12]{1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 1, 1};
205  int64_t const day = floor_div(timeval, kSecsPerDay);
206  unsigned const doe = unsigned_mod(day - kEpochAdjustedDays, kDaysPer400Years);
207  unsigned const yoe = (doe - doe / 1460 + doe / 36524 - (doe == 146096)) / 365;
208  unsigned const doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
209  unsigned const moy = (5 * doy + 2) / 153;
210  return quarter[moy];
211 }
212 
213 extern "C" ALWAYS_INLINE DEVICE int64_t extract_year(const int64_t timeval) {
214  if (timeval >= 0L && timeval <= UINT32_MAX - kEpochOffsetYear1900) {
215  return extract_year_fast(timeval);
216  }
217  int64_t const day = floor_div(timeval, kSecsPerDay);
218  int64_t const era = floor_div(day - kEpochAdjustedDays, kDaysPer400Years);
219  unsigned const doe = day - kEpochAdjustedDays - era * kDaysPer400Years;
220  unsigned const yoe = (doe - doe / 1460 + doe / 36524 - (doe == 146096)) / 365;
221  unsigned const doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
222  return 2000 + era * 400 + yoe + (MARJAN <= doy);
223 }
224 
225 /*
226  * @brief support the SQL EXTRACT function
227  */
228 DEVICE int64_t ExtractFromTime(ExtractField field, const int64_t timeval) {
229  switch (field) {
230  case kEPOCH:
231  return extract_epoch(timeval);
232  case kDATEEPOCH:
233  return extract_dateepoch(timeval);
234  case kQUARTERDAY:
235  return extract_quarterday(timeval);
236  case kHOUR:
237  return extract_hour(timeval);
238  case kMINUTE:
239  return extract_minute(timeval);
240  case kSECOND:
241  return extract_second(timeval);
242  case kMILLISECOND:
243  return extract_millisecond(timeval);
244  case kMICROSECOND:
245  return extract_microsecond(timeval);
246  case kNANOSECOND:
247  return extract_nanosecond(timeval);
248  case kDOW:
249  return extract_dow(timeval);
250  case kISODOW:
251  return extract_isodow(timeval);
252  case kDAY:
253  return extract_day(timeval);
254  case kWEEK:
255  return extract_week(timeval);
256  case kDOY:
257  return extract_day_of_year(timeval);
258  case kMONTH:
259  return extract_month(timeval);
260  case kQUARTER:
261  return extract_quarter(timeval);
262  case kYEAR:
263  return extract_year(timeval);
264  }
265 
266 #ifdef __CUDACC__
267  return -1;
268 #else
269  abort();
270 #endif
271 }
static constexpr int64_t kSecsPerDay
static constexpr uint32_t kSecsJanToMar1900
static constexpr uint32_t kUSecsPerDay
ALWAYS_INLINE DEVICE int64_t extract_second(const int64_t lcltime)
ALWAYS_INLINE DEVICE int64_t extract_nanosecond(const int64_t lcltime)
DEVICE int32_t extract_quarter_fast(const int64_t lcltime)
static constexpr int64_t kSecsPerHour
static constexpr int64_t kSecsPerMin
static constexpr int64_t kNanoSecsPerSec
ALWAYS_INLINE DEVICE int64_t extract_month(const int64_t timeval)
constexpr unsigned JANMAR
ALWAYS_INLINE DEVICE int64_t extract_isodow(const int64_t timeval)
static constexpr int64_t kSecsPerQuarterDay
ALWAYS_INLINE DEVICE int64_t extract_day_of_year(const int64_t timeval)
#define STATIC_QUAL
ALWAYS_INLINE DEVICE int64_t extract_minute(const int64_t lcltime)
DEVICE int64_t floor_div(int64_t const dividend, int64_t const divisor)
ALWAYS_INLINE DEVICE int64_t extract_quarterday(const int64_t lcltime)
ALWAYS_INLINE DEVICE int64_t extract_quarter(const int64_t timeval)
ALWAYS_INLINE DEVICE int64_t extract_dow(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
ALWAYS_INLINE DEVICE int64_t extract_dateepoch(const int64_t timeval)
ALWAYS_INLINE DEVICE int64_t extract_year(const int64_t timeval)
static constexpr int32_t kEpochAdjustedDays
ALWAYS_INLINE DEVICE int64_t extract_microsecond(const int64_t lcltime)
ALWAYS_INLINE DEVICE int64_t extract_hour(const int64_t lcltime)
static constexpr int32_t kDaysPerWeek
static constexpr uint32_t kSecondsPer4YearCycle
ALWAYS_INLINE DEVICE int64_t extract_epoch(const int64_t timeval)
static constexpr int64_t kDaysPer400Years
ALWAYS_INLINE DEVICE int64_t extract_millisecond(const int64_t lcltime)
constexpr unsigned MARJAN
DEVICE int64_t unsigned_mod(int64_t const dividend, int64_t const divisor)
DEVICE int64_t ExtractFromTime(ExtractField field, const int64_t timeval)
ExtractField
DEVICE int32_t extract_month_fast(const int64_t lcltime)
ALWAYS_INLINE DEVICE int64_t extract_day(const int64_t timeval)
static constexpr uint32_t kSecondsPerNonLeapYear
#define ALWAYS_INLINE
static constexpr int64_t kMicroSecsPerSec
static constexpr int32_t kMonsPerYear
DEVICE unsigned iso_week_start_from_yoe(unsigned const yoe)
DEVICE int32_t extract_year_fast(const int64_t lcltime)
ALWAYS_INLINE DEVICE int64_t extract_week(const int64_t timeval)