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>
|
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>);
|
static_assert(std::is_integral_v<T> && std::is_integral_v<Divisor>);
|
||||||
assert(divisor > 0);
|
assert(divisor > 0);
|
||||||
|
|
||||||
|
if (likely(offset_is_whole_number_of_hours_during_epoch))
|
||||||
|
{
|
||||||
if (likely(x >= 0))
|
if (likely(x >= 0))
|
||||||
return x / divisor * divisor;
|
return x / divisor * divisor;
|
||||||
|
|
||||||
/// Integer division for negative numbers rounds them towards zero (up).
|
/// Integer division for negative numbers rounds them towards zero (up).
|
||||||
/// We will shift the number so it will be rounded towards -inf (down).
|
/// We will shift the number so it will be rounded towards -inf (down).
|
||||||
|
|
||||||
return (x + 1 - divisor) / divisor * divisor;
|
return (x + 1 - divisor) / divisor * divisor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Time date = find(x).date;
|
||||||
|
return date + (x - date) / divisor * divisor;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const std::string & getTimeZone() const { return time_zone; }
|
const std::string & getTimeZone() const { return time_zone; }
|
||||||
|
|
||||||
@ -458,6 +463,8 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
inline unsigned toSecond(Time t) const
|
inline unsigned toSecond(Time t) const
|
||||||
|
{
|
||||||
|
if (offset_is_whole_number_of_hours_during_epoch)
|
||||||
{
|
{
|
||||||
auto res = t % 60;
|
auto res = t % 60;
|
||||||
if (likely(res >= 0))
|
if (likely(res >= 0))
|
||||||
@ -465,6 +472,18 @@ public:
|
|||||||
return res + 60;
|
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
|
inline unsigned toMinute(Time t) const
|
||||||
{
|
{
|
||||||
if (t >= 0 && offset_is_whole_number_of_hours_during_epoch)
|
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 toStartOfMinute(Time t) const { return roundDown(t, 60); }
|
||||||
inline Time toStartOfFiveMinute(Time t) const { return roundDown(t, 300); }
|
inline Time toStartOfFiveMinute(Time t) const { return roundDown(t, 300); }
|
||||||
inline Time toStartOfFifteenMinutes(Time t) const { return roundDown(t, 900); }
|
inline Time toStartOfFifteenMinutes(Time t) const { return roundDown(t, 900); }
|
||||||
|
inline Time toStartOfTenMinutes(Time t) const { return roundDown(t, 600); }
|
||||||
inline Time toStartOfTenMinutes(Time t) const
|
inline Time toStartOfHour(Time t) const { return roundDown(t, 3600); }
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Number of calendar day since the beginning of UNIX epoch (1970-01-01 is zero)
|
/** 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.
|
* 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