OmniSciDB  b24e664e58
 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 #include "ExtractFromTime.h"
18 #include "../Shared/funcannotations.h"
19 
20 #ifndef __CUDACC__
21 #include <cstdlib> // abort()
22 #endif
23 
24 extern "C" NEVER_INLINE DEVICE int32_t extract_hour(const int64_t lcltime) {
25  int64_t days, rem;
26  days = lcltime / kSecsPerDay - kEpochAdjustedDays;
27  rem = lcltime % kSecsPerDay;
28  if (rem < 0) {
29  rem += kSecsPerDay;
30  --days;
31  }
32  return static_cast<int32_t>(rem / kSecPerHour);
33 }
34 
35 DEVICE int32_t extract_minute(const int64_t lcltime) {
36  int64_t days, rem;
37  days = lcltime / kSecsPerDay - kEpochAdjustedDays;
38  rem = lcltime % kSecsPerDay;
39  if (rem < 0) {
40  rem += kSecsPerDay;
41  --days;
42  }
43  rem %= kSecPerHour;
44  return static_cast<int32_t>(rem / kSecsPerMin);
45 }
46 
47 DEVICE int32_t extract_second(const int64_t lcltime) {
48  return static_cast<int32_t>(lcltime % kSecsPerMin);
49 }
50 
51 DEVICE int64_t extract_millisecond(const int64_t lcltime) {
52  return lcltime % (kSecsPerMin * kMilliSecsPerSec);
53 }
54 
55 DEVICE int64_t extract_microsecond(const int64_t lcltime) {
56  return lcltime % (kSecsPerMin * kMicroSecsPerSec);
57 }
58 
59 DEVICE int64_t extract_nanosecond(const int64_t lcltime) {
60  return lcltime % (kSecsPerMin * kNanoSecsPerSec);
61 }
62 
63 DEVICE int32_t extract_dow(const int64_t lcltime) {
64  int64_t days, rem;
65  int32_t weekday;
66  days = lcltime / kSecsPerDay - kEpochAdjustedDays;
67  rem = lcltime % kSecsPerDay;
68  if (rem < 0) {
69  rem += kSecsPerDay;
70  --days;
71  }
72 
73  if ((weekday = ((kEpochAdjustedWDay + days) % kDaysPerWeek)) < 0) {
74  weekday += kDaysPerWeek;
75  }
76  return weekday;
77 }
78 
79 DEVICE int32_t extract_quarterday(const int64_t lcltime) {
80  int64_t quarterdays;
81  quarterdays = lcltime / kSecsPerQuarterDay;
82  return static_cast<int32_t>(quarterdays % 4) + 1;
83 }
84 
85 DEVICE int32_t extract_month_fast(const int64_t lcltime) {
86  STATIC_QUAL const uint32_t cumulative_month_epoch_starts[kMonsPerYear] = {0,
87  2678400,
88  5270400,
89  7948800,
90  10540800,
91  13219200,
92  15897600,
93  18489600,
94  21168000,
95  23760000,
96  26438400,
97  29116800};
98  uint32_t seconds_march_1900 = lcltime + kEpochOffsetYear1900 - kSecsJanToMar1900;
99  uint32_t seconds_past_4year_period = seconds_march_1900 % kSecondsPer4YearCycle;
100  uint32_t year_seconds_past_4year_period =
101  (seconds_past_4year_period / kSecondsPerNonLeapYear) * kSecondsPerNonLeapYear;
102  if (seconds_past_4year_period >=
103  kSecondsPer4YearCycle - kUSecsPerDay) { // if we are in Feb 29th
104  year_seconds_past_4year_period -= kSecondsPerNonLeapYear;
105  }
106  uint32_t seconds_past_march =
107  seconds_past_4year_period - year_seconds_past_4year_period;
108  uint32_t month =
109  seconds_past_march / (30 * kUSecsPerDay); // Will make the correct month either be
110  // the guessed month or month before
111  month = month <= 11 ? month : 11;
112  if (cumulative_month_epoch_starts[month] > seconds_past_march) {
113  month--;
114  }
115  return (month + 2) % 12 + 1;
116 }
117 
118 DEVICE int32_t extract_quarter_fast(const int64_t lcltime) {
119  STATIC_QUAL const uint32_t cumulative_quarter_epoch_starts[4] = {
120  0, 7776000, 15638400, 23587200};
121  STATIC_QUAL const uint32_t cumulative_quarter_epoch_starts_leap_year[4] = {
122  0, 7862400, 15724800, 23673600};
123  uint32_t seconds_1900 = lcltime + kEpochOffsetYear1900;
124  uint32_t leap_years = (seconds_1900 - kSecsJanToMar1900) / kSecondsPer4YearCycle;
125  uint32_t year = (seconds_1900 - leap_years * kSecsPerDay) / kSecondsPerNonLeapYear;
126  uint32_t base_year_leap_years = (year - 1) / 4;
127  uint32_t base_year_seconds =
128  year * kSecondsPerNonLeapYear + base_year_leap_years * kUSecsPerDay;
129  bool is_leap_year = year % 4 == 0 && year != 0;
130  const uint32_t* quarter_offsets = is_leap_year
131  ? cumulative_quarter_epoch_starts_leap_year
132  : cumulative_quarter_epoch_starts;
133  uint32_t partial_year_seconds = seconds_1900 % base_year_seconds;
134  uint32_t quarter = partial_year_seconds / (90 * kUSecsPerDay);
135  quarter = quarter <= 3 ? quarter : 3;
136  if (quarter_offsets[quarter] > partial_year_seconds) {
137  quarter--;
138  }
139  return quarter + 1;
140 }
141 
142 DEVICE int32_t extract_year_fast(const int64_t lcltime) {
143  const uint32_t seconds_1900 = lcltime + kEpochOffsetYear1900;
144  const uint32_t leap_years = (seconds_1900 - kSecsJanToMar1900) / kSecondsPer4YearCycle;
145  const uint32_t year =
146  (seconds_1900 - leap_years * kUSecsPerDay) / kSecondsPerNonLeapYear + 1900;
147  return year;
148 }
149 
150 DEVICE tm gmtime_r_newlib(const int64_t lcltime, tm& res) {
151  const int32_t month_lengths[2][kMonsPerYear] = {
152  {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
153  {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
154  int64_t days, rem;
155  int32_t year, month, yearday, weekday;
156  int32_t years400, years100, years4, remainingyears;
157  int32_t yearleap;
158  const int32_t* ip;
159 
160  days = lcltime / kSecsPerDay - kEpochAdjustedDays;
161  rem = lcltime % kSecsPerDay;
162  if (rem < 0) {
163  rem += kSecsPerDay;
164  --days;
165  }
166 
167  /* compute hour, min, and sec */
168  res.tm_hour = static_cast<int32_t>(rem / kSecPerHour);
169  rem %= kSecPerHour;
170  res.tm_min = static_cast<int32_t>(rem / kSecsPerMin);
171  res.tm_sec = static_cast<int32_t>(rem % kSecsPerMin);
172 
173  /* compute day of week */
174  if ((weekday = ((kEpochAdjustedWDay + days) % kDaysPerWeek)) < 0) {
175  weekday += kDaysPerWeek;
176  }
177  res.tm_wday = weekday;
178 
179  /* compute year & day of year */
180  years400 = static_cast<int32_t>(days / kDaysPer400Years);
181  days -= years400 * kDaysPer400Years;
182  /* simplify by making the values positive */
183  if (days < 0) {
184  days += kDaysPer400Years;
185  --years400;
186  }
187 
188  years100 = static_cast<int32_t>(days / kDaysPer100Years);
189  if (years100 == 4) { /* required for proper day of year calculation */
190  --years100;
191  }
192  days -= years100 * kDaysPer100Years;
193  years4 = days / kDaysPer4Years;
194  days -= years4 * kDaysPer4Years;
195  remainingyears = days / kDaysPerYear;
196  if (remainingyears == 4) { /* required for proper day of year calculation */
197  --remainingyears;
198  }
199  days -= remainingyears * kDaysPerYear;
200 
201  year =
202  kEpochAdjustedYears + years400 * 400 + years100 * 100 + years4 * 4 + remainingyears;
203 
204  /* If remainingyears is zero, it means that the years were completely
205  * "consumed" by modulo calculations by 400, 100 and 4, so the year is:
206  * 1. a multiple of 4, but not a multiple of 100 or 400 - it's a leap year,
207  * 2. a multiple of 4 and 100, but not a multiple of 400 - it's not a leap
208  * year,
209  * 3. a multiple of 4, 100 and 400 - it's a leap year.
210  * If years4 is non-zero, it means that the year is not a multiple of 100 or
211  * 400 (case 1), so it's a leap year. If years100 is zero (and years4 is zero
212  * - due to short-circuiting), it means that the year is a multiple of 400
213  * (case 3), so it's also a leap year. */
214  yearleap = remainingyears == 0 && (years4 != 0 || years100 == 0);
215 
216  /* adjust back to 1st January */
217  yearday = days + kDaysInJanuary + kDaysInFebruary + yearleap;
218  if (yearday >= kDaysPerYear + yearleap) {
219  yearday -= kDaysPerYear + yearleap;
220  ++year;
221  }
222  res.tm_yday = yearday;
223  res.tm_year = year - kYearBase;
224 
225  /* Because "days" is the number of days since 1st March, the additional leap
226  * day (29th of February) is the last possible day, so it doesn't matter much
227  * whether the year is actually leap or not. */
228  ip = month_lengths[1];
229  month = 2;
230  while (days >= ip[month]) {
231  days -= ip[month];
232  if (++month >= kMonsPerYear) {
233  month = 0;
234  }
235  }
236  res.tm_mon = month;
237  res.tm_mday = days + 1;
238 
239  res.tm_isdst = 0;
240 
241  return res;
242 }
243 
244 /*
245  * @brief support the SQL EXTRACT function
246  */
248  const int64_t timeval) {
249  // We have fast paths for the 5 fields below - do not need to do full gmtime
250  switch (field) {
251  case kEPOCH:
252  return timeval;
253  case kQUARTERDAY:
254  return extract_quarterday(timeval);
255  case kHOUR:
256  return extract_hour(timeval);
257  case kMINUTE:
258  return extract_minute(timeval);
259  case kSECOND:
260  return extract_second(timeval);
261  case kMILLISECOND:
262  return extract_millisecond(timeval);
263  case kMICROSECOND:
264  return extract_microsecond(timeval);
265  case kNANOSECOND:
266  return extract_nanosecond(timeval);
267  case kDOW:
268  return extract_dow(timeval);
269  case kISODOW: {
270  int64_t dow = extract_dow(timeval);
271  return (dow == 0 ? 7 : dow);
272  }
273  case kMONTH: {
274  if (timeval >= 0L && timeval <= UINT32_MAX - kEpochOffsetYear1900) {
275  return extract_month_fast(timeval);
276  }
277  break;
278  }
279  case kQUARTER: {
280  if (timeval >= 0L && timeval <= UINT32_MAX - kEpochOffsetYear1900) {
281  return extract_quarter_fast(timeval);
282  }
283  break;
284  }
285  case kYEAR: {
286  if (timeval >= 0L && timeval <= UINT32_MAX - kEpochOffsetYear1900) {
287  return extract_year_fast(timeval);
288  }
289  break;
290  }
291  default:
292  break;
293  }
294 
295  tm tm_struct;
296  gmtime_r_newlib(timeval, tm_struct);
297  switch (field) {
298  case kYEAR:
299  return 1900 + tm_struct.tm_year;
300  case kQUARTER:
301  return (tm_struct.tm_mon) / 3 + 1;
302  case kMONTH:
303  return tm_struct.tm_mon + 1;
304  case kDAY:
305  return tm_struct.tm_mday;
306  case kDOY:
307  return tm_struct.tm_yday + 1;
308  case kWEEK: {
309  int32_t doy = tm_struct.tm_yday; // numbered from 0
310  int32_t dow = extract_dow(timeval) + 1; // use Sunday 1 - Saturday 7
311  int32_t week = (doy / 7) + 1;
312  // now adjust for offset at start of year
313  // S M T W T F S
314  // doy 0 1 2 3 4
315  // doy 5 6
316  // mod 5 6 0 1 2 3 4
317  // dow 1 2 3 4 5 6 7
318  // week 2 2 1 1 1 1 1
319  if (dow > (doy % 7)) {
320  return week;
321  }
322  return week + 1;
323  }
324  default:
325 #ifdef __CUDACC__
326  return -1;
327 #else
328  abort();
329 #endif
330  }
331 }
332 
334  const int64_t timeval,
335  const int64_t null_val) {
336  if (timeval == null_val) {
337  return null_val;
338  }
339  return ExtractFromTime(field, timeval);
340 }
static constexpr int64_t kSecsPerDay
static constexpr uint32_t kSecsJanToMar1900
static constexpr uint32_t kUSecsPerDay
NEVER_INLINE DEVICE int32_t extract_hour(const int64_t lcltime)
DEVICE int32_t extract_quarter_fast(const int64_t lcltime)
static constexpr int32_t kDaysPerYear
static constexpr int64_t kSecsPerMin
static constexpr int64_t kNanoSecsPerSec
DEVICE int64_t extract_nanosecond(const int64_t lcltime)
static constexpr int64_t kSecsPerQuarterDay
#define STATIC_QUAL
static constexpr int32_t kDaysInJanuary
static constexpr uint32_t kEpochOffsetYear1900
static constexpr int32_t kYearBase
#define DEVICE
static constexpr int64_t kMilliSecsPerSec
const rapidjson::Value & field(const rapidjson::Value &obj, const char field[]) noexcept
Definition: JsonAccessors.h:31
DEVICE int32_t extract_dow(const int64_t lcltime)
DEVICE int32_t extract_second(const int64_t lcltime)
static constexpr int32_t kEpochAdjustedDays
DEVICE int64_t extract_millisecond(const int64_t lcltime)
DEVICE int64_t ExtractFromTimeNullable(ExtractField field, const int64_t timeval, const int64_t null_val)
DEVICE tm gmtime_r_newlib(const int64_t lcltime, tm &res)
NEVER_INLINE DEVICE int64_t ExtractFromTime(ExtractField field, const int64_t timeval)
DEVICE int32_t extract_quarterday(const int64_t lcltime)
static constexpr int32_t kDaysPerWeek
static constexpr int32_t kDaysInFebruary
DEVICE int32_t extract_minute(const int64_t lcltime)
static constexpr int32_t kEpochAdjustedYears
static constexpr uint32_t kSecondsPer4YearCycle
static constexpr int64_t kDaysPer400Years
static constexpr int64_t kSecPerHour
ExtractField
DEVICE int32_t extract_month_fast(const int64_t lcltime)
#define NEVER_INLINE
static constexpr int32_t kDaysPer4Years
DEVICE int64_t extract_microsecond(const int64_t lcltime)
static constexpr uint32_t kSecondsPerNonLeapYear
static constexpr int64_t kMicroSecsPerSec
static constexpr int32_t kEpochAdjustedWDay
static constexpr int32_t kMonsPerYear
DEVICE int32_t extract_year_fast(const int64_t lcltime)
static constexpr int64_t kDaysPer100Years