-
Notifications
You must be signed in to change notification settings - Fork 81
/
Copy pathTimeTransformHelper.h
201 lines (187 loc) · 8.11 KB
/
TimeTransformHelper.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#pragma once
#include <Interpreters/Context_fwd.h>
#include <Common/DateLUT.h>
#include <Common/IntervalKind.h>
namespace DB
{
namespace Streaming
{
template <typename DateOrTime, typename Divisor>
inline DateOrTime roundDown(DateOrTime x, Divisor divisor)
{
static_assert(std::is_integral_v<DateOrTime> && std::is_integral_v<Divisor>);
assert(divisor > 0);
if (likely(x >= 0))
return static_cast<DateOrTime>(x / divisor * divisor);
/// Integer division for negative numbers rounds them towards zero (up).
/// We will shift the number so it will be rounded towards -inf (down).
return static_cast<DateOrTime>((x + 1 - divisor) / divisor * divisor);
}
template <IntervalKind::Kind unit>
struct ToStartOfTransform;
#define TRANSFORM_DATE(INTERVAL_KIND) \
template <> \
struct ToStartOfTransform<IntervalKind::INTERVAL_KIND> \
{ \
static UInt32 execute(UInt32 time_sec, UInt64 delta, const DateLUTImpl & time_zone) \
{ \
auto days = time_zone.toStartOf##INTERVAL_KIND##Interval(time_zone.toDayNum(time_sec), delta); \
return static_cast<UInt32>(time_zone.fromDayNum(days)); \
} \
template <typename Timestamp> \
requires(std::is_same_v<Timestamp, Int64> || std::is_same_v<Timestamp, DateTime64>) \
static Timestamp execute(Timestamp t, UInt64 delta, const DateLUTImpl & time_zone, UInt32 scale) \
{ \
auto scale_multiplier = common::exp10_i64(static_cast<int>(scale)); \
auto days = time_zone.toStartOf##INTERVAL_KIND##Interval(time_zone.toDayNum(t / scale_multiplier), delta); \
return time_zone.fromDayNum(days) * scale_multiplier; \
} \
};
TRANSFORM_DATE(Year)
TRANSFORM_DATE(Quarter)
TRANSFORM_DATE(Month)
TRANSFORM_DATE(Week)
#undef TRANSFORM_DATE
template <>
struct ToStartOfTransform<IntervalKind::Day>
{
static UInt32 execute(UInt32 time_sec, UInt64 delta, const DateLUTImpl & time_zone)
{
return static_cast<UInt32>(time_zone.toStartOfDayInterval(time_zone.toDayNum(time_sec), delta));
}
template <typename Timestamp>
requires(std::is_same_v<Timestamp, Int64> || std::is_same_v<Timestamp, DateTime64>)
static Timestamp execute(Timestamp t, UInt64 delta, const DateLUTImpl & time_zone, UInt32 scale)
{
auto scale_multiplier = common::exp10_i64(static_cast<int>(scale));
return time_zone.toStartOfDayInterval(time_zone.toDayNum(t / scale_multiplier), delta) * scale_multiplier;
}
};
#define TRANSFORM_TIME(INTERVAL_KIND) \
template <> \
struct ToStartOfTransform<IntervalKind::INTERVAL_KIND> \
{ \
static UInt32 execute(UInt32 time_sec, UInt64 delta, const DateLUTImpl & time_zone) \
{ \
return time_zone.toStartOf##INTERVAL_KIND##Interval(time_sec, delta); \
} \
template <typename Timestamp> \
requires(std::is_same_v<Timestamp, Int64> || std::is_same_v<Timestamp, DateTime64>) \
static Timestamp execute(Timestamp t, UInt64 delta, const DateLUTImpl & time_zone, UInt32 scale) \
{ \
auto scale_multiplier = common::exp10_i64(static_cast<int>(scale)); \
return time_zone.toStartOf##INTERVAL_KIND##Interval(t / scale_multiplier, delta) * scale_multiplier; \
} \
};
TRANSFORM_TIME(Hour)
TRANSFORM_TIME(Minute)
TRANSFORM_TIME(Second)
#undef TRANSFORM_TIME
/// Subsceonds: assume an hour has integer intervals
#define TRANSFORM_TIME(INTERVAL_KIND, INTERVAL_SCALE) \
template <> \
struct ToStartOfTransform<IntervalKind::INTERVAL_KIND> \
{ \
static constexpr auto interval_scale_multiplier = common::exp10_i64(INTERVAL_SCALE); \
static UInt32 execute(UInt32 t, UInt64 delta, const DateLUTImpl & time_zone) \
{ \
if (likely(interval_scale_multiplier % delta == 0)) \
return t; \
\
Int64 start_of_hour = time_zone.toStartOfHour(t); \
auto start_interval_of_hour = roundDown((t - start_of_hour) * interval_scale_multiplier, delta) / interval_scale_multiplier; \
return static_cast<UInt32>(start_of_hour + start_interval_of_hour); \
} \
template <typename Timestamp> \
requires(std::is_same_v<Timestamp, Int64> || std::is_same_v<Timestamp, DateTime64>) \
static Timestamp execute(Timestamp t, UInt64 delta, const DateLUTImpl & time_zone, UInt32 scale) \
{ \
if (likely(interval_scale_multiplier % delta == 0)) \
{ \
if (likely(scale >= INTERVAL_SCALE)) \
return roundDown(static_cast<Int64>(t), delta * common::exp10_i64(scale - INTERVAL_SCALE)); \
\
auto multiplier = common::exp10_i64(INTERVAL_SCALE - scale); \
return roundDown(t * multiplier, delta) / multiplier; \
} \
\
Int64 start_of_hour = time_zone.toStartOfHour(t / interval_scale_multiplier) * interval_scale_multiplier; \
if (likely(scale >= INTERVAL_SCALE)) \
return start_of_hour + roundDown(t - start_of_hour, delta * common::exp10_i64(scale - INTERVAL_SCALE)); \
\
auto multiplier = common::exp10_i64(INTERVAL_SCALE - scale); \
return start_of_hour + roundDown((t - start_of_hour) * multiplier, delta) / multiplier; \
} \
};
TRANSFORM_TIME(Millisecond, 3)
TRANSFORM_TIME(Microsecond, 6)
TRANSFORM_TIME(Nanosecond, 9)
#undef TRANSFORM_TIME
template <IntervalKind::Kind unit>
struct AddTime;
#define ADD_DATE(INTERVAL_KIND) \
template <> \
struct AddTime<IntervalKind::INTERVAL_KIND> \
{ \
static inline UInt32 execute(UInt32 time_sec, Int64 delta, const DateLUTImpl & time_zone) \
{ \
return static_cast<UInt32>(time_zone.add##INTERVAL_KIND##s(time_sec, delta)); \
} \
template <typename Timestamp> \
requires(std::is_same_v<Timestamp, Int64> || std::is_same_v<Timestamp, DateTime64>) \
static inline Timestamp execute(Timestamp t, Int64 delta, const DateLUTImpl & time_zone, UInt32 scale) \
{ \
auto scale_multiplier = common::exp10_i64(static_cast<int>(scale)); \
return time_zone.add##INTERVAL_KIND##s(t / scale_multiplier, delta) * scale_multiplier + (t % scale_multiplier); \
} \
};
ADD_DATE(Year)
ADD_DATE(Quarter)
ADD_DATE(Month)
ADD_DATE(Week)
ADD_DATE(Day)
#undef ADD_DATE
#define ADD_TIME(INTERVAL_KIND, INTERVAL) \
template <> \
struct AddTime<IntervalKind::INTERVAL_KIND> \
{ \
static inline NO_SANITIZE_UNDEFINED UInt32 execute(UInt32 time_sec, Int64 delta, const DateLUTImpl &) \
{ \
return static_cast<UInt32>(time_sec + INTERVAL * delta); \
} \
template <typename Timestamp> \
requires(std::is_same_v<Timestamp, Int64> || std::is_same_v<Timestamp, DateTime64>) \
static inline NO_SANITIZE_UNDEFINED Timestamp execute(Timestamp t, Int64 delta, const DateLUTImpl &, UInt32 scale) \
{ \
return t + delta * INTERVAL * common::exp10_i64(static_cast<int>(scale)); \
} \
};
ADD_TIME(Hour, 3600)
ADD_TIME(Minute, 60)
ADD_TIME(Second, 1)
#undef ADD_TIME
#define ADD_TIME(INTERVAL_KIND, INTERVAL_SCALE) \
template <> \
struct AddTime<IntervalKind::INTERVAL_KIND> \
{ \
static constexpr auto interval_scale_multiplier = common::exp10_i64(INTERVAL_SCALE); \
static inline NO_SANITIZE_UNDEFINED UInt32 execute(UInt32 time_sec, Int64 delta, const DateLUTImpl &) \
{ \
return static_cast<UInt32>(time_sec + delta / interval_scale_multiplier); \
} \
template <typename Timestamp> \
requires(std::is_same_v<Timestamp, Int64> || std::is_same_v<Timestamp, DateTime64>) \
static inline NO_SANITIZE_UNDEFINED Timestamp execute(Timestamp t, Int64 delta, const DateLUTImpl &, UInt32 scale) \
{ \
if (likely(scale >= INTERVAL_SCALE)) \
return t + delta * common::exp10_i64(scale - INTERVAL_SCALE); \
else \
return t + delta / common::exp10_i64(INTERVAL_SCALE - scale); \
} \
};
ADD_TIME(Millisecond, 3)
ADD_TIME(Microsecond, 6)
ADD_TIME(Nanosecond, 9)
#undef ADD_TIME
}
}