8
8
#include " duckdb/parser/parsed_data/create_scalar_function_info.hpp"
9
9
#include " duckdb/planner/expression/bound_function_expression.hpp"
10
10
#include " include/icu-datefunc.hpp"
11
+ #include " icu-helpers.hpp"
11
12
12
13
namespace duckdb {
13
14
14
15
struct ICUCalendarAdd {
15
16
template <class TA , class TB , class TR >
16
- static inline TR Operation (TA left, TB right, icu::Calendar *calendar ) {
17
+ static inline TR Operation (TA left, TB right, TZCalendar &calendar_p ) {
17
18
throw InternalException (" Unimplemented type for ICUCalendarAdd" );
18
19
}
19
20
};
20
21
21
22
struct ICUCalendarSub : public ICUDateFunc {
22
23
template <class TA , class TB , class TR >
23
- static inline TR Operation (TA left, TB right, icu::Calendar *calendar ) {
24
+ static inline TR Operation (TA left, TB right, TZCalendar &calendar_p ) {
24
25
throw InternalException (" Unimplemented type for ICUCalendarSub" );
25
26
}
26
27
};
27
28
28
29
struct ICUCalendarAge : public ICUDateFunc {
29
30
template <class TA , class TB , class TR >
30
- static inline TR Operation (TA left, TB right, icu::Calendar *calendar ) {
31
+ static inline TR Operation (TA left, TB right, TZCalendar &calendar_p ) {
31
32
throw InternalException (" Unimplemented type for ICUCalendarAge" );
32
33
}
33
34
};
@@ -53,10 +54,11 @@ static inline void CalendarAddHour(icu::Calendar *calendar, int64_t interval_hou
53
54
}
54
55
55
56
template <>
56
- timestamp_t ICUCalendarAdd::Operation (timestamp_t timestamp, interval_t interval, icu::Calendar *calendar ) {
57
+ timestamp_t ICUCalendarAdd::Operation (timestamp_t timestamp, interval_t interval, TZCalendar &calendar_p ) {
57
58
if (!Timestamp::IsFinite (timestamp)) {
58
59
return timestamp;
59
60
}
61
+ auto calendar = calendar_p.GetICUCalendar ();
60
62
61
63
int64_t millis = timestamp.value / Interval::MICROS_PER_MSEC;
62
64
int64_t micros = timestamp.value % Interval::MICROS_PER_MSEC;
@@ -120,25 +122,26 @@ timestamp_t ICUCalendarAdd::Operation(timestamp_t timestamp, interval_t interval
120
122
}
121
123
122
124
template <>
123
- timestamp_t ICUCalendarAdd::Operation (interval_t interval, timestamp_t timestamp, icu::Calendar * calendar) {
125
+ timestamp_t ICUCalendarAdd::Operation (interval_t interval, timestamp_t timestamp, TZCalendar & calendar) {
124
126
return Operation<timestamp_t , interval_t , timestamp_t >(timestamp, interval, calendar);
125
127
}
126
128
127
129
template <>
128
- timestamp_t ICUCalendarSub::Operation (timestamp_t timestamp, interval_t interval, icu::Calendar * calendar) {
130
+ timestamp_t ICUCalendarSub::Operation (timestamp_t timestamp, interval_t interval, TZCalendar & calendar) {
129
131
const interval_t negated {-interval.months , -interval.days , -interval.micros };
130
132
return ICUCalendarAdd::template Operation<timestamp_t , interval_t , timestamp_t >(timestamp, negated, calendar);
131
133
}
132
134
133
135
template <>
134
- interval_t ICUCalendarSub::Operation (timestamp_t end_date, timestamp_t start_date, icu::Calendar *calendar ) {
136
+ interval_t ICUCalendarSub::Operation (timestamp_t end_date, timestamp_t start_date, TZCalendar &calendar_p ) {
135
137
if (!Timestamp::IsFinite (end_date) || !Timestamp::IsFinite (start_date)) {
136
138
throw InvalidInputException (" Cannot subtract infinite timestamps" );
137
139
}
138
140
if (start_date > end_date) {
139
- auto negated = Operation<timestamp_t , timestamp_t , interval_t >(start_date, end_date, calendar );
141
+ auto negated = Operation<timestamp_t , timestamp_t , interval_t >(start_date, end_date, calendar_p );
140
142
return {-negated.months , -negated.days , -negated.micros };
141
143
}
144
+ auto calendar = calendar_p.GetICUCalendar ();
142
145
143
146
auto start_micros = ICUDateFunc::SetTime (calendar, start_date);
144
147
auto end_micros = (uint64_t )(end_date.value % Interval::MICROS_PER_MSEC);
@@ -166,9 +169,16 @@ interval_t ICUCalendarSub::Operation(timestamp_t end_date, timestamp_t start_dat
166
169
}
167
170
168
171
template <>
169
- interval_t ICUCalendarAge::Operation (timestamp_t end_date, timestamp_t start_date, icu::Calendar *calendar) {
172
+ interval_t ICUCalendarAge::Operation (timestamp_t end_date, timestamp_t start_date, TZCalendar &calendar_p) {
173
+ auto calendar = calendar_p.GetICUCalendar ();
174
+ if (calendar_p.IsGregorian ()) {
175
+ auto start_data = ICUHelpers::GetComponents (timestamp_tz_t (start_date.value ), calendar);
176
+ auto end_data = ICUHelpers::GetComponents (timestamp_tz_t (end_date.value ), calendar);
177
+ return Interval::GetAge (end_data, start_data, start_date > end_date);
178
+ }
179
+ // fallback for non-gregorian calendars, since Interval::GetAge does not handle
170
180
if (start_date > end_date) {
171
- auto negated = Operation<timestamp_t , timestamp_t , interval_t >(start_date, end_date, calendar );
181
+ auto negated = Operation<timestamp_t , timestamp_t , interval_t >(start_date, end_date, calendar_p );
172
182
return {-negated.months , -negated.days , -negated.micros };
173
183
}
174
184
@@ -205,13 +215,13 @@ struct ICUDateAdd : public ICUDateFunc {
205
215
206
216
auto &func_expr = state.expr .Cast <BoundFunctionExpression>();
207
217
auto &info = func_expr.bind_info ->Cast <BindData>();
208
- CalendarPtr calendar (info.calendar -> clone () );
218
+ TZCalendar calendar (* info.calendar , info. cal_setting );
209
219
210
220
// Subtract argument from current_date (at midnight)
211
- const auto end_date = CurrentMidnight (calendar.get (), state);
221
+ const auto end_date = CurrentMidnight (calendar.GetICUCalendar (), state);
212
222
213
223
UnaryExecutor::Execute<TA, TR>(args.data [0 ], result, args.size (), [&](TA start_date) {
214
- return OP::template Operation<timestamp_t , TA, TR>(end_date, start_date, calendar. get () );
224
+ return OP::template Operation<timestamp_t , TA, TR>(end_date, start_date, calendar);
215
225
});
216
226
}
217
227
@@ -227,10 +237,10 @@ struct ICUDateAdd : public ICUDateFunc {
227
237
228
238
auto &func_expr = state.expr .Cast <BoundFunctionExpression>();
229
239
auto &info = func_expr.bind_info ->Cast <BindData>();
230
- CalendarPtr calendar (info.calendar -> clone () );
240
+ TZCalendar calendar (* info.calendar , info. cal_setting );
231
241
232
242
BinaryExecutor::Execute<TA, TB, TR>(args.data [0 ], args.data [1 ], result, args.size (), [&](TA left, TB right) {
233
- return OP::template Operation<TA, TB, TR>(left, right, calendar. get () );
243
+ return OP::template Operation<TA, TB, TR>(left, right, calendar);
234
244
});
235
245
}
236
246
@@ -287,15 +297,15 @@ struct ICUDateAdd : public ICUDateFunc {
287
297
}
288
298
};
289
299
290
- timestamp_t ICUDateFunc::Add (icu::Calendar * calendar, timestamp_t timestamp, interval_t interval) {
300
+ timestamp_t ICUDateFunc::Add (TZCalendar & calendar, timestamp_t timestamp, interval_t interval) {
291
301
return ICUCalendarAdd::Operation<timestamp_t , interval_t , timestamp_t >(timestamp, interval, calendar);
292
302
}
293
303
294
- timestamp_t ICUDateFunc::Sub (icu::Calendar * calendar, timestamp_t timestamp, interval_t interval) {
304
+ timestamp_t ICUDateFunc::Sub (TZCalendar & calendar, timestamp_t timestamp, interval_t interval) {
295
305
return ICUCalendarSub::Operation<timestamp_t , interval_t , timestamp_t >(timestamp, interval, calendar);
296
306
}
297
307
298
- interval_t ICUDateFunc::Sub (icu::Calendar * calendar, timestamp_t end_date, timestamp_t start_date) {
308
+ interval_t ICUDateFunc::Sub (TZCalendar & calendar, timestamp_t end_date, timestamp_t start_date) {
299
309
return ICUCalendarSub::Operation<timestamp_t , timestamp_t , interval_t >(end_date, start_date, calendar);
300
310
}
301
311
0 commit comments