mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Merge pull request #22060 from ClickHouse/to-start-of-interval-hour-align
Change behaviour of `toStartOfInterval` in backward incompatible way
This commit is contained in:
commit
9fd1577cd4
@ -853,15 +853,43 @@ public:
|
||||
{
|
||||
if (hours == 1)
|
||||
return toStartOfHour(t);
|
||||
|
||||
/** We will round the hour number since the midnight.
|
||||
* It may split the day into non-equal intervals.
|
||||
* For example, if we will round to 11-hour interval,
|
||||
* the day will be split to the intervals 00:00:00..10:59:59, 11:00:00..21:59:59, 22:00:00..23:59:59.
|
||||
* In case of daylight saving time or other transitions,
|
||||
* the intervals can be shortened or prolonged to the amount of transition.
|
||||
*/
|
||||
|
||||
UInt64 seconds = hours * 3600;
|
||||
|
||||
t = roundDown(t, seconds);
|
||||
const LUTIndex index = findIndex(t);
|
||||
const Values & values = lut[index];
|
||||
|
||||
if (t >= 0 && offset_is_whole_number_of_hours_during_epoch)
|
||||
return t;
|
||||
time_t time = t - values.date;
|
||||
if (time >= values.time_at_offset_change())
|
||||
{
|
||||
/// Align to new hour numbers before rounding.
|
||||
time += values.amount_of_offset_change();
|
||||
time = time / seconds * seconds;
|
||||
|
||||
/// TODO check if it's correct.
|
||||
return toStartOfHour(t);
|
||||
/// Should subtract the shift back but only if rounded time is not before shift.
|
||||
if (time >= values.time_at_offset_change())
|
||||
{
|
||||
time -= values.amount_of_offset_change();
|
||||
|
||||
/// With cutoff at the time of the shift. Otherwise we may end up with something like 23:00 previous day.
|
||||
if (time < values.time_at_offset_change())
|
||||
time = values.time_at_offset_change();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
time = time / seconds * seconds;
|
||||
}
|
||||
|
||||
return values.date + time;
|
||||
}
|
||||
|
||||
inline time_t toStartOfMinuteInterval(time_t t, UInt64 minutes) const
|
||||
@ -869,6 +897,14 @@ public:
|
||||
if (minutes == 1)
|
||||
return toStartOfMinute(t);
|
||||
|
||||
/** In contrast to "toStartOfHourInterval" function above,
|
||||
* the minute intervals are not aligned to the midnight.
|
||||
* You will get unexpected results if for example, you round down to 60 minute interval
|
||||
* and there was a time shift to 30 minutes.
|
||||
*
|
||||
* But this is not specified in docs and can be changed in future.
|
||||
*/
|
||||
|
||||
UInt64 seconds = 60 * minutes;
|
||||
return roundDown(t, seconds);
|
||||
}
|
||||
|
@ -130,7 +130,6 @@ TEST(DateLUTTest, TimeValuesInMiddleOfRange)
|
||||
EXPECT_EQ(lut.toRelativeQuarterNum(time), 8078 /*unsigned*/);
|
||||
EXPECT_EQ(lut.toRelativeHourNum(time), 435736 /*time_t*/);
|
||||
EXPECT_EQ(lut.toRelativeMinuteNum(time), 26144180 /*time_t*/);
|
||||
EXPECT_EQ(lut.toStartOfHourInterval(time, 5), 1568646000 /*time_t*/);
|
||||
EXPECT_EQ(lut.toStartOfMinuteInterval(time, 6), 1568650680 /*time_t*/);
|
||||
EXPECT_EQ(lut.toStartOfSecondInterval(time, 7), 1568650811 /*time_t*/);
|
||||
EXPECT_EQ(lut.toNumYYYYMM(time), 201909 /*UInt32*/);
|
||||
@ -191,7 +190,6 @@ TEST(DateLUTTest, TimeValuesAtLeftBoderOfRange)
|
||||
EXPECT_EQ(lut.toRelativeQuarterNum(time), 7880 /*unsigned*/); // ?
|
||||
EXPECT_EQ(lut.toRelativeHourNum(time), 0 /*time_t*/);
|
||||
EXPECT_EQ(lut.toRelativeMinuteNum(time), 0 /*time_t*/);
|
||||
EXPECT_EQ(lut.toStartOfHourInterval(time, 5), 0 /*time_t*/);
|
||||
EXPECT_EQ(lut.toStartOfMinuteInterval(time, 6), 0 /*time_t*/);
|
||||
EXPECT_EQ(lut.toStartOfSecondInterval(time, 7), 0 /*time_t*/);
|
||||
EXPECT_EQ(lut.toNumYYYYMM(time), 197001 /*UInt32*/);
|
||||
@ -253,7 +251,6 @@ TEST(DateLUTTest, TimeValuesAtRightBoderOfRangeOfOldLUT)
|
||||
EXPECT_EQ(lut.toRelativeQuarterNum(time), 8424 /*unsigned*/);
|
||||
EXPECT_EQ(lut.toRelativeHourNum(time), 1192873 /*time_t*/);
|
||||
EXPECT_EQ(lut.toRelativeMinuteNum(time), 71572397 /*time_t*/);
|
||||
EXPECT_EQ(lut.toStartOfHourInterval(time, 5), 4294332000 /*time_t*/);
|
||||
EXPECT_EQ(lut.toStartOfMinuteInterval(time, 6), 4294343520 /*time_t*/);
|
||||
EXPECT_EQ(lut.toStartOfSecondInterval(time, 7), 4294343872 /*time_t*/);
|
||||
EXPECT_EQ(lut.toNumYYYYMM(time), 210601 /*UInt32*/);
|
||||
|
@ -148,9 +148,9 @@ toStartOfInterval
|
||||
2019-02-05 00:00:00
|
||||
2019-02-03 00:00:00
|
||||
2019-02-06 22:00:00
|
||||
2019-02-06 21:00:00
|
||||
2019-02-06 21:00:00
|
||||
2019-02-06 03:00:00
|
||||
2019-02-06 22:00:00
|
||||
2019-02-06 18:00:00
|
||||
2019-02-06 00:00:00
|
||||
2019-02-06 22:57:00
|
||||
2019-02-06 22:56:00
|
||||
2019-02-06 22:55:00
|
@ -0,0 +1,86 @@
|
||||
2021-03-23 00:00:00
|
||||
2021-03-23 11:00:00
|
||||
2021-03-23 22:00:00
|
||||
2021-03-23 13:00:00
|
||||
2021-03-23 12:00:00
|
||||
2021-03-23 00:00:00
|
||||
2010-03-28 00:00:00 2010-03-28 00:00:00 1269723600
|
||||
2010-03-28 00:15:00 2010-03-28 00:00:00 1269724500
|
||||
2010-03-28 00:30:00 2010-03-28 00:00:00 1269725400
|
||||
2010-03-28 00:45:00 2010-03-28 00:00:00 1269726300
|
||||
2010-03-28 01:00:00 2010-03-28 00:00:00 1269727200
|
||||
2010-03-28 01:15:00 2010-03-28 00:00:00 1269728100
|
||||
2010-03-28 01:30:00 2010-03-28 00:00:00 1269729000
|
||||
2010-03-28 01:45:00 2010-03-28 00:00:00 1269729900
|
||||
2010-03-28 03:00:00 2010-03-28 03:00:00 1269730800
|
||||
2010-03-28 03:15:00 2010-03-28 03:00:00 1269731700
|
||||
2010-03-28 03:30:00 2010-03-28 03:00:00 1269732600
|
||||
2010-03-28 03:45:00 2010-03-28 03:00:00 1269733500
|
||||
2010-03-28 04:00:00 2010-03-28 04:00:00 1269734400
|
||||
2010-03-28 04:15:00 2010-03-28 04:00:00 1269735300
|
||||
2010-03-28 04:30:00 2010-03-28 04:00:00 1269736200
|
||||
2010-03-28 04:45:00 2010-03-28 04:00:00 1269737100
|
||||
2010-03-28 05:00:00 2010-03-28 04:00:00 1269738000
|
||||
2010-03-28 05:15:00 2010-03-28 04:00:00 1269738900
|
||||
2010-03-28 05:30:00 2010-03-28 04:00:00 1269739800
|
||||
2010-03-28 05:45:00 2010-03-28 04:00:00 1269740700
|
||||
2010-10-31 00:00:00 2010-10-31 00:00:00 1288468800
|
||||
2010-10-31 00:15:00 2010-10-31 00:00:00 1288469700
|
||||
2010-10-31 00:30:00 2010-10-31 00:00:00 1288470600
|
||||
2010-10-31 00:45:00 2010-10-31 00:00:00 1288471500
|
||||
2010-10-31 01:00:00 2010-10-31 00:00:00 1288472400
|
||||
2010-10-31 01:15:00 2010-10-31 00:00:00 1288473300
|
||||
2010-10-31 01:30:00 2010-10-31 00:00:00 1288474200
|
||||
2010-10-31 01:45:00 2010-10-31 00:00:00 1288475100
|
||||
2010-10-31 02:00:00 2010-10-31 02:00:00 1288476000
|
||||
2010-10-31 02:15:00 2010-10-31 02:00:00 1288476900
|
||||
2010-10-31 02:30:00 2010-10-31 02:00:00 1288477800
|
||||
2010-10-31 02:45:00 2010-10-31 02:00:00 1288478700
|
||||
2010-10-31 02:00:00 2010-10-31 02:00:00 1288479600
|
||||
2010-10-31 02:15:00 2010-10-31 02:00:00 1288480500
|
||||
2010-10-31 02:30:00 2010-10-31 02:00:00 1288481400
|
||||
2010-10-31 02:45:00 2010-10-31 02:00:00 1288482300
|
||||
2010-10-31 03:00:00 2010-10-31 02:00:00 1288483200
|
||||
2010-10-31 03:15:00 2010-10-31 02:00:00 1288484100
|
||||
2010-10-31 03:30:00 2010-10-31 02:00:00 1288485000
|
||||
2010-10-31 03:45:00 2010-10-31 02:00:00 1288485900
|
||||
2020-04-05 00:00:00 2020-04-05 00:00:00 1586005200
|
||||
2020-04-05 00:15:00 2020-04-05 00:00:00 1586006100
|
||||
2020-04-05 00:30:00 2020-04-05 00:00:00 1586007000
|
||||
2020-04-05 00:45:00 2020-04-05 00:00:00 1586007900
|
||||
2020-04-05 01:00:00 2020-04-05 00:00:00 1586008800
|
||||
2020-04-05 01:15:00 2020-04-05 00:00:00 1586009700
|
||||
2020-04-05 01:30:00 2020-04-05 00:00:00 1586010600
|
||||
2020-04-05 01:45:00 2020-04-05 00:00:00 1586011500
|
||||
2020-04-05 01:30:00 2020-04-05 00:00:00 1586012400
|
||||
2020-04-05 01:45:00 2020-04-05 00:00:00 1586013300
|
||||
2020-04-05 02:00:00 2020-04-05 02:00:00 1586014200
|
||||
2020-04-05 02:15:00 2020-04-05 02:00:00 1586015100
|
||||
2020-04-05 02:30:00 2020-04-05 02:00:00 1586016000
|
||||
2020-04-05 02:45:00 2020-04-05 02:00:00 1586016900
|
||||
2020-04-05 03:00:00 2020-04-05 02:00:00 1586017800
|
||||
2020-04-05 03:15:00 2020-04-05 02:00:00 1586018700
|
||||
2020-04-05 03:30:00 2020-04-05 02:00:00 1586019600
|
||||
2020-04-05 03:45:00 2020-04-05 02:00:00 1586020500
|
||||
2020-04-05 04:00:00 2020-04-05 04:00:00 1586021400
|
||||
2020-04-05 04:15:00 2020-04-05 04:00:00 1586022300
|
||||
2020-10-04 00:00:00 2020-10-04 00:00:00 1601731800
|
||||
2020-10-04 00:15:00 2020-10-04 00:00:00 1601732700
|
||||
2020-10-04 00:30:00 2020-10-04 00:00:00 1601733600
|
||||
2020-10-04 00:45:00 2020-10-04 00:00:00 1601734500
|
||||
2020-10-04 01:00:00 2020-10-04 00:00:00 1601735400
|
||||
2020-10-04 01:15:00 2020-10-04 00:00:00 1601736300
|
||||
2020-10-04 01:30:00 2020-10-04 00:00:00 1601737200
|
||||
2020-10-04 01:45:00 2020-10-04 00:00:00 1601738100
|
||||
2020-10-04 02:30:00 2020-10-04 02:30:00 1601739000
|
||||
2020-10-04 02:45:00 2020-10-04 02:30:00 1601739900
|
||||
2020-10-04 03:00:00 2020-10-04 02:30:00 1601740800
|
||||
2020-10-04 03:15:00 2020-10-04 02:30:00 1601741700
|
||||
2020-10-04 03:30:00 2020-10-04 02:30:00 1601742600
|
||||
2020-10-04 03:45:00 2020-10-04 02:30:00 1601743500
|
||||
2020-10-04 04:00:00 2020-10-04 04:00:00 1601744400
|
||||
2020-10-04 04:15:00 2020-10-04 04:00:00 1601745300
|
||||
2020-10-04 04:30:00 2020-10-04 04:00:00 1601746200
|
||||
2020-10-04 04:45:00 2020-10-04 04:00:00 1601747100
|
||||
2020-10-04 05:00:00 2020-10-04 04:00:00 1601748000
|
||||
2020-10-04 05:15:00 2020-10-04 04:00:00 1601748900
|
21
tests/queries/0_stateless/01772_to_start_of_hour_align.sql
Normal file
21
tests/queries/0_stateless/01772_to_start_of_hour_align.sql
Normal file
@ -0,0 +1,21 @@
|
||||
-- Rounding down to hour intervals is aligned to midnight even if the interval length does not divide the whole day.
|
||||
SELECT toStartOfInterval(toDateTime('2021-03-23 03:58:00'), INTERVAL 11 HOUR);
|
||||
SELECT toStartOfInterval(toDateTime('2021-03-23 13:58:00'), INTERVAL 11 HOUR);
|
||||
SELECT toStartOfInterval(toDateTime('2021-03-23 23:58:00'), INTERVAL 11 HOUR);
|
||||
|
||||
-- It should work correctly even in timezones with non-whole hours offset. India have +05:30.
|
||||
SELECT toStartOfHour(toDateTime('2021-03-23 13:58:00', 'Asia/Kolkata'));
|
||||
SELECT toStartOfInterval(toDateTime('2021-03-23 13:58:00', 'Asia/Kolkata'), INTERVAL 6 HOUR);
|
||||
|
||||
-- Specifying the interval longer than 24 hours is not correct, but it works as expected by just rounding to midnight.
|
||||
SELECT toStartOfInterval(toDateTime('2021-03-23 13:58:00', 'Asia/Kolkata'), INTERVAL 66 HOUR);
|
||||
|
||||
-- In case of timezone shifts, rounding is performed to the hour number on "wall clock" time.
|
||||
-- The intervals may become shorter or longer due to time shifts. For example, the three hour interval may actually last two hours.
|
||||
-- If the same hour number on "wall clock" time correspond to multiple time points due to shifting backwards, the unspecified time point is selected among the candidates.
|
||||
SELECT toDateTime('2010-03-28 00:00:00', 'Europe/Moscow') + INTERVAL 15 * number MINUTE AS src, toStartOfInterval(src, INTERVAL 2 HOUR) AS rounded, toUnixTimestamp(src) AS t FROM numbers(20);
|
||||
SELECT toDateTime('2010-10-31 00:00:00', 'Europe/Moscow') + INTERVAL 15 * number MINUTE AS src, toStartOfInterval(src, INTERVAL 2 HOUR) AS rounded, toUnixTimestamp(src) AS t FROM numbers(20);
|
||||
|
||||
-- And this should work even for non whole number of hours shifts.
|
||||
SELECT toDateTime('2020-04-05 00:00:00', 'Australia/Lord_Howe') + INTERVAL 15 * number MINUTE AS src, toStartOfInterval(src, INTERVAL 2 HOUR) AS rounded, toUnixTimestamp(src) AS t FROM numbers(20);
|
||||
SELECT toDateTime('2020-10-04 00:00:00', 'Australia/Lord_Howe') + INTERVAL 15 * number MINUTE AS src, toStartOfInterval(src, INTERVAL 2 HOUR) AS rounded, toUnixTimestamp(src) AS t FROM numbers(20);
|
Loading…
Reference in New Issue
Block a user