OmniSciDB  2c44a3935d
DateTruncate.cpp File Reference
#include "DateTruncate.h"
#include "ExtractFromTime.h"
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <iostream>
+ Include dependency graph for DateTruncate.cpp:

Go to the source code of this file.

Functions

DEVICE int64_t create_epoch (int32_t year)
 
NEVER_INLINE DEVICE int64_t DateTruncate (DatetruncField field, const int64_t timeval)
 
DEVICE int64_t DateTruncateNullable (DatetruncField field, const int64_t timeval, const int64_t null_val)
 
DEVICE int64_t DateTruncateHighPrecisionToDate (const int64_t timeval, const int64_t scale)
 
DEVICE int64_t DateTruncateHighPrecisionToDateNullable (const int64_t timeval, const int64_t scale, const int64_t null_val)
 
DEVICE int64_t DateDiff (const DatetruncField datepart, const int64_t startdate, const int64_t enddate)
 
DEVICE int64_t DateDiffHighPrecision (const DatetruncField datepart, const int64_t startdate, const int64_t enddate, const int32_t adj_dimen, const int64_t adj_scale, const int64_t sml_scale, const int64_t scale)
 
DEVICE int64_t DateDiffNullable (const DatetruncField datepart, const int64_t startdate, const int64_t enddate, const int64_t null_val)
 
DEVICE int64_t DateDiffHighPrecisionNullable (const DatetruncField datepart, const int64_t startdate, const int64_t enddate, const int32_t adj_dimen, const int64_t adj_scale, const int64_t sml_scale, const int64_t scale, const int64_t null_val)
 

Function Documentation

◆ create_epoch()

DEVICE int64_t create_epoch ( int32_t  year)

Definition at line 28 of file DateTruncate.cpp.

References kDaysInFebruary, kDaysInJanuary, kDaysPer100Years, kDaysPer400Years, kDaysPer4Years, kDaysPerYear, kEpochAdjustedDays, kEpochAdjustedYears, and kSecsPerDay.

Referenced by DateTruncate().

