OmniSciDB  1dac507f6e
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
DateAdd.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 "DateAdd.h"
18 #include "ExtractFromTime.h"
19 
20 #ifdef EXECUTE_INCLUDE
21 
22 #ifndef __CUDACC__
23 #include <cstdlib> // abort()
24 #endif
25 
26 DEVICE
27 int32_t is_leap(int64_t year) {
28  return (((year % 400) == 0) || ((year % 4) == 0 && ((year % 100) != 0))) ? 1 : 0;
29 }
30 
31 DEVICE
32 int64_t skip_months(int64_t timeval, int64_t months_to_go) {
33  const int32_t month_lengths[2][kMonsPerYear] = {
34  {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
35  {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
36  tm tm_struct;
37  gmtime_r_newlib(timeval, tm_struct);
38  auto tod = timeval % kSecsPerDay;
39  auto day = (timeval / kSecsPerDay) * kSecsPerDay;
40  // calculate the day of month offset
41  int32_t dom = tm_struct.tm_mday;
42  int64_t month = day - (dom * kSecsPerDay);
43  // find what month we are
44  int32_t mon = tm_struct.tm_mon;
45  int64_t months_covered = 0;
46  while (months_to_go != 0) {
47  int32_t leap_year = 0;
48  if (months_to_go >= 48) {
49  month += (months_to_go / 48) * kDaysPer4Years * kSecsPerDay;
50  months_to_go = months_to_go % 48;
51  months_covered += 48 * (months_to_go / 48);
52  continue;
53  }
54  if (months_to_go > 0) {
55  auto m = (mon + months_covered) % kMonsPerYear;
56  if (m == 1) {
57  leap_year = is_leap(ExtractFromTime(kYEAR, month));
58  }
59  month += (month_lengths[0 + leap_year][m] * kSecsPerDay);
60  months_to_go--;
61  months_covered++;
62  continue;
63  }
64  if (months_to_go <= -48) {
65  month -= ((-months_to_go) / 48) * kDaysPer4Years * kSecsPerDay;
66  months_to_go = -((-months_to_go) % 48);
67  months_covered += 48 * ((-months_to_go) / 48);
68  continue;
69  }
70  if (months_to_go < 0) {
71  auto m =
72  (((mon - 1 - months_covered) % kMonsPerYear) + kMonsPerYear) % kMonsPerYear;
73  if (m == 1) {
74  leap_year = is_leap(ExtractFromTime(kYEAR, month));
75  }
76  month -= (month_lengths[0 + leap_year][m] * kSecsPerDay);
77  months_to_go++;
78  months_covered++;
79  }
80  }
81 
82  int64_t new_timeval = month + dom * kSecsPerDay + tod;
83  tm new_tm_struct;
84  gmtime_r_newlib(new_timeval, new_tm_struct);
85  int32_t new_dom = new_tm_struct.tm_mday;
86  if (dom > new_dom) {
87  // Landed on a month with fewer days, overshot by a few days,
88  // e.g. 2008-1-31 + INTERVAL '1' MONTH should yield 2008-2-29 and
89  // e.g. 2009-1-31 + INTERVAL '1' MONTH should yield 2008-2-28
90  // Go to the last day of preceeding month
91  new_timeval -= new_dom * kSecsPerDay;
92  }
93  return new_timeval;
94 }
95 
96 extern "C" NEVER_INLINE DEVICE int64_t DateAdd(DateaddField field,
97  const int64_t number,
98  const int64_t timeval) {
99  switch (field) {
100  case daNANOSECOND:
101  case daMICROSECOND:
102  case daMILLISECOND:
103  case daSECOND:
104  /* this is the limit of current granularity */
105  return timeval + number;
106  case daMINUTE:
107  return timeval + number * kSecsPerMin;
108  case daHOUR:
109  return timeval + number * kSecPerHour;
110  case daWEEKDAY:
111  case daDAYOFYEAR:
112  case daDAY:
113  return timeval + number * kSecsPerDay;
114  case daWEEK:
115  return timeval + number * kDaysPerWeek * kSecsPerDay;
116  default:
117  break;
118  }
119 
120  int64_t months_to_go;
121  switch (field) {
122  case daMONTH:
123  months_to_go = 1;
124  break;
125  case daQUARTER:
126  months_to_go = 3;
127  break;
128  case daYEAR:
129  months_to_go = 12;
130  break;
131  case daDECADE:
132  months_to_go = 10 * 12;
133  break;
134  case daCENTURY:
135  months_to_go = 100 * 12;
136  break;
137  case daMILLENNIUM:
138  months_to_go = 1000 * 12;
139  break;
140  default:
141 #ifdef __CUDACC__
142  return -1;
143 #else
144  abort();
145 #endif
146  }
147  months_to_go *= number;
148  return skip_months(timeval, months_to_go);
149 }
150 
151 extern "C" NEVER_INLINE DEVICE int64_t DateAddHighPrecision(DateaddField field,
152  const int64_t number,
153  const int64_t timeval,
154  const int64_t scale) {
155  switch (field) {
156  case daNANOSECOND:
157  case daMICROSECOND:
158  case daMILLISECOND:
159  /* Since number is constant, it is being adjusted according to the dimension
160  of type and field in RelAlgTranslator. Therefore, here would skip math and
161  just add the value.*/
162  return timeval + number;
163  default:
164  break;
165  }
166  return (DateAdd(field, number, timeval / scale) * scale) + (timeval % scale);
167 }
168 
169 extern "C" DEVICE int64_t DateAddNullable(const DateaddField field,
170  const int64_t number,
171  const int64_t timeval,
172  const int64_t null_val) {
173  if (timeval == null_val) {
174  return null_val;
175  }
176  return DateAdd(field, number, timeval);
177 }
178 
179 extern "C" DEVICE int64_t DateAddHighPrecisionNullable(const DateaddField field,
180  const int64_t number,
181  const int64_t timeval,
182  const int64_t scale,
183  const int64_t null_val) {
184  if (timeval == null_val) {
185  return null_val;
186  }
187  return DateAddHighPrecision(field, number, timeval, scale);
188 }
189 
190 #endif // EXECUTE_INCLUDE
static constexpr int64_t kSecsPerDay
static constexpr int64_t kSecsPerMin
NEVER_INLINE DEVICE int64_t DateAddHighPrecision(DateaddField field, const int64_t number, const int64_t timeval, const int64_t scale)
Definition: DateAdd.h:47
#define DEVICE
const rapidjson::Value & field(const rapidjson::Value &obj, const char field[]) noexcept
Definition: JsonAccessors.h:31
Definition: DateAdd.h:43
DateaddField
Definition: DateAdd.h:42
DEVICE tm gmtime_r_newlib(const int64_t lcltime, tm &res)
Definition: DateAdd.h:56
NEVER_INLINE DEVICE int64_t ExtractFromTime(ExtractField field, const int64_t timeval)
static constexpr int32_t kDaysPerWeek
static constexpr int64_t kSecPerHour
NEVER_INLINE DEVICE int64_t DateAdd(DateaddField field, int64_t number, int64_t timeval)
#define NEVER_INLINE
static constexpr int32_t kDaysPer4Years
Definition: DateAdd.h:46
static constexpr int32_t kMonsPerYear