mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Improve compatibility with non-whole-minute timezone offsets
This commit is contained in:
parent
908505c12e
commit
abeaf60e4a
@ -251,20 +251,25 @@ private:
|
||||
}
|
||||
|
||||
template <typename T, typename Divisor>
|
||||
static inline T roundDown(T x, Divisor divisor)
|
||||
inline T roundDown(T x, Divisor divisor) const
|
||||
{
|
||||
static_assert(std::is_integral_v<T> && std::is_integral_v<Divisor>);
|
||||
assert(divisor > 0);
|
||||
|
||||
if (likely(offset_is_whole_number_of_hours_during_epoch))
|
||||
{
|
||||
if (likely(x >= 0))
|
||||
return 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 (x + 1 - divisor) / divisor * divisor;
|
||||
}
|
||||
|
||||
Time date = find(x).date;
|
||||
return date + (x - date) / divisor * divisor;
|
||||
}
|
||||
|
||||
public:
|
||||
const std::string & getTimeZone() const { return time_zone; }
|
||||
|
||||
@ -458,6 +463,8 @@ public:
|
||||
|
||||
|
||||
inline unsigned toSecond(Time t) const
|
||||
{
|
||||
if (offset_is_whole_number_of_hours_during_epoch)
|
||||
{
|
||||
auto res = t % 60;
|
||||
if (likely(res >= 0))
|
||||
@ -465,6 +472,18 @@ public:
|
||||
return res + 60;
|
||||
}
|
||||
|
||||
LUTIndex index = findIndex(t);
|
||||
UInt32 time = t - lut[index].date;
|
||||
|
||||
if (time >= lut[index].time_at_offset_change())
|
||||
time += lut[index].amount_of_offset_change();
|
||||
|
||||
auto res = time % 60;
|
||||
if (likely(res >= 0))
|
||||
return res;
|
||||
return res + 60;
|
||||
}
|
||||
|
||||
inline unsigned toMinute(Time t) const
|
||||
{
|
||||
if (t >= 0 && offset_is_whole_number_of_hours_during_epoch)
|
||||
@ -486,26 +505,8 @@ public:
|
||||
inline Time toStartOfMinute(Time t) const { return roundDown(t, 60); }
|
||||
inline Time toStartOfFiveMinute(Time t) const { return roundDown(t, 300); }
|
||||
inline Time toStartOfFifteenMinutes(Time t) const { return roundDown(t, 900); }
|
||||
|
||||
inline Time toStartOfTenMinutes(Time t) const
|
||||
{
|
||||
if (t >= 0 && offset_is_whole_number_of_hours_during_epoch)
|
||||
return t / 600 * 600;
|
||||
|
||||
/// More complex logic is for Nepal - it has offset 05:45. Australia/Eucla is also unfortunate.
|
||||
Time date = find(t).date;
|
||||
return date + (t - date) / 600 * 600;
|
||||
}
|
||||
|
||||
/// NOTE: Assuming timezone transitions are multiple of hours. Lord Howe Island in Australia is a notable exception.
|
||||
inline Time toStartOfHour(Time t) const
|
||||
{
|
||||
if (t >= 0 && offset_is_whole_number_of_hours_during_epoch)
|
||||
return t / 3600 * 3600;
|
||||
|
||||
Time date = find(t).date;
|
||||
return date + (t - date) / 3600 * 3600;
|
||||
}
|
||||
inline Time toStartOfTenMinutes(Time t) const { return roundDown(t, 600); }
|
||||
inline Time toStartOfHour(Time t) const { return roundDown(t, 3600); }
|
||||
|
||||
/** Number of calendar day since the beginning of UNIX epoch (1970-01-01 is zero)
|
||||
* We use just two bytes for it. It covers the range up to 2105 and slightly more.
|
||||
|
@ -0,0 +1,20 @@
|
||||
Row 1:
|
||||
──────
|
||||
toUnixTimestamp(t): 14459031
|
||||
timeZoneOffset(t): -2670
|
||||
formatDateTime(t, '%F %T', 'Africa/Monrovia'): 1970-06-17 07:39:21
|
||||
toString(t, 'Africa/Monrovia'): 1970-06-17 07:39:21
|
||||
toStartOfMinute(t): 1970-06-17 07:39:00
|
||||
toStartOfFiveMinute(t): 1970-06-17 07:35:00
|
||||
toStartOfFifteenMinutes(t): 1970-06-17 07:30:00
|
||||
toStartOfTenMinutes(t): 1970-06-17 07:30:00
|
||||
toStartOfHour(t): 1970-06-17 07:00:00
|
||||
toStartOfDay(t): 1970-06-17 00:00:00
|
||||
toStartOfWeek(t): 1970-06-14
|
||||
toStartOfInterval(t, toIntervalSecond(1)): 1970-06-17 07:39:21
|
||||
toStartOfInterval(t, toIntervalMinute(1)): 1970-06-17 07:39:00
|
||||
toStartOfInterval(t, toIntervalMinute(2)): 1970-06-17 07:38:00
|
||||
toStartOfInterval(t, toIntervalMinute(5)): 1970-06-17 07:35:00
|
||||
toStartOfInterval(t, toIntervalMinute(60)): 1970-06-17 07:00:00
|
||||
addMinutes(t, 1): 1970-06-17 07:40:21
|
||||
addMinutes(t, 60): 1970-06-17 08:39:21
|
21
tests/queries/0_stateless/01958_partial_hour_timezone.sql
Normal file
21
tests/queries/0_stateless/01958_partial_hour_timezone.sql
Normal file
@ -0,0 +1,21 @@
|
||||
-- Appeared in https://github.com/ClickHouse/ClickHouse/pull/26978#issuecomment-890889362
|
||||
WITH toDateTime('1970-06-17 07:39:21', 'Africa/Monrovia') as t
|
||||
SELECT toUnixTimestamp(t),
|
||||
timeZoneOffset(t),
|
||||
formatDateTime(t, '%F %T', 'Africa/Monrovia'),
|
||||
toString(t, 'Africa/Monrovia'),
|
||||
toStartOfMinute(t),
|
||||
toStartOfFiveMinute(t),
|
||||
toStartOfFifteenMinutes(t),
|
||||
toStartOfTenMinutes(t),
|
||||
toStartOfHour(t),
|
||||
toStartOfDay(t),
|
||||
toStartOfWeek(t),
|
||||
toStartOfInterval(t, INTERVAL 1 second),
|
||||
toStartOfInterval(t, INTERVAL 1 minute),
|
||||
toStartOfInterval(t, INTERVAL 2 minute),
|
||||
toStartOfInterval(t, INTERVAL 5 minute),
|
||||
toStartOfInterval(t, INTERVAL 60 minute),
|
||||
addMinutes(t, 1),
|
||||
addMinutes(t, 60)
|
||||
FORMAT Vertical;
|
Loading…
Reference in New Issue
Block a user