28  {
29  // Note this is not general purpose
30  // it has a final assumption that the year being passed can never be a leap
31  // year
32  // use 2001 epoch time 31 March as start
33 
34  int64_t new_time = kEpochAdjustedDays * kSecsPerDay;
35  bool forward = true;
36  int32_t years_offset = year - kEpochAdjustedYears;
37  // convert year_offset to positive
38  if (years_offset < 0) {
39  forward = false;
40  years_offset = -years_offset;
41  }
42  // now get number of 400 year cycles in the years_offset;
43 
44  int32_t year400 = years_offset / 400;
45  int32_t years_remaining = years_offset - (year400 * 400);
46  int32_t year100 = years_remaining / 100;
47  years_remaining -= year100 * 100;
48  int32_t year4 = years_remaining / 4;
49  years_remaining -= year4 * 4;
50 
51  // get new date I know the final year will never be a leap year
52  if (forward) {
53  new_time += (year400 * kDaysPer400Years + year100 * kDaysPer100Years +
54  year4 * kDaysPer4Years + years_remaining * kDaysPerYear -
56  kSecsPerDay;
57  } else {
58  new_time -= (year400 * kDaysPer400Years + year100 * kDaysPer100Years +
59  year4 * kDaysPer4Years + years_remaining * kDaysPerYear +
60  // one more day for leap year of 2000 when going backward;
62  kSecsPerDay;
63  };
64 
65  return new_time;
66 }
static constexpr int64_t kSecsPerDay
static constexpr int32_t kDaysPerYear
static constexpr int32_t kDaysInJanuary
static constexpr int32_t kEpochAdjustedDays
static constexpr int32_t kDaysInFebruary
static constexpr int32_t kEpochAdjustedYears
static constexpr int64_t kDaysPer400Years
static constexpr int32_t kDaysPer4Years
static constexpr int64_t kDaysPer100Years
+ Here is the caller graph for this function:

◆ DateDiff()

DEVICE int64_t DateDiff ( const DatetruncField  datepart,
const int64_t  startdate,
const int64_t  enddate 
)

Definition at line 334 of file DateTruncate.cpp.

References DateTruncate(), dtDAY, dtHOUR, dtMICROSECOND, dtMILLISECOND, dtMINUTE, dtNANOSECOND, dtQUARTERDAY, dtSECOND, dtWEEK, kDaysPerWeek, kMicroSecsPerSec, kMilliSecsPerSec, kNanoSecsPerSec, kSecPerHour, kSecsPerDay, kSecsPerMin, kSecsPerQuarterDay, and run_benchmark_import::res.

Referenced by DateDiffHighPrecision(), and DateDiffNullable().

336  {
337  int64_t res = enddate - startdate;
338  switch (datepart) {
339  case dtNANOSECOND:
340  return res * kNanoSecsPerSec;
341  case dtMICROSECOND:
342  return res * kMicroSecsPerSec;
343  case dtMILLISECOND:
344  return res * kMilliSecsPerSec;
345  case dtSECOND:
346  return res;
347  case dtMINUTE:
348  return res / kSecsPerMin;
349  case dtHOUR:
350  return res / kSecPerHour;
351  case dtQUARTERDAY:
352  return res / kSecsPerQuarterDay;
353  case dtDAY:
354  return res / kSecsPerDay;
355  case dtWEEK:
356  return res / (kSecsPerDay * kDaysPerWeek);
357  default:
358  break;
359  }
360 
361  auto future_date = (res > 0);
362  auto end = future_date ? enddate : startdate;
363  auto start = future_date ? startdate : enddate;
364  res = 0;
365  int64_t crt = end;
366  while (crt > start) {
367  const int64_t dt = DateTruncate(datepart, crt);
368  if (dt <= start) {
369  break;
370  }
371  ++res;
372  crt = dt - 1;
373  }
374  return future_date ? res : -res;
375 }
static constexpr int64_t kSecsPerDay
NEVER_INLINE DEVICE int64_t DateTruncate(DatetruncField field, const int64_t timeval)
static constexpr int64_t kSecsPerMin
static constexpr int64_t kNanoSecsPerSec
static constexpr int64_t kSecsPerQuarterDay
static constexpr int64_t kMilliSecsPerSec
static constexpr int32_t kDaysPerWeek
static constexpr int64_t kSecPerHour
static constexpr int64_t kMicroSecsPerSec
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ DateDiffHighPrecision()

DEVICE int64_t DateDiffHighPrecision ( const DatetruncField  datepart,
const int64_t  startdate,
const int64_t  enddate,
const int32_t  adj_dimen,
const int64_t  adj_scale,
const int64_t  sml_scale,
const int64_t  scale 
)

Definition at line 377 of file DateTruncate.cpp.

References DateDiff(), dtMICROSECOND, dtMILLISECOND, dtNANOSECOND, kMicroSecsPerSec, kMilliSecsPerSec, kNanoSecsPerSec, and run_benchmark_import::res.

Referenced by DateDiffHighPrecisionNullable().

383  {
384  /* TODO(wamsi): When adj_dimen is 1 i.e. both precisions are same,
385  this code is really not required. We cam direcly do enddate-startdate here.
386  Need to address this in refactoring focussed subsequent PR.*/
387  int64_t res = (adj_dimen > 0) ? (enddate - (startdate * adj_scale))
388  : ((enddate * adj_scale) - startdate);
389  switch (datepart) {
390  case dtNANOSECOND:
391  // limit of current granularity
392  return res;
393  case dtMICROSECOND: {
394  if (scale == kNanoSecsPerSec) {
395  return res / kMilliSecsPerSec;
396  } else {
397  { return res; }
398  }
399  }
400  case dtMILLISECOND: {
401  if (scale == kNanoSecsPerSec) {
402  return res / kMicroSecsPerSec;
403  } else if (scale == kMicroSecsPerSec) {
404  return res / kMilliSecsPerSec;
405  } else {
406  { return res; }
407  }
408  }
409  default:
410  break;
411  }
412  const int64_t nstartdate = adj_dimen > 0 ? startdate / sml_scale : startdate / scale;
413  const int64_t nenddate = adj_dimen < 0 ? enddate / sml_scale : enddate / scale;
414  return DateDiff(datepart, nstartdate, nenddate);
415 }
static constexpr int64_t kNanoSecsPerSec
static constexpr int64_t kMilliSecsPerSec
DEVICE int64_t DateDiff(const DatetruncField datepart, const int64_t startdate, const int64_t enddate)
static constexpr int64_t kMicroSecsPerSec
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ DateDiffHighPrecisionNullable()

DEVICE int64_t DateDiffHighPrecisionNullable ( const DatetruncField  datepart,
const int64_t  startdate,
const int64_t  enddate,
const int32_t  adj_dimen,
const int64_t  adj_scale,
const int64_t  sml_scale,
const int64_t  scale,
const int64_t  null_val 
)

Definition at line 427 of file DateTruncate.cpp.

References DateDiffHighPrecision().

434  {
435  if (startdate == null_val || enddate == null_val) {
436  return null_val;
437  }
438  return DateDiffHighPrecision(
439  datepart, startdate, enddate, adj_dimen, adj_scale, sml_scale, scale);
440 }
DEVICE int64_t DateDiffHighPrecision(const DatetruncField datepart, const int64_t startdate, const int64_t enddate, const int32_t adj_dimen, const int64_t adj_scale, const int64_t sml_scale, const int64_t scale)
+ Here is the call graph for this function:

◆ DateDiffNullable()

DEVICE int64_t DateDiffNullable ( const DatetruncField  datepart,
const int64_t  startdate,
const int64_t  enddate,
const int64_t  null_val 
)

Definition at line 417 of file DateTruncate.cpp.

References DateDiff().

420  {
421  if (startdate == null_val || enddate == null_val) {
422  return null_val;
423  }
424  return DateDiff(datepart, startdate, enddate);
425 }
DEVICE int64_t DateDiff(const DatetruncField datepart, const int64_t startdate, const int64_t enddate)
+ Here is the call graph for this function:

◆ DateTruncate()

NEVER_INLINE DEVICE int64_t DateTruncate ( DatetruncField  field,
const int64_t  timeval 
)

Definition at line 71 of file DateTruncate.cpp.

References create_epoch(), dtCENTURY, dtDAY, dtDECADE, dtHOUR, dtMICROSECOND, dtMILLENNIUM, dtMILLISECOND, dtMINUTE, dtMONTH, dtNANOSECOND, dtQUARTER, dtQUARTERDAY, dtSECOND, dtWEEK, dtYEAR, extract_dow(), gmtime_r_newlib(), kEpochOffsetYear1900, kMonsPerYear, kSecondsPer4YearCycle, kSecondsPerNonLeapYear, kSecPerHour, kSecsJanToMar1900, kSecsPerDay, kSecsPerMin, kSecsPerQuarterDay, kUSecsPerDay, kYearBase, and STATIC_QUAL.

Referenced by DateDiff(), DateTruncateNullable(), Analyzer::Constant::do_cast(), anonymous_namespace{ExpressionRange.cpp}::getDateTimePrecisionCastRange(), and DateTimeTranslator::getDateTruncConstantValue().

72  {
73  STATIC_QUAL const int32_t month_lengths[2][kMonsPerYear] = {
74  {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
75  {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
76 
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  STATIC_QUAL const uint32_t cumulative_quarter_epoch_starts[4] = {
90  0, 7776000, 15638400, 23587200};
91  STATIC_QUAL const uint32_t cumulative_quarter_epoch_starts_leap_year[4] = {
92  0, 7862400, 15724800, 23673600};
93  switch (field) {
94  case dtNANOSECOND:
95  case dtMICROSECOND:
96  case dtMILLISECOND:
97  case dtSECOND:
98  return timeval;
99  case dtMINUTE: {
100  int64_t ret = (timeval / kSecsPerMin) * kSecsPerMin;
101  if (timeval < 0 && timeval % kSecsPerMin) {
102  ret -= kSecsPerMin;
103  }
104  return ret;
105  }
106  case dtHOUR: {
107  int64_t ret = (timeval / kSecPerHour) * kSecPerHour;
108  if (timeval < 0 && timeval % kSecPerHour) {
109  ret -= kSecPerHour;
110  }
111  return ret;
112  }
113  case dtQUARTERDAY: {
114  int64_t ret = (timeval / kSecsPerQuarterDay) * kSecsPerQuarterDay;
115  if (timeval < 0 && timeval % kSecsPerQuarterDay) {
116  ret -= kSecsPerQuarterDay;
117  }
118  return ret;
119  }
120  case dtDAY: {
121  int64_t ret = (timeval / kSecsPerDay) * kSecsPerDay;
122  if (timeval < 0 && timeval % kSecsPerDay) {
123  ret -= kSecsPerDay;
124  }
125  return ret;
126  }
127  case dtWEEK: {
128  if (timeval >= 0L && timeval <= UINT32_MAX - (kEpochOffsetYear1900)) {
129  int64_t day = (timeval / kSecsPerDay) * kSecsPerDay;
130  if (timeval % kSecsPerDay) {
131  day -= kSecsPerDay;
132  }
133  int32_t dow = extract_dow(day);
134  return day - ((dow - 1) * kSecsPerDay);
135  }
136  break;
137  }
138  case dtMONTH: {
139  if (timeval >= 0L && timeval <= UINT32_MAX - (kEpochOffsetYear1900)) {
140  uint32_t seconds_march_1900 = timeval + kEpochOffsetYear1900 - kSecsJanToMar1900;
141  uint32_t seconds_past_4year_period = seconds_march_1900 % kSecondsPer4YearCycle;
142  uint32_t four_year_period_seconds =
143  (seconds_march_1900 / kSecondsPer4YearCycle) * kSecondsPer4YearCycle;
144  uint32_t year_seconds_past_4year_period =
145  (seconds_past_4year_period / kSecondsPerNonLeapYear) * kSecondsPerNonLeapYear;
146  if (seconds_past_4year_period >=
147  kSecondsPer4YearCycle - kUSecsPerDay) { // if we are in Feb 29th
148  year_seconds_past_4year_period -= kSecondsPerNonLeapYear;
149  }
150  uint32_t seconds_past_march =
151  seconds_past_4year_period - year_seconds_past_4year_period;
152  uint32_t month = seconds_past_march /
153  (30 * kUSecsPerDay); // Will make the correct month either be
154  // the guessed month or month before
155  month = month <= 11 ? month : 11;
156  if (cumulative_month_epoch_starts[month] > seconds_past_march) {
157  month--;
158  }
159  return (static_cast<int64_t>(four_year_period_seconds) +
160  year_seconds_past_4year_period + cumulative_month_epoch_starts[month] -
162  }
163  break;
164  }
165  case dtQUARTER: {
166  if (timeval >= 0L && timeval <= UINT32_MAX - kEpochOffsetYear1900) {
167  uint32_t seconds_1900 = timeval + kEpochOffsetYear1900;
168  uint32_t leap_years = (seconds_1900 - kSecsJanToMar1900) / kSecondsPer4YearCycle;
169  uint32_t year =
170  (seconds_1900 - leap_years * kUSecsPerDay) / kSecondsPerNonLeapYear;
171  uint32_t base_year_leap_years = (year - 1) / 4;
172  uint32_t base_year_seconds =
173  year * kSecondsPerNonLeapYear + base_year_leap_years * kUSecsPerDay;
174  const bool is_leap_year = year % 4 == 0 && year != 0;
175  const uint32_t* quarter_offsets = is_leap_year
176  ? cumulative_quarter_epoch_starts_leap_year
177  : cumulative_quarter_epoch_starts;
178  uint32_t partial_year_seconds = seconds_1900 % base_year_seconds;
179  uint32_t quarter = partial_year_seconds / (90 * kUSecsPerDay);
180  quarter = quarter <= 3 ? quarter : 3;
181  if (quarter_offsets[quarter] > partial_year_seconds) {
182  quarter--;
183  }
184  return (static_cast<int64_t>(base_year_seconds) + quarter_offsets[quarter] -
186  }
187  break;
188  }
189  case dtYEAR: {
190  if (timeval >= 0L && timeval <= UINT32_MAX - kEpochOffsetYear1900) {
191  uint32_t seconds_1900 = static_cast<uint32_t>(timeval) + kEpochOffsetYear1900;
192  uint32_t leap_years = (seconds_1900 - kSecsJanToMar1900) / kSecondsPer4YearCycle;
193  uint32_t year =
194  (seconds_1900 - leap_years * kUSecsPerDay) / kSecondsPerNonLeapYear;
195  uint32_t base_year_leap_years = (year - 1) / 4;
196  return (static_cast<int64_t>(year) * kSecondsPerNonLeapYear +
197  base_year_leap_years * kUSecsPerDay - kEpochOffsetYear1900);
198  }
199  break;
200  }
201  default:
202  break;
203  }
204 
205  // use ExtractFromTime functions where available
206  // have to do some extra work for these ones
207  tm tm_struct;
208  gmtime_r_newlib(timeval, tm_struct);
209  switch (field) {
210  case dtWEEK: {
211  // clear the time
212  int64_t day = (timeval / kSecsPerDay) * kSecsPerDay;
213  if (tm_struct.tm_hour >= 12) {
214  day -= kSecsPerDay;
215  }
216  // calculate the day of week
217  int32_t dow = tm_struct.tm_wday;
218  // offset to start of week
219  return day - (static_cast<int64_t>(dow - 1) * kSecsPerDay);
220  }
221  case dtMONTH: {
222  // clear the time
223  int64_t day = (timeval / kSecsPerDay) * kSecsPerDay;
224  if (tm_struct.tm_hour >= 12) {
225  day -= kSecsPerDay;
226  }
227  // calculate the day of month offset
228  int32_t dom = tm_struct.tm_mday;
229  return (day - (static_cast<int64_t>(dom - 1) * kSecsPerDay));
230  }
231  case dtQUARTER: {
232  // clear the time
233  int64_t day = (timeval / kSecsPerDay) * kSecsPerDay;
234  if (tm_struct.tm_hour >= 12) {
235  day -= kSecsPerDay;
236  }
237  // calculate the day of month offset
238  int32_t dom = tm_struct.tm_mday;
239  // go to the start of the current month
240  day = day - ((dom - 1) * kSecsPerDay);
241  // find what month we are
242  int32_t mon = tm_struct.tm_mon;
243  // find start of quarter
244  int32_t start_of_quarter = tm_struct.tm_mon / 3 * 3;
245  int32_t year = tm_struct.tm_year + kYearBase;
246  // are we in a leap year
247  int32_t leap_year = 0;
248  // only matters if month is March so save some mod operations
249  if (mon == 2) {
250  if (((year % 400) == 0) || ((year % 4) == 0 && ((year % 100) != 0))) {
251  leap_year = 1;
252  }
253  }
254  // now walk back until at correct quarter start
255  for (; mon > start_of_quarter; mon--) {
256  day = day - (month_lengths[0 + leap_year][mon - 1] * kSecsPerDay);
257  }
258  return day;
259  }
260  case dtYEAR: {
261  // clear the time
262  int64_t day = (timeval / kSecsPerDay) * kSecsPerDay;
263  if (tm_struct.tm_hour >= 12) {
264  day -= kSecsPerDay;
265  }
266  // calculate the day of year offset
267  int32_t doy = tm_struct.tm_yday;
268  return day - ((doy)*kSecsPerDay);
269  }
270  case dtDECADE: {
271  int32_t year = tm_struct.tm_year + kYearBase;
272  int32_t decade_start = (year / 10) * 10;
273  if (decade_start != 0 && decade_start % 4 == 0) {
274  auto prior_year_epoch = create_epoch(decade_start - 1);
275  return prior_year_epoch + kSecsPerDay * 365;
276  } else {
277  return create_epoch(decade_start);
278  }
279  }
280  case dtCENTURY: {
281  int32_t year = tm_struct.tm_year + kYearBase;
282  int32_t century_start = ((year - 1) / 100) * 100 + 1;
283  if (century_start != 0 && century_start % 4 == 0) {
284  auto prior_year_epoch = create_epoch(century_start - 1);
285  return prior_year_epoch + kSecsPerDay * 365;
286  } else {
287  return create_epoch(century_start);
288  }
289  }
290  case dtMILLENNIUM: {
291  int32_t year = tm_struct.tm_year + kYearBase;
292  int32_t millennium_start = ((year - 1) / 1000) * 1000 + 1;
293  if (millennium_start != 0 && millennium_start % 4 == 0) {
294  auto prior_year_epoch = create_epoch(millennium_start - 1);
295  return prior_year_epoch + kSecsPerDay * 365;
296  } else {
297  return create_epoch(millennium_start);
298  }
299  }
300  default:
301 #ifdef __CUDACC__
302  return -1;
303 #else
304  abort();
305 #endif
306  }
307 }
static constexpr int64_t kSecsPerDay
static constexpr uint32_t kSecsJanToMar1900
static constexpr uint32_t kUSecsPerDay
NEVER_INLINE DEVICE int64_t extract_dow(const int64_t lcltime)
static constexpr int64_t kSecsPerMin
static constexpr int64_t kSecsPerQuarterDay
#define STATIC_QUAL
static constexpr uint32_t kEpochOffsetYear1900
static constexpr int32_t kYearBase
const rapidjson::Value & field(const rapidjson::Value &obj, const char field[]) noexcept
Definition: JsonAccessors.h:31
DEVICE tm gmtime_r_newlib(const int64_t lcltime, tm &res)
static constexpr uint32_t kSecondsPer4YearCycle
static constexpr int64_t kSecPerHour
DEVICE int64_t create_epoch(int32_t year)
static constexpr uint32_t kSecondsPerNonLeapYear
static constexpr int32_t kMonsPerYear
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ DateTruncateHighPrecisionToDate()

DEVICE int64_t DateTruncateHighPrecisionToDate ( const int64_t  timeval,
const int64_t  scale 
)

Definition at line 318 of file DateTruncate.cpp.

References DEVICE, and kSecsPerDay.

Referenced by DateTruncateHighPrecisionToDateNullable(), and Analyzer::Constant::do_cast().

319  {
320  const int64_t retval = (timeval / (scale * kSecsPerDay)) * kSecsPerDay;
321  return retval < 0 ? retval - kSecsPerDay : retval;
322 }
static constexpr int64_t kSecsPerDay
+ Here is the caller graph for this function:

◆ DateTruncateHighPrecisionToDateNullable()

DEVICE int64_t DateTruncateHighPrecisionToDateNullable ( const int64_t  timeval,
const int64_t  scale,
const int64_t  null_val 
)

Definition at line 325 of file DateTruncate.cpp.

References DateTruncateHighPrecisionToDate().

327  {
328  if (timeval == null_val) {
329  return null_val;
330  }
331  return DateTruncateHighPrecisionToDate(timeval, scale);
332 }
DEVICE int64_t DateTruncateHighPrecisionToDate(const int64_t timeval, const int64_t scale)
+ Here is the call graph for this function:

◆ DateTruncateNullable()

DEVICE int64_t DateTruncateNullable ( DatetruncField  field,
const int64_t  timeval,
const int64_t  null_val 
)

Definition at line 309 of file DateTruncate.cpp.

References DateTruncate().

311  {
312  if (timeval == null_val) {
313  return null_val;
314  }
315  return DateTruncate(field, timeval);
316 }
NEVER_INLINE DEVICE int64_t DateTruncate(DatetruncField field, const int64_t timeval)
const rapidjson::Value & field(const rapidjson::Value &obj, const char field[]) noexcept
Definition: JsonAccessors.h:31
+ Here is the call graph for this function: