Extended range of DateTime64 to years 1925 - 2238

The Year 1925 is a starting point because most of the timezones
switched to saner (mostly 15-minutes based) offsets somewhere
during 1924 or before. And that significantly simplifies implementation.

2238 is to simplify arithmetics for sanitizing LUT index access;
there are less than 0x1ffff days from 1925.

* Extended DateLUTImpl internal LUT to 0x1ffff items, some of which
  represent negative (pre-1970) time values.
  As a collateral benefit, Date now correctly supports dates up to 2149
  (instead of 2106).
* Added a new strong typedef ExtendedDayNum, which represents dates
  pre-1970 and post 2149.
* Functions that used to return DayNum now return ExtendedDayNum.
* Refactored DateLUTImpl to untie DayNum from the dual role of being
  a value and an index (due to negative time). Index is now a different
  type LUTIndex with explicit conversion functions from DatNum, time_t,
  and ExtendedDayNum.
* Updated DateLUTImpl to properly support values close to epoch start
  (1970-01-01 00:00), including negative ones.
* Reduced resolution of DateLUTImpl::Values::time_at_offset_change
  to multiple of 15-minutes to allow storing 64-bits of time_t in
  DateLUTImpl::Value while keeping same size.
* Minor performance updates to DateLUTImpl when building month LUT
  by skipping non-start-of-month days.
* Fixed extractTimeZoneFromFunctionArguments to work correctly
  with DateTime64.
* New unit-tests and stateless integration tests for both DateTime
  and DateTime64.
This commit is contained in:
Vasily Nemkov 2020-04-17 16:26:44 +03:00
parent c1a077a111
commit 2d03d330bc
54 changed files with 1585 additions and 741 deletions

View File

@ -32,7 +32,6 @@ public:
return date_lut.getImplementation(time_zone);
}
static void setDefaultTimezone(const std::string & time_zone)
{
auto & date_lut = getInstance();

View File

@ -46,19 +46,26 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
if (&inside_main)
assert(inside_main);
size_t i = 0;
time_t start_of_day = 0;
cctz::time_zone cctz_time_zone;
if (!cctz::load_time_zone(time_zone, &cctz_time_zone))
throw Poco::Exception("Cannot load time zone " + time_zone_);
cctz::time_zone::absolute_lookup start_of_epoch_lookup = cctz_time_zone.lookup(std::chrono::system_clock::from_time_t(start_of_day));
offset_at_start_of_epoch = start_of_epoch_lookup.offset;
const cctz::civil_day epoch{1970, 1, 1};
const cctz::civil_day lut_start{DATE_LUT_MIN_YEAR, 1, 1};
time_t start_of_day = std::chrono::system_clock::to_time_t(cctz_time_zone.lookup(lut_start).pre);
time_offset_epoch = cctz::convert(cctz::civil_second(lut_start), cctz_time_zone).time_since_epoch().count();
// Note validated this against all timezones in the system.
assert((epoch - lut_start) == daynum_offset_epoch);
offset_at_start_of_epoch = cctz_time_zone.lookup(cctz_time_zone.lookup(epoch).pre).offset;
offset_at_start_of_lut = cctz_time_zone.lookup(cctz_time_zone.lookup(lut_start).pre).offset;
offset_is_whole_number_of_hours_everytime = true;
cctz::civil_day date{1970, 1, 1};
cctz::civil_day date = lut_start;
UInt32 i = 0;
do
{
cctz::time_zone::civil_lookup lookup = cctz_time_zone.lookup(date);
@ -72,7 +79,7 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
values.day_of_week = getDayOfWeek(date);
values.date = start_of_day;
assert(values.year >= DATE_LUT_MIN_YEAR && values.year <= DATE_LUT_MAX_YEAR);
assert(values.year >= DATE_LUT_MIN_YEAR && values.year <= DATE_LUT_MAX_YEAR + 1);
assert(values.month >= 1 && values.month <= 12);
assert(values.day_of_month >= 1 && values.day_of_month <= 31);
assert(values.day_of_week >= 1 && values.day_of_week <= 7);
@ -85,10 +92,13 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
else
values.days_in_month = i != 0 ? lut[i - 1].days_in_month : 31;
values.time_at_offset_change = 0;
values.amount_of_offset_change = 0;
values.time_at_offset_change_value = 0;
values.amount_of_offset_change_value = 0;
if (start_of_day % 3600)
// TODO: this partially ignores fractional pre-epoch offsets, which may cause incorrect toRelativeHourNum() results for some timezones, namelly Europe\Minsk
// when pre-May 2 1924 it had an offset of UTC+1:50, and after it was UTC+2h.
// https://www.timeanddate.com/time/zone/belarus/minsk?syear=1900
if (start_of_day > 0 && start_of_day % 3600)
offset_is_whole_number_of_hours_everytime = false;
/// If UTC offset was changed in previous day.
@ -97,7 +107,7 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
auto amount_of_offset_change_at_prev_day = 86400 - (lut[i].date - lut[i - 1].date);
if (amount_of_offset_change_at_prev_day)
{
lut[i - 1].amount_of_offset_change = amount_of_offset_change_at_prev_day;
lut[i - 1].amount_of_offset_change_value = amount_of_offset_change_at_prev_day / Values::OffsetChangeFactor;
const auto utc_offset_at_beginning_of_day = cctz_time_zone.lookup(std::chrono::system_clock::from_time_t(lut[i - 1].date)).offset;
@ -116,11 +126,11 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
time_at_offset_change += 900;
}
lut[i - 1].time_at_offset_change = time_at_offset_change;
lut[i - 1].time_at_offset_change_value = time_at_offset_change / Values::OffsetChangeFactor;
/// We doesn't support cases when time change results in switching to previous day.
if (static_cast<int>(lut[i - 1].time_at_offset_change) + static_cast<int>(lut[i - 1].amount_of_offset_change) < 0)
lut[i - 1].time_at_offset_change = -lut[i - 1].amount_of_offset_change;
/// We don't support cases when time change results in switching to previous day.
if (static_cast<int>(lut[i - 1].time_at_offset_change()) + static_cast<int>(lut[i - 1].amount_of_offset_change()) < 0)
lut[i - 1].time_at_offset_change_value = -lut[i - 1].amount_of_offset_change_value;
}
}
@ -128,7 +138,9 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
++date;
++i;
}
while (start_of_day <= DATE_LUT_MAX && i <= DATE_LUT_MAX_DAY_NUM);
while (i < DATE_LUT_SIZE && lut[i - 1].year <= DATE_LUT_MAX_YEAR);
// date_lut_max = start_of_day;
/// Fill excessive part of lookup table. This is needed only to simplify handling of overflow cases.
while (i < DATE_LUT_SIZE)

File diff suppressed because it is too large Load Diff

View File

@ -7,3 +7,8 @@
* See DateLUTImpl for usage examples.
*/
STRONG_TYPEDEF(UInt16, DayNum)
/** Represent number of days since 1970-01-01 but in extended range,
* for dates before 1970-01-01 and after 2105
*/
STRONG_TYPEDEF(Int32, ExtendedDayNum)

View File

@ -105,7 +105,8 @@ public:
DayNum getDayNum() const
{
return DateLUT::instance().makeDayNum(m_year, m_month, m_day);
const auto & lut = DateLUT::instance();
return DayNum(lut.makeDayNum(m_year, m_month, m_day).toUnderType());
}
operator DayNum() const

View File

@ -12,6 +12,7 @@ private:
T t;
public:
using UnderlyingType = T;
template <class Enable = typename std::is_copy_constructible<T>::type>
explicit StrongTypedef(const T & t_) : t(t_) {}
template <class Enable = typename std::is_move_constructible<T>::type>

View File

@ -16,7 +16,9 @@ target_link_libraries (realloc-perf PRIVATE common)
add_check(local_date_time_comparison)
if(USE_GTEST)
add_executable(unit_tests_libcommon gtest_json_test.cpp gtest_strong_typedef.cpp gtest_find_symbols.cpp)
add_executable(unit_tests_libcommon gtest_json_test.cpp gtest_strong_typedef.cpp gtest_find_symbols.cpp gtest_DateLutImpl.cpp
${CMAKE_BINARY_DIR}/src/Storages/System/StorageSystemTimeZones.generated.cpp
)
target_link_libraries(unit_tests_libcommon PRIVATE common ${GTEST_MAIN_LIBRARIES} ${GTEST_LIBRARIES})
add_check(unit_tests_libcommon)
endif()

View File

@ -0,0 +1,515 @@
#include <common/DateLUT.h>
#include <common/DateLUTImpl.h>
#include <gtest/gtest.h>
#include <string>
#include <cctz/time_zone.h>
/// For the expansion of gtest macros.
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wused-but-marked-unused"
#endif
// All timezones present at build time and embedded into CH binary.
extern const char * auto_time_zones[];
namespace
{
cctz::civil_day YYYYMMDDToDay(unsigned value)
{
return cctz::civil_day(
value / 10000, // year
(value % 10000) / 100, // month
value % 100); // day
}
cctz::civil_second YYYYMMDDHMMSSToSecond(std::uint64_t value)
{
return cctz::civil_second(
value / 10000000000,
value / 100000000 % 100,
value / 1000000 % 100,
value / 10000 % 100,
value / 100 % 100,
value % 100);
}
std::vector<const char*> allTimezones()
{
std::vector<const char*> result;
auto timezone_name = auto_time_zones;
while (*timezone_name)
{
result.push_back(*timezone_name);
++timezone_name;
}
return result;
}
struct FailuresCount
{
size_t non_fatal = 0;
size_t fatal = 0;
size_t total = 0;
};
FailuresCount countFailures(const ::testing::TestResult & test_result)
{
FailuresCount failures{0, 0, 0};
const size_t count = test_result.total_part_count();
for (size_t i = 0; i < count; ++i)
{
const auto & part = test_result.GetTestPartResult(i);
if (part.nonfatally_failed())
{
++failures.non_fatal;
++failures.total;
}
if (part.fatally_failed())
{
++failures.fatal;
++failures.total;
}
}
return failures;
}
}
TEST(YYYYMMDDToDay, Test)
{
std::cerr << YYYYMMDDHMMSSToSecond(19700101'00'00'00) << std::endl;
}
TEST(DateLUTTest, TimeValuesInMiddleOfRange)
{
const DateLUTImpl lut("Europe/Minsk");
const time_t time = 1568650811; // 2019-09-16 19:20:11 (Monday)
EXPECT_EQ(lut.getTimeZone(), "Europe/Minsk");
EXPECT_EQ(lut.getOffsetAtStartOfEpoch(), 3600*3); // UTC-3
EXPECT_EQ(lut.toDate(time), 1568581200);
EXPECT_EQ(lut.toMonth(time), 9);
EXPECT_EQ(lut.toQuarter(time), 3);
EXPECT_EQ(lut.toYear(time), 2019);
EXPECT_EQ(lut.toDayOfMonth(time), 16);
EXPECT_EQ(lut.toFirstDayOfWeek(time), 1568581200 /*time_t*/);
EXPECT_EQ(lut.toFirstDayNumOfWeek(time), DayNum(18155) /*DayNum*/);
EXPECT_EQ(lut.toFirstDayOfMonth(time), 1567285200 /*time_t*/);
EXPECT_EQ(lut.toFirstDayNumOfMonth(time), DayNum(18140) /*DayNum*/);
EXPECT_EQ(lut.toFirstDayNumOfQuarter(time), DayNum(18078) /*DayNum*/);
EXPECT_EQ(lut.toFirstDayOfQuarter(time), 1561928400 /*time_t*/);
EXPECT_EQ(lut.toFirstDayOfYear(time), 1546290000 /*time_t*/);
EXPECT_EQ(lut.toFirstDayNumOfYear(time), DayNum(17897) /*DayNum*/);
EXPECT_EQ(lut.toFirstDayOfNextMonth(time), 1569877200 /*time_t*/);
EXPECT_EQ(lut.toFirstDayOfPrevMonth(time), 1564606800 /*time_t*/);
EXPECT_EQ(lut.daysInMonth(time), 30 /*UInt8*/);
EXPECT_EQ(lut.toDateAndShift(time, 10), 1569445200 /*time_t*/);
EXPECT_EQ(lut.toTime(time), 58811 /*time_t*/);
EXPECT_EQ(lut.toHour(time), 19 /*unsigned*/);
EXPECT_EQ(lut.toSecond(time), 11 /*unsigned*/);
EXPECT_EQ(lut.toMinute(time), 20 /*unsigned*/);
EXPECT_EQ(lut.toStartOfMinute(time), 1568650800 /*time_t*/);
EXPECT_EQ(lut.toStartOfFiveMinute(time), 1568650800 /*time_t*/);
EXPECT_EQ(lut.toStartOfFifteenMinutes(time), 1568650500 /*time_t*/);
EXPECT_EQ(lut.toStartOfTenMinutes(time), 1568650800 /*time_t*/);
EXPECT_EQ(lut.toStartOfHour(time), 1568649600 /*time_t*/);
EXPECT_EQ(lut.toDayNum(time), DayNum(18155) /*DayNum*/);
EXPECT_EQ(lut.toDayOfYear(time), 259 /*unsigned*/);
EXPECT_EQ(lut.toRelativeWeekNum(time), 2594 /*unsigned*/);
EXPECT_EQ(lut.toISOYear(time), 2019 /*unsigned*/);
EXPECT_EQ(lut.toFirstDayNumOfISOYear(time), DayNum(17896) /*DayNum*/);
EXPECT_EQ(lut.toFirstDayOfISOYear(time), 1546203600 /*time_t*/);
EXPECT_EQ(lut.toISOWeek(time), 38 /*unsigned*/);
EXPECT_EQ(lut.toRelativeMonthNum(time), 24237 /*unsigned*/);
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*/);
EXPECT_EQ(lut.toNumYYYYMMDD(time), 20190916 /*UInt32*/);
EXPECT_EQ(lut.toNumYYYYMMDDhhmmss(time), 20190916192011 /*UInt64*/);
EXPECT_EQ(lut.addDays(time, 100), 1577290811 /*time_t*/);
EXPECT_EQ(lut.addWeeks(time, 100), 1629130811 /*time_t*/);
EXPECT_EQ(lut.addMonths(time, 100), 1831652411 /*time_t*/);
EXPECT_EQ(lut.addQuarters(time, 100), 2357655611 /*time_t*/);
EXPECT_EQ(lut.addYears(time, 10), 1884270011 /*time_t*/);
EXPECT_EQ(lut.timeToString(time), "2019-09-16 19:20:11" /*std::string*/);
EXPECT_EQ(lut.dateToString(time), "2019-09-16" /*std::string*/);
}
TEST(DateLUTTest, TimeValuesAtLeftBoderOfRange)
{
const DateLUTImpl lut("UTC");
const time_t time = 0; // 1970-01-01 00:00:00 (Thursday)
EXPECT_EQ(lut.getTimeZone(), "UTC");
EXPECT_EQ(lut.toDate(time), 0);
EXPECT_EQ(lut.toMonth(time), 1);
EXPECT_EQ(lut.toQuarter(time), 1);
EXPECT_EQ(lut.toYear(time), 1970);
EXPECT_EQ(lut.toDayOfMonth(time), 1);
EXPECT_EQ(lut.toFirstDayOfWeek(time), -259200 /*time_t*/); // 1969-12-29 00:00:00
EXPECT_EQ(lut.toFirstDayNumOfWeek(time), ExtendedDayNum(-3) /*DayNum*/);
EXPECT_EQ(lut.toFirstDayOfMonth(time), 0 /*time_t*/);
EXPECT_EQ(lut.toFirstDayNumOfMonth(time), DayNum(0) /*DayNum*/);
EXPECT_EQ(lut.toFirstDayNumOfQuarter(time), DayNum(0) /*DayNum*/);
EXPECT_EQ(lut.toFirstDayOfQuarter(time), 0 /*time_t*/);
EXPECT_EQ(lut.toFirstDayOfYear(time), 0 /*time_t*/);
EXPECT_EQ(lut.toFirstDayNumOfYear(time), DayNum(0) /*DayNum*/);
EXPECT_EQ(lut.toFirstDayOfNextMonth(time), 2678400 /*time_t*/);
EXPECT_EQ(lut.toFirstDayOfPrevMonth(time), -2678400 /*time_t*/); // 1969-12-01 00:00:00
EXPECT_EQ(lut.daysInMonth(time), 31 /*UInt8*/);
EXPECT_EQ(lut.toDateAndShift(time, 10), 864000 /*time_t*/);
EXPECT_EQ(lut.toTime(time), 0 /*time_t*/);
EXPECT_EQ(lut.toHour(time), 0 /*unsigned*/);
EXPECT_EQ(lut.toSecond(time), 0 /*unsigned*/);
EXPECT_EQ(lut.toMinute(time), 0 /*unsigned*/);
EXPECT_EQ(lut.toStartOfMinute(time), 0 /*time_t*/);
EXPECT_EQ(lut.toStartOfFiveMinute(time), 0 /*time_t*/);
EXPECT_EQ(lut.toStartOfFifteenMinutes(time), 0 /*time_t*/);
EXPECT_EQ(lut.toStartOfTenMinutes(time), 0 /*time_t*/);
EXPECT_EQ(lut.toStartOfHour(time), 0 /*time_t*/);
EXPECT_EQ(lut.toDayNum(time), DayNum(0) /*DayNum*/);
EXPECT_EQ(lut.toDayOfYear(time), 1 /*unsigned*/);
EXPECT_EQ(lut.toRelativeWeekNum(time), 0 /*unsigned*/);
EXPECT_EQ(lut.toISOYear(time), 1970 /*unsigned*/);
EXPECT_EQ(lut.toFirstDayNumOfISOYear(time), ExtendedDayNum(-3) /*DayNum*/);
EXPECT_EQ(lut.toFirstDayOfISOYear(time), -259200 /*time_t*/); // 1969-12-29 00:00:00
EXPECT_EQ(lut.toISOWeek(time), 1 /*unsigned*/);
EXPECT_EQ(lut.toRelativeMonthNum(time), 23641 /*unsigned*/); // ?
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*/);
EXPECT_EQ(lut.toNumYYYYMMDD(time), 19700101 /*UInt32*/);
EXPECT_EQ(lut.toNumYYYYMMDDhhmmss(time), 19700101000000 /*UInt64*/);
EXPECT_EQ(lut.addDays(time, 100), 8640000 /*time_t*/);
EXPECT_EQ(lut.addWeeks(time, 100), 60480000 /*time_t*/);
EXPECT_EQ(lut.addMonths(time, 100), 262828800 /*time_t*/);
EXPECT_EQ(lut.addQuarters(time, 100), 788918400 /*time_t*/);
EXPECT_EQ(lut.addYears(time, 10), 315532800 /*time_t*/);
EXPECT_EQ(lut.timeToString(time), "1970-01-01 00:00:00" /*std::string*/);
EXPECT_EQ(lut.dateToString(time), "1970-01-01" /*std::string*/);
}
TEST(DateLUTTest, TimeValuesAtRightBoderOfRangeOfOLDLut)
{
// Value is at the right border of the OLD (small) LUT, and provides meaningful values where OLD LUT would provide garbage.
const DateLUTImpl lut("UTC");
const time_t time = 4294343873; // 2106-01-31T01:17:53 (Sunday)
EXPECT_EQ(lut.getTimeZone(), "UTC");
EXPECT_EQ(lut.toDate(time), 4294339200);
EXPECT_EQ(lut.toMonth(time), 1);
EXPECT_EQ(lut.toQuarter(time), 1);
EXPECT_EQ(lut.toYear(time), 2106);
EXPECT_EQ(lut.toDayOfMonth(time), 31);
EXPECT_EQ(lut.toFirstDayOfWeek(time), 4293820800 /*time_t*/);
EXPECT_EQ(lut.toFirstDayNumOfWeek(time), DayNum(49697));
EXPECT_EQ(lut.toFirstDayOfMonth(time), 4291747200 /*time_t*/); // 2016-01-01
EXPECT_EQ(lut.toFirstDayNumOfMonth(time), DayNum(49673));
EXPECT_EQ(lut.toFirstDayNumOfQuarter(time), DayNum(49673) /*DayNum*/);
EXPECT_EQ(lut.toFirstDayOfQuarter(time), 4291747200 /*time_t*/);
EXPECT_EQ(lut.toFirstDayOfYear(time), 4291747200 /*time_t*/);
EXPECT_EQ(lut.toFirstDayNumOfYear(time), DayNum(49673) /*DayNum*/);
EXPECT_EQ(lut.toFirstDayOfNextMonth(time), 4294425600 /*time_t*/); // 2106-02-01
EXPECT_EQ(lut.toFirstDayOfPrevMonth(time), 4289068800 /*time_t*/); // 2105-12-01
EXPECT_EQ(lut.daysInMonth(time), 31 /*UInt8*/);
EXPECT_EQ(lut.toDateAndShift(time, 10), 4295203200 /*time_t*/); // 2106-02-10
EXPECT_EQ(lut.toTime(time), 4673 /*time_t*/);
EXPECT_EQ(lut.toHour(time), 1 /*unsigned*/);
EXPECT_EQ(lut.toMinute(time), 17 /*unsigned*/);
EXPECT_EQ(lut.toSecond(time), 53 /*unsigned*/);
EXPECT_EQ(lut.toStartOfMinute(time), 4294343820 /*time_t*/);
EXPECT_EQ(lut.toStartOfFiveMinute(time), 4294343700 /*time_t*/);
EXPECT_EQ(lut.toStartOfFifteenMinutes(time), 4294343700 /*time_t*/);
EXPECT_EQ(lut.toStartOfTenMinutes(time), 4294343400 /*time_t*/);
EXPECT_EQ(lut.toStartOfHour(time), 4294342800 /*time_t*/);
EXPECT_EQ(lut.toDayNum(time), DayNum(49703) /*DayNum*/);
EXPECT_EQ(lut.toDayOfYear(time), 31 /*unsigned*/);
EXPECT_EQ(lut.toRelativeWeekNum(time), 7100 /*unsigned*/);
EXPECT_EQ(lut.toISOYear(time), 2106 /*unsigned*/);
EXPECT_EQ(lut.toFirstDayNumOfISOYear(time), DayNum(49676) /*DayNum*/); // 2106-01-04
EXPECT_EQ(lut.toFirstDayOfISOYear(time), 4292006400 /*time_t*/);
EXPECT_EQ(lut.toISOWeek(time), 4 /*unsigned*/);
EXPECT_EQ(lut.toRelativeMonthNum(time), 25273 /*unsigned*/);
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*/);
EXPECT_EQ(lut.toNumYYYYMMDD(time), 21060131 /*UInt32*/);
EXPECT_EQ(lut.toNumYYYYMMDDhhmmss(time), 21060131011753 /*UInt64*/);
EXPECT_EQ(lut.addDays(time, 100), 4302983873 /*time_t*/);
EXPECT_EQ(lut.addWeeks(time, 10), 4300391873 /*time_t*/);
EXPECT_EQ(lut.addMonths(time, 10), 4320523073 /*time_t*/); // 2106-11-30 01:17:53
EXPECT_EQ(lut.addQuarters(time, 10), 4373140673 /*time_t*/); // 2108-07-31 01:17:53
EXPECT_EQ(lut.addYears(time, 10), 4609876673 /*time_t*/); // 2116-01-31 01:17:53
EXPECT_EQ(lut.timeToString(time), "2106-01-31 01:17:53" /*std::string*/);
EXPECT_EQ(lut.dateToString(time), "2106-01-31" /*std::string*/);
}
class DateLUT_TimeZone : public ::testing::TestWithParam<const char * /* timezone name */>
{};
TEST_P(DateLUT_TimeZone, DISABLED_LoadAllTimeZones)
{
// There are some assumptions and assertions about TZ data made in DateLUTImpl which are verified upon loading,
// to make sure that those assertions are true for all timezones we are going to load all of them one by one.
DateLUTImpl{GetParam()};
}
// Another long running test, shouldn't be run to often
TEST_P(DateLUT_TimeZone, VaidateTimeComponentsAroundEpoch)
{
// Converting time around 1970-01-01 to hour-minute-seconds time components
// could be problematic.
const size_t max_failures_per_tz = 3;
const auto timezone_name = GetParam();
const auto * test_info = ::testing::UnitTest::GetInstance()->current_test_info();
const auto lut = DateLUTImpl(timezone_name);
for (time_t i = -856147870; i < 86400 * 10000; i += 11 * 13 * 17 * 19)
{
SCOPED_TRACE(::testing::Message()
<< "\n\tTimezone: " << timezone_name
<< "\n\ttimestamp: " << i
<< "\n\t offset at start of epoch : " << lut.getOffsetAtStartOfEpoch()
<< "\n\t offset_is_whole_number_of_hours_everytime : " << lut.getOffsetIsWholNumberOfHoursEveryWhere()
<< "\n\t time_offset_epoch : " << lut.getTimeOffsetEpoch()
<< "\n\t offset_at_start_of_lut : " << lut.getTimeOffsetAtStartOfLUT());
EXPECT_GE(24, lut.toHour(i));
EXPECT_GT(60, lut.toMinute(i));
EXPECT_GT(60, lut.toSecond(i));
const auto current_failures = countFailures(*test_info->result());
if (current_failures.total > 0)
{
if (i < 0)
i = -1;
}
if (current_failures.total >= max_failures_per_tz)
break;
}
}
TEST_P(DateLUT_TimeZone, getTimeZone)
{
const auto & lut = DateLUT::instance(GetParam());
EXPECT_EQ(GetParam(), lut.getTimeZone());
}
TEST_P(DateLUT_TimeZone, ZeroTime)
{
const auto & lut = DateLUT::instance(GetParam());
EXPECT_EQ(0, lut.toDayNum(time_t{0}));
EXPECT_EQ(0, lut.toDayNum(DayNum{0}));
EXPECT_EQ(0, lut.toDayNum(ExtendedDayNum{0}));
}
// Group of tests for timezones that have or had some time ago an offset which is not multiple of 15 minutes.
INSTANTIATE_TEST_SUITE_P(ExoticTimezones,
DateLUT_TimeZone,
::testing::ValuesIn(std::initializer_list<const char*>{
"Africa/El_Aaiun",
"Pacific/Apia",
"Pacific/Enderbury",
"Pacific/Fakaofo",
"Pacific/Kiritimati",
})
);
INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimeZones,
DateLUT_TimeZone,
::testing::ValuesIn(allTimezones())
);
std::ostream & operator<<(std::ostream & ostr, const DateLUTImpl::Values & v)
{
return ostr << "DateLUTImpl::Values{"
<< "\n\t date : " << v.date
<< "\n\t year : " << static_cast<unsigned int>(v.year)
<< "\n\t month : " << static_cast<unsigned int>(v.month)
<< "\n\t day : " << static_cast<unsigned int>(v.day_of_month)
<< "\n\t weekday : " << static_cast<unsigned int>(v.day_of_week)
<< "\n\t days in month : " << static_cast<unsigned int>(v.days_in_month)
<< "\n\t offset change : " << v.amount_of_offset_change()
<< "\n\t offfset change at : " << v.time_at_offset_change()
<< "\n}";
}
struct TimeRangeParam
{
const cctz::civil_second begin;
const cctz::civil_second end;
const int step_in_seconds;
};
std::ostream & operator<<(std::ostream & ostr, const TimeRangeParam & param)
{
const auto approximate_step = [](const int step) -> std::string
{
// Convert seconds to a string of seconds or fractional count of minutes/hours/days.
static const size_t multipliers[] = {1 /*seconds to seconds*/, 60 /*seconds to minutes*/, 60 /*minutes to hours*/, 24 /*hours to days*/, 0 /*terminator*/};
static const char* names[] = {"s", "m", "h", "d", nullptr};
double result = step;
size_t i = 0;
for (; i < sizeof(multipliers)/sizeof(multipliers[0]) && result > multipliers[i]; ++i)
result /= multipliers[i];
char buffer[256] = {'\0'};
std::snprintf(buffer, sizeof(buffer), "%.1f%s", result, names[i - 1]);
return std::string{buffer};
};
return ostr << param.begin << " : " << param.end << " step: " << param.step_in_seconds << "s (" << approximate_step(param.step_in_seconds) << ")";
}
class DateLUT_Timezone_TimeRange : public ::testing::TestWithParam<std::tuple<const char* /*timezone_name*/, TimeRangeParam>>
{};
// refactored test from tests/date_lut3.cpp
TEST_P(DateLUT_Timezone_TimeRange, InRange)
{
// for a time_t values in range [begin, end) to match with reference obtained from cctz:
// compare date and time components: year, month, day, hours, minutes, seconds, formatted time string.
const auto & [timezone_name, range_data] = GetParam();
const auto & [begin, end, step] = range_data;
const auto * test_info = ::testing::UnitTest::GetInstance()->current_test_info();
static const size_t max_failures_per_case = 3;
cctz::time_zone tz;
ASSERT_TRUE(cctz::load_time_zone(timezone_name, &tz));
const auto & lut = DateLUT::instance(timezone_name);
const auto start = cctz::convert(begin, tz).time_since_epoch().count();
const auto stop = cctz::convert(end, tz).time_since_epoch().count();
for (time_t expected_time_t = start; expected_time_t < stop; expected_time_t += step)
{
SCOPED_TRACE(expected_time_t);
const auto tz_time = cctz::convert(std::chrono::system_clock::from_time_t(expected_time_t), tz);
EXPECT_EQ(tz_time.year(), lut.toYear(expected_time_t));
EXPECT_EQ(tz_time.month(), lut.toMonth(expected_time_t));
EXPECT_EQ(tz_time.day(), lut.toDayOfMonth(expected_time_t));
EXPECT_EQ(static_cast<int>(cctz::get_weekday(tz_time)) + 1, lut.toDayOfWeek(expected_time_t)); // tm.tm_wday Sunday is 0, while for DateLUTImpl it is 7
EXPECT_EQ(cctz::get_yearday(tz_time), lut.toDayOfYear(expected_time_t));
EXPECT_EQ(tz_time.hour(), lut.toHour(expected_time_t));
EXPECT_EQ(tz_time.minute(), lut.toMinute(expected_time_t));
EXPECT_EQ(tz_time.second(), lut.toSecond(expected_time_t));
const auto time_string = cctz::format("%E4Y-%m-%d %H:%M:%S", std::chrono::system_clock::from_time_t(expected_time_t), tz);
EXPECT_EQ(time_string, lut.timeToString(expected_time_t));
// it makes sense to let test execute all checks above to simplify debugging,
// but once we've found a bad apple, no need to dig deeper.
if (countFailures(*test_info->result()).total >= max_failures_per_case)
break;
}
}
/** Next tests are disabled due to following reasons:
* 1. They are huge and take enormous amount of time to run
* 2. Current implementation of DateLUTImpl is inprecise and some cases fail and it seems impractical to try to fix those.
* 3. Many failures (~300) were fixed while refactoring, about ~40 remain the same and 3 new introduced:
* "Asia/Gaza"
* "Pacific/Enderbury"
* "Pacific/Kiritimati"
* So it would be tricky to skip knonw failures to allow all unit tests to pass.
*/
INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_Year2010,
DateLUT_Timezone_TimeRange,
::testing::Combine(
::testing::ValuesIn(allTimezones()),
::testing::ValuesIn(std::initializer_list<TimeRangeParam>{
// Values from tests/date_lut3.cpp
{YYYYMMDDToDay(20101031), YYYYMMDDToDay(20101101), 15 * 60},
{YYYYMMDDToDay(20100328), YYYYMMDDToDay(20100330), 15 * 60}
}))
);
INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_Year1970_WHOLE,
DateLUT_Timezone_TimeRange,
::testing::Combine(
::testing::ValuesIn(allTimezones()),
::testing::ValuesIn(std::initializer_list<TimeRangeParam>{
// Values from tests/date_lut3.cpp
{YYYYMMDDToDay(19700101), YYYYMMDDToDay(19701231), 3191 /*53m 11s*/},
}))
);
INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_Year2010_WHOLE,
DateLUT_Timezone_TimeRange,
::testing::Combine(
::testing::ValuesIn(allTimezones()),
::testing::ValuesIn(std::initializer_list<TimeRangeParam>{
// Values from tests/date_lut3.cpp
{YYYYMMDDToDay(20100101), YYYYMMDDToDay(20101231), 3191 /*53m 11s*/},
}))
);
INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_Year2020_WHOLE,
DateLUT_Timezone_TimeRange,
::testing::Combine(
::testing::ValuesIn(allTimezones()),
::testing::ValuesIn(std::initializer_list<TimeRangeParam>{
// Values from tests/date_lut3.cpp
{YYYYMMDDToDay(20200101), YYYYMMDDToDay(20201231), 3191 /*53m 11s*/},
}))
);
INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_PreEpoch,
DateLUT_Timezone_TimeRange,
::testing::Combine(
::testing::ValuesIn(allTimezones()),
::testing::ValuesIn(std::initializer_list<TimeRangeParam>{
{YYYYMMDDToDay(19500101), YYYYMMDDToDay(19600101), 15 * 60},
{YYYYMMDDToDay(19300101), YYYYMMDDToDay(19350101), 11 * 15 * 60}
}))
);
INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_Year1970,
DateLUT_Timezone_TimeRange,
::testing::Combine(
::testing::ValuesIn(allTimezones()),
::testing::ValuesIn(std::initializer_list<TimeRangeParam>{
{YYYYMMDDToDay(19700101), YYYYMMDDToDay(19700201), 15 * 60},
{YYYYMMDDToDay(19700101), YYYYMMDDToDay(19701231), 11 * 13 * 17}
// // 11 was chosen as a number which can't divide product of 2-combinarions of (7, 24, 60),
// // to reduce likelehood of hitting same hour/minute/second values for different days.
// // + 12 is just to make sure that last day is covered fully.
// {0, 0 + 11 * 3600 * 24 + 12, 11},
}))
);

View File

@ -390,7 +390,7 @@ private:
for (auto d : chineseNewYearIndicators)
{
/// Let's celebrate until Lantern Festival
if (d <= days && d + 25u >= days)
if (d <= days && d + 25 >= days)
return true;
else if (d > days)
return false;

View File

@ -50,9 +50,10 @@ inline auto scaleMultiplier(UInt32 scale)
* whole - represents whole part of decimal, can be negative or positive.
* fractional - for fractional part of decimal, always positive.
*/
template <typename T>
template <typename DecimalType>
struct DecimalComponents
{
using T = typename DecimalType::NativeType;
T whole;
T fractional;
};
@ -106,6 +107,15 @@ inline DecimalType decimalFromComponentsWithMultiplier(
return DecimalType(value);
}
template <typename DecimalType>
inline DecimalType decimalFromComponentsWithMultiplier(
const DecimalComponents<DecimalType> & components,
typename DecimalType::NativeType scale_multiplier)
{
return decimalFromComponentsWithMultiplier<DecimalType>(components.whole, components.fractional, scale_multiplier);
}
/** Make a decimal value from whole and fractional components with given scale.
*
* @see `decimalFromComponentsWithMultiplier` for details.
@ -126,7 +136,7 @@ inline DecimalType decimalFromComponents(
*/
template <typename DecimalType>
inline DecimalType decimalFromComponents(
const DecimalComponents<typename DecimalType::NativeType> & components,
const DecimalComponents<DecimalType> & components,
UInt32 scale)
{
return decimalFromComponents<DecimalType>(components.whole, components.fractional, scale);
@ -136,7 +146,7 @@ inline DecimalType decimalFromComponents(
* This is an optimization to reduce number of calls to scaleMultiplier on known scale.
*/
template <typename DecimalType>
inline DecimalComponents<typename DecimalType::NativeType> splitWithScaleMultiplier(
inline DecimalComponents<DecimalType> splitWithScaleMultiplier(
const DecimalType & decimal,
typename DecimalType::NativeType scale_multiplier)
{
@ -151,7 +161,7 @@ inline DecimalComponents<typename DecimalType::NativeType> splitWithScaleMultipl
/// Split decimal into components: whole and fractional part, @see `DecimalComponents` for details.
template <typename DecimalType>
inline DecimalComponents<typename DecimalType::NativeType> split(const DecimalType & decimal, UInt32 scale)
inline DecimalComponents<DecimalType> split(const DecimalType & decimal, UInt32 scale)
{
if (scale == 0)
{

View File

@ -420,8 +420,8 @@ namespace MySQLReplication
UInt32 i24 = 0;
payload.readStrict(reinterpret_cast<char *>(&i24), 3);
DayNum date_day_number = DateLUT::instance().makeDayNum(
static_cast<int>((i24 >> 9) & 0x7fff), static_cast<int>((i24 >> 5) & 0xf), static_cast<int>(i24 & 0x1f));
const DayNum date_day_number{DateLUT::instance().makeDayNum(
static_cast<int>((i24 >> 9) & 0x7fff), static_cast<int>((i24 >> 5) & 0xf), static_cast<int>(i24 & 0x1f)).toUnderType()};
row.push_back(Field(date_day_number.toUnderType()));
break;
@ -443,7 +443,7 @@ namespace MySQLReplication
row.push_back(Field{UInt32(date_time)});
else
{
DB::DecimalUtils::DecimalComponents<DateTime64::NativeType> components{
DB::DecimalUtils::DecimalComponents<DateTime64> components{
static_cast<DateTime64::NativeType>(date_time), 0};
components.fractional = fsp;
@ -462,7 +462,7 @@ namespace MySQLReplication
row.push_back(Field{sec});
else
{
DB::DecimalUtils::DecimalComponents<DateTime64::NativeType> components{
DB::DecimalUtils::DecimalComponents<DateTime64> components{
static_cast<DateTime64::NativeType>(sec), 0};
components.fractional = fsp;

View File

@ -14,7 +14,7 @@ struct DecimalUtilsSplitAndCombineTestParam
Decimal64 decimal_value;
uint8_t scale;
DecimalUtils::DecimalComponents<typename Decimal64::NativeType> components;
DecimalUtils::DecimalComponents<Decimal64> components;
};
std::ostream & operator << (std::ostream & ostr, const DecimalUtilsSplitAndCombineTestParam & param)

View File

@ -270,8 +270,8 @@ namespace
throw Exception{"Type mismatch, expected Timestamp, got type id = " + toString(value.type()) + " for column " + name,
ErrorCodes::TYPE_MISMATCH};
assert_cast<ColumnUInt16 &>(column).getData().push_back(UInt16{DateLUT::instance().toDayNum(
static_cast<const Poco::MongoDB::ConcreteElement<Poco::Timestamp> &>(value).value().epochTime())});
assert_cast<ColumnUInt16 &>(column).getData().push_back(static_cast<UInt16>(DateLUT::instance().toDayNum(
static_cast<const Poco::MongoDB::ConcreteElement<Poco::Timestamp> &>(value).value().epochTime())));
break;
}

View File

@ -48,66 +48,5 @@ public:
bool canBePromoted() const override { return false; }
};
/** Tansform-type wrapper for DateTime64, applies given Transform to DateTime64 value or only to a whole part of it.
*
* Depending on what overloads of Transform::execute() are available, when called with DateTime64 value,
* invokes Transform::execute() with:
* * whole part of DateTime64 value, discarding fractional part.
* * DateTime64 value and scale factor.
*
* Suitable Transfotm-types are commonly used in Date/DateTime manipulation functions,
* and should implement static (or const) function with following signatures:
* R execute(UInt32 whole_value, ... , const TimeZoneImpl &)
* OR
* R execute(DateTime64 value, Int64 scale_factor, ... , const TimeZoneImpl &)
*
* Where R and T could be arbitrary types.
*/
template <typename Transform>
class TransformDateTime64 : public Transform
{
private:
// Detect if Transform::execute is const or static method
// with signature defined by template args (ignoring result type).
template<typename = void, typename... Args>
struct TransformHasExecuteOverload : std::false_type {};
template<typename... Args>
struct TransformHasExecuteOverload<std::void_t<decltype(std::declval<Transform>().execute(std::declval<Args>()...))>, Args...>
: std::true_type {};
template<typename... Args>
static constexpr bool TransformHasExecuteOverload_v = TransformHasExecuteOverload<void, Args...>::value;
public:
static constexpr auto name = Transform::name;
using Transform::execute;
// non-explicit constructor to allow creating from scale value (or with no scale at all), indispensable in some contexts.
TransformDateTime64(UInt32 scale_ = 0)
: scale_multiplier(DecimalUtils::scaleMultiplier<DateTime64::NativeType>(scale_))
{}
template <typename ... Args>
inline auto execute(const DateTime64 & t, Args && ... args) const
{
const auto transform = static_cast<const Transform *>(this);
if constexpr (TransformHasExecuteOverload_v<DateTime64, decltype(scale_multiplier), Args...>)
{
return transform->execute(t, scale_multiplier, std::forward<Args>(args)...);
}
else
{
const auto components = DecimalUtils::splitWithScaleMultiplier(t, scale_multiplier);
return transform->execute(static_cast<UInt32>(components.whole), std::forward<Args>(args)...);
}
}
private:
DateTime64::NativeType scale_multiplier = 1;
};
}

View File

@ -33,14 +33,21 @@ static inline UInt32 dateIsNotSupported(const char * name)
/// This factor transformation will say that the function is monotone everywhere.
struct ZeroTransform
{
static inline UInt16 execute(UInt32, UInt8, const DateLUTImpl &) { return 0; }
static inline UInt16 execute(UInt16, UInt8, const DateLUTImpl &) { return 0; }
static inline UInt16 execute(UInt32, UInt8, const DateLUTImpl &) { return 0; }
static inline UInt16 execute(Int64, UInt8, const DateLUTImpl &) { return 0; }
};
struct ToWeekImpl
{
static constexpr auto name = "toWeek";
static inline UInt8 execute(Int64 t, UInt8 week_mode, const DateLUTImpl & time_zone)
{
// TODO: ditch conversion to DayNum, since it doesn't support extended range.
YearWeek yw = time_zone.toYearWeek(time_zone.toDayNum(t), week_mode);
return yw.second;
}
static inline UInt8 execute(UInt32 t, UInt8 week_mode, const DateLUTImpl & time_zone)
{
YearWeek yw = time_zone.toYearWeek(time_zone.toDayNum(t), week_mode);
@ -59,6 +66,13 @@ struct ToYearWeekImpl
{
static constexpr auto name = "toYearWeek";
static inline UInt32 execute(Int64 t, UInt8 week_mode, const DateLUTImpl & time_zone)
{
// TODO: ditch toDayNum()
YearWeek yw = time_zone.toYearWeek(time_zone.toDayNum(t), week_mode | static_cast<UInt32>(WeekModeFlag::YEAR));
return yw.first * 100 + yw.second;
}
static inline UInt32 execute(UInt32 t, UInt8 week_mode, const DateLUTImpl & time_zone)
{
YearWeek yw = time_zone.toYearWeek(time_zone.toDayNum(t), week_mode | static_cast<UInt32>(WeekModeFlag::YEAR));
@ -77,13 +91,19 @@ struct ToStartOfWeekImpl
{
static constexpr auto name = "toStartOfWeek";
static inline UInt16 execute(Int64 t, UInt8 week_mode, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfWeek(time_zone.toDayNum(t), week_mode);
// return time_zone.toFirstDayNumOfWeek(t, week_mode);
}
static inline UInt16 execute(UInt32 t, UInt8 week_mode, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfWeek(time_zone.toDayNum(t), week_mode);
// return time_zone.toFirstDayNumOfWeek(t, week_mode);
}
static inline UInt16 execute(UInt16 d, UInt8 week_mode, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfWeek(DayNum(d), week_mode);
return time_zone.toFirstDayNumOfWeek(ExtendedDayNum(d), week_mode);
}
using FactorTransform = ZeroTransform;

View File

@ -3,6 +3,7 @@
#include <Core/DecimalFunctions.h>
#include <Common/Exception.h>
#include <common/DateLUTImpl.h>
//#include <common/TimeZone.h>
#include <Columns/ColumnVector.h>
#include <Columns/ColumnDecimal.h>
#include <Functions/FunctionHelpers.h>
@ -33,14 +34,15 @@ namespace ErrorCodes
* factor-transformation F is "round to the nearest month" (2015-02-03 -> 2015-02-01).
*/
static inline UInt32 dateIsNotSupported(const char * name)
{
static inline UInt32 dateIsNotSupported(const char * name)
{
throw Exception("Illegal type Date of argument for function " + std::string(name), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
}
/// This factor transformation will say that the function is monotone everywhere.
struct ZeroTransform
{
static inline UInt16 execute(Int64, const DateLUTImpl &) { return 0; }
static inline UInt16 execute(UInt32, const DateLUTImpl &) { return 0; }
static inline UInt16 execute(UInt16, const DateLUTImpl &) { return 0; }
};
@ -49,6 +51,10 @@ struct ToDateImpl
{
static constexpr auto name = "toDate";
static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone)
{
return UInt16(time_zone.toDayNum(t));
}
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return UInt16(time_zone.toDayNum(t));
@ -65,13 +71,18 @@ struct ToStartOfDayImpl
{
static constexpr auto name = "toStartOfDay";
//TODO: right now it is hardcoded to produce DateTime only, needs fixing later. See date_and_time_type_details::ResultDataTypeMap for deduction of result type example.
static inline UInt32 execute(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
{
return time_zone.toDate(static_cast<time_t>(t.whole));
}
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toDate(t);
}
static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toDate(DayNum(d));
return time_zone.toDate(ExtendedDayNum(d));
}
using FactorTransform = ZeroTransform;
@ -81,13 +92,19 @@ struct ToMondayImpl
{
static constexpr auto name = "toMonday";
static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone)
{
//return time_zone.toFirstDayNumOfWeek(time_zone.toDayNum(t));
return time_zone.toFirstDayNumOfWeek(t);
}
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfWeek(time_zone.toDayNum(t));
//return time_zone.toFirstDayNumOfWeek(time_zone.toDayNum(t));
return time_zone.toFirstDayNumOfWeek(t);
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfWeek(DayNum(d));
return time_zone.toFirstDayNumOfWeek(ExtendedDayNum(d));
}
using FactorTransform = ZeroTransform;
@ -97,13 +114,17 @@ struct ToStartOfMonthImpl
{
static constexpr auto name = "toStartOfMonth";
static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfMonth(time_zone.toDayNum(t));
}
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfMonth(time_zone.toDayNum(t));
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfMonth(DayNum(d));
return time_zone.toFirstDayNumOfMonth(ExtendedDayNum(d));
}
using FactorTransform = ZeroTransform;
@ -113,13 +134,17 @@ struct ToStartOfQuarterImpl
{
static constexpr auto name = "toStartOfQuarter";
static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfQuarter(time_zone.toDayNum(t));
}
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfQuarter(time_zone.toDayNum(t));
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfQuarter(DayNum(d));
return time_zone.toFirstDayNumOfQuarter(ExtendedDayNum(d));
}
using FactorTransform = ZeroTransform;
@ -129,13 +154,17 @@ struct ToStartOfYearImpl
{
static constexpr auto name = "toStartOfYear";
static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfYear(time_zone.toDayNum(t));
}
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfYear(time_zone.toDayNum(t));
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfYear(DayNum(d));
return time_zone.toFirstDayNumOfYear(ExtendedDayNum(d));
}
using FactorTransform = ZeroTransform;
@ -144,9 +173,13 @@ struct ToStartOfYearImpl
struct ToTimeImpl
{
/// When transforming to time, the date will be equated to 1970-01-01.
static constexpr auto name = "toTime";
/// When transforming to time, the date will be equated to 1970-01-02.
static UInt32 execute(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
{
return time_zone.toTime(t.whole) + 86400;
}
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toTime(t) + 86400;
@ -164,6 +197,10 @@ struct ToStartOfMinuteImpl
{
static constexpr auto name = "toStartOfMinute";
static inline UInt32 execute(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfMinute(t.whole);
}
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfMinute(t);
@ -215,6 +252,10 @@ struct ToStartOfFiveMinuteImpl
{
static constexpr auto name = "toStartOfFiveMinute";
static inline UInt32 execute(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfFiveMinute(t.whole);
}
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfFiveMinute(t);
@ -231,6 +272,10 @@ struct ToStartOfTenMinutesImpl
{
static constexpr auto name = "toStartOfTenMinutes";
static inline UInt32 execute(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfTenMinutes(t.whole);
}
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfTenMinutes(t);
@ -247,6 +292,10 @@ struct ToStartOfFifteenMinutesImpl
{
static constexpr auto name = "toStartOfFifteenMinutes";
static inline UInt32 execute(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfFifteenMinutes(t.whole);
}
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfFifteenMinutes(t);
@ -264,6 +313,12 @@ struct TimeSlotImpl
{
static constexpr auto name = "timeSlot";
//static inline DecimalUtils::DecimalComponents<DateTime64> execute(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl &)
static inline UInt32 execute(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl &)
{
return t.whole / 1800 * 1800;
}
static inline UInt32 execute(UInt32 t, const DateLUTImpl &)
{
return t / 1800 * 1800;
@ -281,6 +336,11 @@ struct ToStartOfHourImpl
{
static constexpr auto name = "toStartOfHour";
static inline UInt32 execute(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfHour(t.whole);
}
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfHour(t);
@ -298,13 +358,17 @@ struct ToYearImpl
{
static constexpr auto name = "toYear";
static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toYear(t);
}
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toYear(t);
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toYear(DayNum(d));
return time_zone.toYear(ExtendedDayNum(d));
}
using FactorTransform = ZeroTransform;
@ -314,13 +378,17 @@ struct ToQuarterImpl
{
static constexpr auto name = "toQuarter";
static inline UInt8 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toQuarter(t);
}
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toQuarter(t);
}
static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toQuarter(DayNum(d));
return time_zone.toQuarter(ExtendedDayNum(d));
}
using FactorTransform = ToStartOfYearImpl;
@ -330,13 +398,17 @@ struct ToMonthImpl
{
static constexpr auto name = "toMonth";
static inline UInt8 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toMonth(t);
}
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toMonth(t);
}
static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toMonth(DayNum(d));
return time_zone.toMonth(ExtendedDayNum(d));
}
using FactorTransform = ToStartOfYearImpl;
@ -346,13 +418,17 @@ struct ToDayOfMonthImpl
{
static constexpr auto name = "toDayOfMonth";
static inline UInt8 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toDayOfMonth(t);
}
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toDayOfMonth(t);
}
static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toDayOfMonth(DayNum(d));
return time_zone.toDayOfMonth(ExtendedDayNum(d));
}
using FactorTransform = ToStartOfMonthImpl;
@ -362,13 +438,17 @@ struct ToDayOfWeekImpl
{
static constexpr auto name = "toDayOfWeek";
static inline UInt8 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toDayOfWeek(t);
}
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toDayOfWeek(t);
}
static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toDayOfWeek(DayNum(d));
return time_zone.toDayOfWeek(ExtendedDayNum(d));
}
using FactorTransform = ToMondayImpl;
@ -378,13 +458,17 @@ struct ToDayOfYearImpl
{
static constexpr auto name = "toDayOfYear";
static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toDayOfYear(t);
}
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toDayOfYear(t);
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toDayOfYear(DayNum(d));
return time_zone.toDayOfYear(ExtendedDayNum(d));
}
using FactorTransform = ToStartOfYearImpl;
@ -394,6 +478,10 @@ struct ToHourImpl
{
static constexpr auto name = "toHour";
static inline UInt8 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toHour(t);
}
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toHour(t);
@ -411,6 +499,11 @@ struct TimezoneOffsetImpl
{
static constexpr auto name = "timezoneOffset";
static inline time_t execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.timezoneOffset(t);
}
static inline time_t execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.timezoneOffset(t);
@ -428,6 +521,10 @@ struct ToMinuteImpl
{
static constexpr auto name = "toMinute";
static inline UInt8 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toMinute(t);
}
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toMinute(t);
@ -444,6 +541,10 @@ struct ToSecondImpl
{
static constexpr auto name = "toSecond";
static inline UInt8 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toSecond(t);
}
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toSecond(t);
@ -460,13 +561,17 @@ struct ToISOYearImpl
{
static constexpr auto name = "toISOYear";
static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toISOYear(time_zone.toDayNum(t));
}
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toISOYear(time_zone.toDayNum(t));
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toISOYear(DayNum(d));
return time_zone.toISOYear(ExtendedDayNum(d));
}
using FactorTransform = ZeroTransform;
@ -476,13 +581,17 @@ struct ToStartOfISOYearImpl
{
static constexpr auto name = "toStartOfISOYear";
static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfISOYear(time_zone.toDayNum(t));
}
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfISOYear(time_zone.toDayNum(t));
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toFirstDayNumOfISOYear(DayNum(d));
return time_zone.toFirstDayNumOfISOYear(ExtendedDayNum(d));
}
using FactorTransform = ZeroTransform;
@ -492,13 +601,17 @@ struct ToISOWeekImpl
{
static constexpr auto name = "toISOWeek";
static inline UInt8 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toISOWeek(time_zone.toDayNum(t));
}
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toISOWeek(time_zone.toDayNum(t));
}
static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toISOWeek(DayNum(d));
return time_zone.toISOWeek(ExtendedDayNum(d));
}
using FactorTransform = ToISOYearImpl;
@ -508,13 +621,17 @@ struct ToRelativeYearNumImpl
{
static constexpr auto name = "toRelativeYearNum";
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toYear(t);
}
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toYear(static_cast<time_t>(t));
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toYear(DayNum(d));
return time_zone.toYear(ExtendedDayNum(d));
}
using FactorTransform = ZeroTransform;
@ -524,13 +641,17 @@ struct ToRelativeQuarterNumImpl
{
static constexpr auto name = "toRelativeQuarterNum";
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toRelativeQuarterNum(t);
}
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toRelativeQuarterNum(static_cast<time_t>(t));
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toRelativeQuarterNum(DayNum(d));
return time_zone.toRelativeQuarterNum(ExtendedDayNum(d));
}
using FactorTransform = ZeroTransform;
@ -540,13 +661,17 @@ struct ToRelativeMonthNumImpl
{
static constexpr auto name = "toRelativeMonthNum";
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toRelativeMonthNum(t);
}
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toRelativeMonthNum(static_cast<time_t>(t));
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toRelativeMonthNum(DayNum(d));
return time_zone.toRelativeMonthNum(ExtendedDayNum(d));
}
using FactorTransform = ZeroTransform;
@ -556,13 +681,17 @@ struct ToRelativeWeekNumImpl
{
static constexpr auto name = "toRelativeWeekNum";
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toRelativeWeekNum(t);
}
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toRelativeWeekNum(static_cast<time_t>(t));
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toRelativeWeekNum(DayNum(d));
return time_zone.toRelativeWeekNum(ExtendedDayNum(d));
}
using FactorTransform = ZeroTransform;
@ -572,10 +701,14 @@ struct ToRelativeDayNumImpl
{
static constexpr auto name = "toRelativeDayNum";
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toDayNum(t);
}
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toDayNum(static_cast<time_t>(t));
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl &)
{
return static_cast<DayNum>(d);
@ -589,13 +722,17 @@ struct ToRelativeHourNumImpl
{
static constexpr auto name = "toRelativeHourNum";
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
static inline UInt32 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toRelativeHourNum(t);
}
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toRelativeHourNum(static_cast<time_t>(t));
}
static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toRelativeHourNum(DayNum(d));
return time_zone.toRelativeHourNum(ExtendedDayNum(d));
}
using FactorTransform = ZeroTransform;
@ -605,13 +742,17 @@ struct ToRelativeMinuteNumImpl
{
static constexpr auto name = "toRelativeMinuteNum";
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
static inline UInt32 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toRelativeMinuteNum(t);
}
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toRelativeMinuteNum(static_cast<time_t>(t));
}
static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toRelativeMinuteNum(DayNum(d));
return time_zone.toRelativeMinuteNum(ExtendedDayNum(d));
}
using FactorTransform = ZeroTransform;
@ -621,13 +762,17 @@ struct ToRelativeSecondNumImpl
{
static constexpr auto name = "toRelativeSecondNum";
static inline Int64 execute(Int64 t, const DateLUTImpl &)
{
return t;
}
static inline UInt32 execute(UInt32 t, const DateLUTImpl &)
{
return t;
}
static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.fromDayNum(DayNum(d));
return time_zone.fromDayNum(ExtendedDayNum(d));
}
using FactorTransform = ZeroTransform;
@ -637,6 +782,10 @@ struct ToYYYYMMImpl
{
static constexpr auto name = "toYYYYMM";
static inline UInt32 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toNumYYYYMM(t);
}
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toNumYYYYMM(t);
@ -653,6 +802,10 @@ struct ToYYYYMMDDImpl
{
static constexpr auto name = "toYYYYMMDD";
static inline UInt32 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toNumYYYYMMDD(t);
}
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toNumYYYYMMDD(t);
@ -669,6 +822,10 @@ struct ToYYYYMMDDhhmmssImpl
{
static constexpr auto name = "toYYYYMMDDhhmmss";
static inline UInt64 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toNumYYYYMMDDhhmmss(t);
}
static inline UInt64 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toNumYYYYMMDDhhmmss(t);

View File

@ -4,6 +4,7 @@
#include <DataTypes/DataTypeDateTime64.h>
#include <Functions/CustomWeekTransforms.h>
#include <Functions/IFunctionImpl.h>
#include <Functions/TransformDateTime64.h>
#include <Functions/extractTimeZoneFromFunctionArguments.h>
#include <IO/WriteHelpers.h>

View File

@ -11,6 +11,7 @@
#include <Functions/FunctionHelpers.h>
#include <Functions/castTypeToEither.h>
#include <Functions/extractTimeZoneFromFunctionArguments.h>
#include <Functions/TransformDateTime64.h>
#include <IO/WriteHelpers.h>
@ -25,31 +26,6 @@ namespace ErrorCodes
extern const int ILLEGAL_COLUMN;
}
/// AddOnDateTime64DefaultImpl provides default implementation of add-X functionality for DateTime64.
///
/// Default implementation is not to change fractional part, but only modify whole part as if it was DateTime.
/// That means large whole values (for scale less than 9) might not fit into UInt32-range,
/// and hence default implementation will produce incorrect results.
template <typename T>
struct AddOnDateTime64DefaultImpl
{
AddOnDateTime64DefaultImpl(UInt32 scale_ = 0)
: scale_multiplier(DecimalUtils::scaleMultiplier<DateTime64::NativeType>(scale_))
{}
// Default implementation for add/sub on DateTime64: do math on whole part (the same way as for DateTime), leave fractional as it is.
inline DateTime64 execute(const DateTime64 & t, Int64 delta, const DateLUTImpl & time_zone) const
{
const auto components = DecimalUtils::splitWithScaleMultiplier(t, scale_multiplier);
const auto whole = static_cast<const T *>(this)->execute(static_cast<UInt32>(components.whole), delta, time_zone);
return DecimalUtils::decimalFromComponentsWithMultiplier<DateTime64>(static_cast<DateTime64::NativeType>(whole), components.fractional, scale_multiplier);
}
UInt32 scale_multiplier = 1;
};
/// Type of first argument of 'execute' function overload defines what INPUT DataType it is used for.
/// Return type defines what is the OUTPUT (return) type of the CH function.
/// Corresponding types:
@ -60,14 +36,15 @@ struct AddOnDateTime64DefaultImpl
/// - 'AddSecondsImpl::execute(UInt32, ...) -> UInt32' is available to the ClickHouse users as 'addSeconds(DateTime, ...) -> DateTime'
/// - 'AddSecondsImpl::execute(UInt16, ...) -> UInt32' is available to the ClickHouse users as 'addSeconds(Date, ...) -> DateTime'
struct AddSecondsImpl : public AddOnDateTime64DefaultImpl<AddSecondsImpl>
struct AddSecondsImpl
{
using Base = AddOnDateTime64DefaultImpl<AddSecondsImpl>;
using Base::Base;
using Base::execute;
static constexpr auto name = "addSeconds";
static inline NO_SANITIZE_UNDEFINED DecimalUtils::DecimalComponents<DateTime64> execute(DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl &)
{
return {t.whole + delta, t.fractional};
}
static inline NO_SANITIZE_UNDEFINED UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl &)
{
return t + delta;
@ -75,18 +52,19 @@ struct AddSecondsImpl : public AddOnDateTime64DefaultImpl<AddSecondsImpl>
static inline NO_SANITIZE_UNDEFINED UInt32 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.fromDayNum(DayNum(d)) + delta;
return time_zone.fromDayNum(ExtendedDayNum(d)) + delta;
}
};
struct AddMinutesImpl : public AddOnDateTime64DefaultImpl<AddMinutesImpl>
struct AddMinutesImpl
{
using Base = AddOnDateTime64DefaultImpl<AddMinutesImpl>;
using Base::Base;
using Base::execute;
static constexpr auto name = "addMinutes";
static inline NO_SANITIZE_UNDEFINED DecimalUtils::DecimalComponents<DateTime64> execute(DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl &)
{
return {t.whole + delta * 60, t.fractional};
}
static inline NO_SANITIZE_UNDEFINED UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl &)
{
return t + delta * 60;
@ -94,18 +72,18 @@ struct AddMinutesImpl : public AddOnDateTime64DefaultImpl<AddMinutesImpl>
static inline NO_SANITIZE_UNDEFINED UInt32 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.fromDayNum(DayNum(d)) + delta * 60;
return time_zone.fromDayNum(ExtendedDayNum(d)) + delta * 60;
}
};
struct AddHoursImpl : public AddOnDateTime64DefaultImpl<AddHoursImpl>
struct AddHoursImpl
{
using Base = AddOnDateTime64DefaultImpl<AddHoursImpl>;
using Base::Base;
using Base::execute;
static constexpr auto name = "addHours";
static inline NO_SANITIZE_UNDEFINED DecimalUtils::DecimalComponents<DateTime64> execute(DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl &)
{
return {t.whole + delta * 3600, t.fractional};
}
static inline NO_SANITIZE_UNDEFINED UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl &)
{
return t + delta * 3600;
@ -113,19 +91,20 @@ struct AddHoursImpl : public AddOnDateTime64DefaultImpl<AddHoursImpl>
static inline NO_SANITIZE_UNDEFINED UInt32 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.fromDayNum(DayNum(d)) + delta * 3600;
return time_zone.fromDayNum(ExtendedDayNum(d)) + delta * 3600;
}
};
struct AddDaysImpl : public AddOnDateTime64DefaultImpl<AddDaysImpl>
struct AddDaysImpl
{
using Base = AddOnDateTime64DefaultImpl<AddDaysImpl>;
using Base::Base;
using Base::execute;
static constexpr auto name = "addDays";
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
static inline NO_SANITIZE_UNDEFINED DecimalUtils::DecimalComponents<DateTime64> execute(DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl & time_zone)
{
return {time_zone.addDays(t.whole, delta), t.fractional};
}
static inline NO_SANITIZE_UNDEFINED UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.addDays(t, delta);
}
@ -136,14 +115,15 @@ struct AddDaysImpl : public AddOnDateTime64DefaultImpl<AddDaysImpl>
}
};
struct AddWeeksImpl : public AddOnDateTime64DefaultImpl<AddWeeksImpl>
struct AddWeeksImpl
{
using Base = AddOnDateTime64DefaultImpl<AddWeeksImpl>;
using Base::Base;
using Base::execute;
static constexpr auto name = "addWeeks";
static inline NO_SANITIZE_UNDEFINED DecimalUtils::DecimalComponents<DateTime64> execute(DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl & time_zone)
{
return {time_zone.addWeeks(t.whole, delta), t.fractional};
}
static inline NO_SANITIZE_UNDEFINED UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.addWeeks(t, delta);
@ -155,14 +135,15 @@ struct AddWeeksImpl : public AddOnDateTime64DefaultImpl<AddWeeksImpl>
}
};
struct AddMonthsImpl : public AddOnDateTime64DefaultImpl<AddMonthsImpl>
struct AddMonthsImpl
{
using Base = AddOnDateTime64DefaultImpl<AddMonthsImpl>;
using Base::Base;
using Base::execute;
static constexpr auto name = "addMonths";
static inline DecimalUtils::DecimalComponents<DateTime64> execute(DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl & time_zone)
{
return {time_zone.addMonths(t.whole, delta), t.fractional};
}
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.addMonths(t, delta);
@ -170,18 +151,19 @@ struct AddMonthsImpl : public AddOnDateTime64DefaultImpl<AddMonthsImpl>
static inline UInt16 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.addMonths(DayNum(d), delta);
return time_zone.addMonths(ExtendedDayNum(d), delta);
}
};
struct AddQuartersImpl : public AddOnDateTime64DefaultImpl<AddQuartersImpl>
struct AddQuartersImpl
{
using Base = AddOnDateTime64DefaultImpl<AddQuartersImpl>;
using Base::Base;
using Base::execute;
static constexpr auto name = "addQuarters";
static inline DecimalUtils::DecimalComponents<DateTime64> execute(DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl & time_zone)
{
return {time_zone.addQuarters(t.whole, delta), t.fractional};
}
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.addQuarters(t, delta);
@ -189,18 +171,19 @@ struct AddQuartersImpl : public AddOnDateTime64DefaultImpl<AddQuartersImpl>
static inline UInt16 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.addQuarters(DayNum(d), delta);
return time_zone.addQuarters(ExtendedDayNum(d), delta);
}
};
struct AddYearsImpl : public AddOnDateTime64DefaultImpl<AddYearsImpl>
struct AddYearsImpl
{
using Base = AddOnDateTime64DefaultImpl<AddYearsImpl>;
using Base::Base;
using Base::execute;
static constexpr auto name = "addYears";
static inline DecimalUtils::DecimalComponents<DateTime64> execute(DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl & time_zone)
{
return {time_zone.addYears(t.whole, delta), t.fractional};
}
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.addYears(t, delta);
@ -208,7 +191,7 @@ struct AddYearsImpl : public AddOnDateTime64DefaultImpl<AddYearsImpl>
static inline UInt16 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.addYears(DayNum(d), delta);
return time_zone.addYears(ExtendedDayNum(d), delta);
}
};
@ -351,6 +334,7 @@ template <> struct ResultDataTypeMap<Int16> { using ResultDataType = DataTy
template <> struct ResultDataTypeMap<UInt32> { using ResultDataType = DataTypeDateTime; };
template <> struct ResultDataTypeMap<Int32> { using ResultDataType = DataTypeDateTime; };
template <> struct ResultDataTypeMap<DateTime64> { using ResultDataType = DataTypeDateTime64; };
template <> struct ResultDataTypeMap<Int64> { using ResultDataType = DataTypeDateTime64; };
}
template <typename Transform>
@ -417,10 +401,18 @@ public:
}
}
// TransformDateTime64 helps choosing correct overload of exec and does some transformations
// on input and output parameters to simplify support of DateTime64 in concrete Transform.
template <typename FieldType>
using TransformType = std::conditional_t<
std::is_same_v<FieldType, DateTime64>,
TransformDateTime64<Transform>,
Transform>;
/// Helper templates to deduce return type based on argument type, since some overloads may promote or denote types,
/// e.g. addSeconds(Date, 1) => DateTime
template <typename FieldType>
using TransformExecuteReturnType = decltype(std::declval<Transform>().execute(FieldType(), 0, std::declval<DateLUTImpl>()));
using TransformExecuteReturnType = decltype(std::declval<TransformType<FieldType>>().execute(FieldType(), 0, std::declval<DateLUTImpl>()));
// Deduces RETURN DataType from INPUT DataType, based on return type of Transform{}.execute(INPUT_TYPE, UInt64, DateLUTImpl).
// e.g. for Transform-type that has execute()-overload with 'UInt16' input and 'UInt32' return,
@ -475,8 +467,9 @@ public:
}
else if (const auto * datetime64_type = assert_cast<const DataTypeDateTime64 *>(from_type))
{
return DateTimeAddIntervalImpl<DataTypeDateTime64, TransformResultDataType<DataTypeDateTime64>, Transform>::execute(
Transform{datetime64_type->getScale()}, arguments, result_type);
using WrappedTransformType = TransformType<typename DataTypeDateTime64::FieldType>;
return DateTimeAddIntervalImpl<DataTypeDateTime64, TransformResultDataType<DataTypeDateTime64>, WrappedTransformType>::execute(
WrappedTransformType{datetime64_type->getScale()}, arguments, result_type);
}
else
throw Exception("Illegal type " + arguments[0].type->getName() + " of first argument of function " + getName(),

View File

@ -5,6 +5,7 @@
#include <DataTypes/DataTypeDateTime64.h>
#include <Functions/extractTimeZoneFromFunctionArguments.h>
#include <Functions/DateTimeTransforms.h>
#include <Functions/TransformDateTime64.h>
#include <IO/WriteHelpers.h>
@ -107,6 +108,7 @@ public:
else if (which.isDateTime64())
{
const auto scale = static_cast<const DataTypeDateTime64 *>(from_type)->getScale();
const TransformDateTime64<Transform> transformer(scale);
return DateTimeTransformImpl<DataTypeDateTime64, ToDataType, decltype(transformer)>::execute(arguments, result_type, input_rows_count, transformer);
}
@ -133,7 +135,6 @@ public:
/// This method is called only if the function has one argument. Therefore, we do not care about the non-local time zone.
const DateLUTImpl & date_lut = DateLUT::instance();
if (left.isNull() || right.isNull())
return is_not_monotonic;

View File

@ -44,6 +44,7 @@
#include <Functions/FunctionHelpers.h>
#include <Functions/DateTimeTransforms.h>
#include <Functions/toFixedString.h>
#include <Functions/TransformDateTime64.h>
#include <DataTypes/DataTypeLowCardinality.h>
#include <Columns/ColumnLowCardinality.h>
#include <Interpreters/Context.h>
@ -310,10 +311,15 @@ struct ToDateTimeImpl
return time_zone.fromDayNum(DayNum(d));
}
// no-op conversion from DateTime to DateTime, used in DateTime64 to DateTime conversion.
static inline UInt32 execute(UInt32 d, const DateLUTImpl & /*time_zone*/)
static inline UInt32 execute(UInt32 dt, const DateLUTImpl & /*time_zone*/)
{
return d;
return dt;
}
// TODO: return UInt32 ???
static inline Int64 execute(Int64 dt64, const DateLUTImpl & /*time_zone*/)
{
return dt64;
}
};
@ -329,6 +335,7 @@ struct ToDateTransform32Or64
static inline NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl & time_zone)
{
// since converting to Date, no need in values outside of default LUT range.
return (from < 0xFFFF)
? from
: time_zone.toDayNum(std::min(time_t(from), time_t(0xFFFFFFFF)));
@ -342,6 +349,7 @@ struct ToDateTransform32Or64Signed
static inline NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl & time_zone)
{
// TODO: decide narrow or extended range based on FromType
/// The function should be monotonic (better for query optimizations), so we saturate instead of overflow.
if (from < 0)
return 0;
@ -447,35 +455,8 @@ template <typename Name> struct ConvertImpl<DataTypeFloat32, DataTypeDateTime, N
template <typename Name> struct ConvertImpl<DataTypeFloat64, DataTypeDateTime, Name>
: DateTimeTransformImpl<DataTypeFloat64, DataTypeDateTime, ToDateTimeTransform64Signed<Float64, UInt32>> {};
/** Conversion of Date or DateTime to DateTime64: add zero sub-second part.
*/
struct ToDateTime64Transform
{
static constexpr auto name = "toDateTime64";
const DateTime64::NativeType scale_multiplier = 1;
ToDateTime64Transform(UInt32 scale = 0)
: scale_multiplier(DecimalUtils::scaleMultiplier<DateTime64::NativeType>(scale))
{}
inline DateTime64::NativeType execute(UInt16 d, const DateLUTImpl & time_zone) const
{
const auto dt = ToDateTimeImpl::execute(d, time_zone);
return execute(dt, time_zone);
}
inline DateTime64::NativeType execute(UInt32 dt, const DateLUTImpl & /*time_zone*/) const
{
return DecimalUtils::decimalFromComponentsWithMultiplier<DateTime64>(dt, 0, scale_multiplier);
}
};
template <typename Name> struct ConvertImpl<DataTypeDate, DataTypeDateTime64, Name, ConvertDefaultBehaviorTag>
: DateTimeTransformImpl<DataTypeDate, DataTypeDateTime64, ToDateTime64Transform> {};
template <typename Name> struct ConvertImpl<DataTypeDateTime, DataTypeDateTime64, Name, ConvertDefaultBehaviorTag>
: DateTimeTransformImpl<DataTypeDateTime, DataTypeDateTime64, ToDateTime64Transform> {};
const time_t LUT_MIN_TIME = -1420070400l; // 1925-01-01 UTC
const time_t LUT_MAX_TIME = 9877248000l; // 2282-12-31 UTC
/** Conversion of numeric to DateTime64
*/
@ -493,7 +474,7 @@ struct ToDateTime64TransformUnsigned
inline NO_SANITIZE_UNDEFINED DateTime64::NativeType execute(FromType from, const DateLUTImpl &) const
{
from = std::min(time_t(from), time_t(0xFFFFFFFF));
from = std::min<time_t>(from, LUT_MAX_TIME);
return DecimalUtils::decimalFromComponentsWithMultiplier<DateTime64>(from, 0, scale_multiplier);
}
};
@ -510,9 +491,8 @@ struct ToDateTime64TransformSigned
inline NO_SANITIZE_UNDEFINED DateTime64::NativeType execute(FromType from, const DateLUTImpl &) const
{
if (from < 0)
return 0;
from = std::min(time_t(from), time_t(0xFFFFFFFF));
from = std::max<time_t>(from, LUT_MIN_TIME);
from = std::min<time_t>(from, LUT_MAX_TIME);
return DecimalUtils::decimalFromComponentsWithMultiplier<DateTime64>(from, 0, scale_multiplier);
}
};
@ -551,6 +531,7 @@ template <typename Name> struct ConvertImpl<DataTypeFloat32, DataTypeDateTime64,
template <typename Name> struct ConvertImpl<DataTypeFloat64, DataTypeDateTime64, Name>
: DateTimeTransformImpl<DataTypeFloat64, DataTypeDateTime64, ToDateTime64TransformFloat<DataTypeFloat64, Float64>> {};
/** Conversion of DateTime64 to Date or DateTime: discards fractional part.
*/
template <typename Transform>
@ -571,10 +552,41 @@ struct FromDateTime64Transform
}
};
/** Conversion of DateTime64 to Date or DateTime: discards fractional part.
*/
template <typename Name> struct ConvertImpl<DataTypeDateTime64, DataTypeDate, Name, ConvertDefaultBehaviorTag>
: DateTimeTransformImpl<DataTypeDateTime64, DataTypeDate, FromDateTime64Transform<ToDateImpl>> {};
: DateTimeTransformImpl<DataTypeDateTime64, DataTypeDate, TransformDateTime64<ToDateImpl>> {};
template <typename Name> struct ConvertImpl<DataTypeDateTime64, DataTypeDateTime, Name, ConvertDefaultBehaviorTag>
: DateTimeTransformImpl<DataTypeDateTime64, DataTypeDateTime, FromDateTime64Transform<ToDateTimeImpl>> {};
: DateTimeTransformImpl<DataTypeDateTime64, DataTypeDateTime, TransformDateTime64<ToDateTimeImpl>> {};
struct ToDateTime64Transform
{
static constexpr auto name = "toDateTime64";
const DateTime64::NativeType scale_multiplier = 1;
ToDateTime64Transform(UInt32 scale = 0)
: scale_multiplier(DecimalUtils::scaleMultiplier<DateTime64::NativeType>(scale))
{}
inline DateTime64::NativeType execute(UInt16 d, const DateLUTImpl & time_zone) const
{
const auto dt = ToDateTimeImpl::execute(d, time_zone);
return execute(dt, time_zone);
}
inline DateTime64::NativeType execute(UInt32 dt, const DateLUTImpl & /*time_zone*/) const
{
return DecimalUtils::decimalFromComponentsWithMultiplier<DateTime64>(dt, 0, scale_multiplier);
}
};
/** Conversion of Date or DateTime to DateTime64: add zero sub-second part.
*/
template <typename Name> struct ConvertImpl<DataTypeDate, DataTypeDateTime64, Name, ConvertDefaultBehaviorTag>
: DateTimeTransformImpl<DataTypeDate, DataTypeDateTime64, ToDateTime64Transform> {};
template <typename Name> struct ConvertImpl<DataTypeDateTime, DataTypeDateTime64, Name, ConvertDefaultBehaviorTag>
: DateTimeTransformImpl<DataTypeDateTime, DataTypeDateTime64, ToDateTime64Transform> {};
/** Transformation of numbers, dates, datetimes to strings: through formatting.
@ -658,7 +670,6 @@ struct ConvertImpl<FromDataType, std::enable_if_t<!std::is_same_v<FromDataType,
const auto & type = static_cast<const FromDataType &>(*col_with_type_and_name.type);
const DateLUTImpl * time_zone = nullptr;
/// For argument of DateTime type, second argument with time zone could be specified.
if constexpr (std::is_same_v<FromDataType, DataTypeDateTime> || std::is_same_v<FromDataType, DataTypeDateTime64>)
time_zone = &extractTimeZoneFromFunctionArguments(arguments, 1, 0);
@ -754,6 +765,7 @@ inline void parseImpl<DataTypeDate>(DataTypeDate::FieldType & x, ReadBuffer & rb
x = tmp;
}
// NOTE: no need of extra overload of DateTime64, since readDateTimeText64 has different signature and that case is explicitly handled in the calling code.
template <>
inline void parseImpl<DataTypeDateTime>(DataTypeDateTime::FieldType & x, ReadBuffer & rb, const DateLUTImpl * time_zone)
{
@ -762,6 +774,7 @@ inline void parseImpl<DataTypeDateTime>(DataTypeDateTime::FieldType & x, ReadBuf
x = tmp;
}
template <>
inline void parseImpl<DataTypeUUID>(DataTypeUUID::FieldType & x, ReadBuffer & rb, const DateLUTImpl *)
{
@ -988,11 +1001,20 @@ struct ConvertThroughParsing
}
}
else if constexpr (parsing_mode == ConvertFromStringParsingMode::BestEffortUS)
{
if constexpr (to_datetime64)
{
DateTime64 res = 0;
parseDateTime64BestEffortUS(res, vec_to.getScale(), read_buffer, *local_time_zone, *utc_time_zone);
vec_to[i] = res;
}
else
{
time_t res;
parseDateTimeBestEffortUS(res, read_buffer, *local_time_zone, *utc_time_zone);
vec_to[i] = res;
}
}
else
{
if constexpr (to_datetime64)

View File

@ -0,0 +1,92 @@
#pragma once
#include <Core/Types.h>
#include <Core/DecimalFunctions.h>
namespace DB
{
/** Tansform-type wrapper for DateTime64, simplifies DateTime64 support for given Transform.
*
* Depending on what overloads of Transform::execute() are available, when called with DateTime64 value,
* invokes Transform::execute() with either:
* * whole part of DateTime64 value, discarding fractional part (1)
* * DateTime64 value and scale factor (2)
* * DateTime64 broken down to components, result of execute is then re-assembled back into DateTime64 value (3)
*
* Suitable Transfotm-types are commonly used in Date/DateTime manipulation functions,
* and should implement static (or const) function with following signatures:
* 1:
* R execute(Int64 whole_value, ... )
* 2:
* R execute(DateTime64 value, Int64 scale_multiplier, ... )
* 3:
* R execute(DecimalUtils::DecimalComponents<DateTime64> components, ... )
*
* Where R could be of arbitrary type, in case of (3) if R is DecimalUtils::DecimalComponents<DateTime64>, result is re-assembed back into DateTime64.
*/
template <typename Transform>
class TransformDateTime64
{
private:
// Detect if Transform::execute is const or static method
// with signature defined by template args (ignoring result type).
template<typename = void, typename... Args>
struct TransformHasExecuteOverload : std::false_type {};
template<typename... Args>
struct TransformHasExecuteOverload<std::void_t<decltype(std::declval<Transform>().execute(std::declval<Args>()...))>, Args...>
: std::true_type {};
template<typename... Args>
static constexpr bool TransformHasExecuteOverload_v = TransformHasExecuteOverload<void, Args...>::value;
public:
static constexpr auto name = Transform::name;
// non-explicit constructor to allow creating from scale value (or with no scale at all), indispensable in some contexts.
TransformDateTime64(UInt32 scale_ = 0)
: scale_multiplier(DecimalUtils::scaleMultiplier<DateTime64::NativeType>(scale_))
{}
template <typename ... Args>
inline auto execute(const DateTime64 & t, Args && ... args) const
{
if constexpr (TransformHasExecuteOverload_v<DateTime64, decltype(scale_multiplier), Args...>)
{
return wrapped_transform.execute(t, scale_multiplier, std::forward<Args>(args)...);
}
else if constexpr (TransformHasExecuteOverload_v<DecimalUtils::DecimalComponents<DateTime64>, Args...>)
{
auto components = DecimalUtils::splitWithScaleMultiplier(t, scale_multiplier);
const auto result = wrapped_transform.execute(components, std::forward<Args>(args)...);
using ResultType = std::decay_t<decltype(result)>;
if constexpr (std::is_same_v<DecimalUtils::DecimalComponents<DateTime64>, ResultType>)
{
return DecimalUtils::decimalFromComponentsWithMultiplier<DateTime64>(result, scale_multiplier);
}
else
{
return result;
}
}
else
{
const auto components = DecimalUtils::splitWithScaleMultiplier(t, scale_multiplier);
return wrapped_transform.execute(static_cast<Int64>(components.whole), std::forward<Args>(args)...);
}
}
template <typename T, typename ... Args, typename = std::enable_if_t<std::negation_v<std::is_same_v<T, DateTime64>>>>
inline auto execute(const T & t, Args && ... args) const
{
return wrapped_transform.execute(t, std::forward<Args>(args)...);
}
private:
DateTime64::NativeType scale_multiplier = 1;
Transform wrapped_transform = {};
};
}

View File

@ -97,8 +97,8 @@ public:
size_t rows = input_rows_count;
auto res = ColumnInt64::create(rows);
const DateLUTImpl & timezone_x = extractTimeZoneFromFunctionArguments(arguments, 3, 1);
const DateLUTImpl & timezone_y = extractTimeZoneFromFunctionArguments(arguments, 3, 2);
const auto & timezone_x = extractTimeZoneFromFunctionArguments(arguments, 3, 1);
const auto & timezone_y = extractTimeZoneFromFunctionArguments(arguments, 3, 2);
if (unit == "year" || unit == "yy" || unit == "yyyy")
dispatchForColumns<ToRelativeYearNumImpl>(x, y, timezone_x, timezone_y, res->getData());

View File

@ -66,10 +66,11 @@ const DateLUTImpl & extractTimeZoneFromFunctionArguments(const ColumnsWithTypeAn
if (arguments.empty())
return DateLUT::instance();
const auto & dt_arg = arguments[datetime_arg_num].type.get();
/// If time zone is attached to an argument of type DateTime.
if (const auto * type = checkAndGetDataType<DataTypeDateTime>(arguments[datetime_arg_num].type.get()))
if (const auto * type = checkAndGetDataType<DataTypeDateTime>(dt_arg))
return type->getTimeZone();
if (const auto * type = checkAndGetDataType<DataTypeDateTime64>(arguments[datetime_arg_num].type.get()))
if (const auto * type = checkAndGetDataType<DataTypeDateTime64>(dt_arg))
return type->getTimeZone();
return DateLUT::instance();

View File

@ -46,9 +46,8 @@ template <> struct ActionValueTypeMap<DataTypeInt64> { using ActionValueTyp
template <> struct ActionValueTypeMap<DataTypeUInt64> { using ActionValueType = UInt32; };
template <> struct ActionValueTypeMap<DataTypeDate> { using ActionValueType = UInt16; };
template <> struct ActionValueTypeMap<DataTypeDateTime> { using ActionValueType = UInt32; };
// TODO(vnemkov): once there is support for Int64 in LUT, make that Int64.
// TODO(vnemkov): to add sub-second format instruction, make that DateTime64 and do some math in Action<T>.
template <> struct ActionValueTypeMap<DataTypeDateTime64> { using ActionValueType = UInt32; };
template <> struct ActionValueTypeMap<DataTypeDateTime64> { using ActionValueType = Int64; };
/** formatDateTime(time, 'pattern')
@ -434,7 +433,6 @@ public:
time_zone_tmp = &DateLUT::instance();
const DateLUTImpl & time_zone = *time_zone_tmp;
const auto & vec = times->getData();
UInt32 scale [[maybe_unused]] = 0;
@ -519,6 +517,8 @@ public:
{
if constexpr (std::is_same_v<T, UInt32>)
instructions.emplace_back(func, shift);
else if constexpr (std::is_same_v<T, Int64>)
instructions.emplace_back(func, shift);
else
add_shift(shift);
};

View File

@ -30,7 +30,7 @@ Field nowSubsecond(UInt32 scale)
if (clock_gettime(CLOCK_REALTIME, &spec))
throwFromErrno("Cannot clock_gettime.", ErrorCodes::CANNOT_CLOCK_GETTIME);
DecimalUtils::DecimalComponents<DateTime64::NativeType> components{spec.tv_sec, spec.tv_nsec};
DecimalUtils::DecimalComponents<DateTime64> components{spec.tv_sec, spec.tv_nsec};
// clock_gettime produces subsecond part in nanoseconds, but decimalFromComponents fractional is scale-dependent.
// Andjust fractional to scale, e.g. for 123456789 nanoseconds:

View File

@ -7,6 +7,7 @@
#include <Functions/DateTimeTransforms.h>
#include <Functions/FunctionFactory.h>
#include <Functions/IFunctionImpl.h>
#include <Functions/TransformDateTime64.h>
#include <IO/WriteHelpers.h>
@ -35,13 +36,18 @@ namespace
static UInt16 execute(UInt16 d, UInt64 years, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfYearInterval(DayNum(d), years);
return time_zone.toStartOfYearInterval(ExtendedDayNum(d), years);
}
static UInt16 execute(UInt32 t, UInt64 years, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfYearInterval(time_zone.toDayNum(t), years);
}
static UInt16 execute(Int64 t, UInt64 years, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfYearInterval(time_zone.toDayNum(t), years);
}
};
template <>
@ -51,13 +57,18 @@ namespace
static UInt16 execute(UInt16 d, UInt64 quarters, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfQuarterInterval(DayNum(d), quarters);
return time_zone.toStartOfQuarterInterval(ExtendedDayNum(d), quarters);
}
static UInt16 execute(UInt32 t, UInt64 quarters, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfQuarterInterval(time_zone.toDayNum(t), quarters);
}
static UInt16 execute(Int64 t, UInt64 quarters, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfQuarterInterval(time_zone.toDayNum(t), quarters);
}
};
template <>
@ -67,13 +78,18 @@ namespace
static UInt16 execute(UInt16 d, UInt64 months, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfMonthInterval(DayNum(d), months);
return time_zone.toStartOfMonthInterval(ExtendedDayNum(d), months);
}
static UInt16 execute(UInt32 t, UInt64 months, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfMonthInterval(time_zone.toDayNum(t), months);
}
static UInt16 execute(Int64 t, UInt64 months, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfMonthInterval(time_zone.toDayNum(t), months);
}
};
template <>
@ -83,13 +99,18 @@ namespace
static UInt16 execute(UInt16 d, UInt64 weeks, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfWeekInterval(DayNum(d), weeks);
return time_zone.toStartOfWeekInterval(ExtendedDayNum(d), weeks);
}
static UInt16 execute(UInt32 t, UInt64 weeks, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfWeekInterval(time_zone.toDayNum(t), weeks);
}
static UInt16 execute(Int64 t, UInt64 weeks, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfWeekInterval(time_zone.toDayNum(t), weeks);
}
};
template <>
@ -99,13 +120,18 @@ namespace
static UInt32 execute(UInt16 d, UInt64 days, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfDayInterval(DayNum(d), days);
return time_zone.toStartOfDayInterval(ExtendedDayNum(d), days);
}
static UInt32 execute(UInt32 t, UInt64 days, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfDayInterval(time_zone.toDayNum(t), days);
}
static UInt32 execute(Int64 t, UInt64 days, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfDayInterval(time_zone.toDayNum(t), days);
}
};
template <>
@ -114,8 +140,8 @@ namespace
static constexpr auto name = function_name;
static UInt32 execute(UInt16, UInt64, const DateLUTImpl &) { return dateIsNotSupported(function_name); }
static UInt32 execute(UInt32 t, UInt64 hours, const DateLUTImpl & time_zone) { return time_zone.toStartOfHourInterval(t, hours); }
static UInt32 execute(Int64 t, UInt64 hours, const DateLUTImpl & time_zone) { return time_zone.toStartOfHourInterval(t, hours); }
};
template <>
@ -129,6 +155,11 @@ namespace
{
return time_zone.toStartOfMinuteInterval(t, minutes);
}
static UInt32 execute(Int64 t, UInt64 minutes, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfMinuteInterval(t, minutes);
}
};
template <>
@ -142,6 +173,11 @@ namespace
{
return time_zone.toStartOfSecondInterval(t, seconds);
}
static Int64 execute(Int64 t, UInt64 seconds, const DateLUTImpl & time_zone)
{
return time_zone.toStartOfSecondInterval(t, seconds);
}
};
@ -230,7 +266,7 @@ public:
{
const auto & time_column = arguments[0];
const auto & interval_column = arguments[1];
const DateLUTImpl & time_zone = extractTimeZoneFromFunctionArguments(arguments, 2, 0);
const auto & time_zone = extractTimeZoneFromFunctionArguments(arguments, 2, 0);
auto result_column = dispatchForColumns(time_column, interval_column, time_zone);
return result_column;
}

View File

@ -77,7 +77,7 @@ public:
FunctionBaseImplPtr build(const ColumnsWithTypeAndName &, const DataTypePtr &) const override
{
return std::make_unique<FunctionBaseToday>(DateLUT::instance().toDayNum(time(nullptr)));
return std::make_unique<FunctionBaseToday>(DayNum(DateLUT::instance().toDayNum(time(nullptr)).toUnderType()));
}
};

View File

@ -747,7 +747,7 @@ inline ReturnType readDateTimeTextImpl(DateTime64 & datetime64, UInt32 scale, Re
return ReturnType(false);
}
DB::DecimalUtils::DecimalComponents<DateTime64::NativeType> components{static_cast<DateTime64::NativeType>(whole), 0};
DB::DecimalUtils::DecimalComponents<DateTime64> components{static_cast<DateTime64::NativeType>(whole), 0};
if (!buf.eof() && *buf.position() == '.')
{
@ -791,9 +791,9 @@ inline ReturnType readDateTimeTextImpl(DateTime64 & datetime64, UInt32 scale, Re
return ReturnType(true);
}
inline void readDateTimeText(time_t & datetime, ReadBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance())
inline void readDateTimeText(time_t & datetime, ReadBuffer & buf, const DateLUTImpl & time_zone = DateLUT::instance())
{
readDateTimeTextImpl<void>(datetime, buf, date_lut);
readDateTimeTextImpl<void>(datetime, buf, time_zone);
}
inline void readDateTime64Text(DateTime64 & datetime64, UInt32 scale, ReadBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance())
@ -801,9 +801,9 @@ inline void readDateTime64Text(DateTime64 & datetime64, UInt32 scale, ReadBuffer
readDateTimeTextImpl<void>(datetime64, scale, buf, date_lut);
}
inline bool tryReadDateTimeText(time_t & datetime, ReadBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance())
inline bool tryReadDateTimeText(time_t & datetime, ReadBuffer & buf, const DateLUTImpl & time_zone = DateLUT::instance())
{
return readDateTimeTextImpl<bool>(datetime, buf, date_lut);
return readDateTimeTextImpl<bool>(datetime, buf, time_zone);
}
inline bool tryReadDateTime64Text(DateTime64 & datetime64, UInt32 scale, ReadBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance())

View File

@ -819,12 +819,12 @@ inline void writeDateTimeText(const LocalDateTime & datetime, WriteBuffer & buf)
/// In the format YYYY-MM-DD HH:MM:SS, according to the specified time zone.
template <char date_delimeter = '-', char time_delimeter = ':', char between_date_time_delimiter = ' '>
inline void writeDateTimeText(time_t datetime, WriteBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance())
inline void writeDateTimeText(time_t datetime, WriteBuffer & buf, const DateLUTImpl & time_zone = DateLUT::instance())
{
const auto & values = date_lut.getValues(datetime);
const auto & values = time_zone.getValues(datetime);
writeDateTimeText<date_delimeter, time_delimeter, between_date_time_delimiter>(
LocalDateTime(values.year, values.month, values.day_of_month,
date_lut.toHour(datetime), date_lut.toMinute(datetime), date_lut.toSecond(datetime)), buf);
time_zone.toHour(datetime), time_zone.toMinute(datetime), time_zone.toSecond(datetime)), buf);
}
/// In the format YYYY-MM-DD HH:MM:SS.NNNNNNNNN, according to the specified time zone.
@ -849,9 +849,9 @@ inline void writeDateTimeText(DateTime64 datetime64, UInt32 scale, WriteBuffer &
/// In the RFC 1123 format: "Tue, 03 Dec 2019 00:11:50 GMT". You must provide GMT DateLUT.
/// This is needed for HTTP requests.
inline void writeDateTimeTextRFC1123(time_t datetime, WriteBuffer & buf, const DateLUTImpl & date_lut)
inline void writeDateTimeTextRFC1123(time_t datetime, WriteBuffer & buf, const DateLUTImpl & time_zone = DateLUT::instance())
{
const auto & values = date_lut.getValues(datetime);
const auto & values = time_zone.getValues(datetime);
static const char week_days[3 * 8 + 1] = "XXX" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat" "Sun";
static const char months[3 * 13 + 1] = "XXX" "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec";
@ -865,11 +865,11 @@ inline void writeDateTimeTextRFC1123(time_t datetime, WriteBuffer & buf, const D
buf.write(&digits100[values.year / 100 * 2], 2);
buf.write(&digits100[values.year % 100 * 2], 2);
buf.write(' ');
buf.write(&digits100[date_lut.toHour(datetime) * 2], 2);
buf.write(&digits100[time_zone.toHour(datetime) * 2], 2);
buf.write(':');
buf.write(&digits100[date_lut.toMinute(datetime) * 2], 2);
buf.write(&digits100[time_zone.toMinute(datetime) * 2], 2);
buf.write(':');
buf.write(&digits100[date_lut.toSecond(datetime) * 2], 2);
buf.write(&digits100[time_zone.toSecond(datetime) * 2], 2);
buf.write(" GMT", 4);
}

View File

@ -600,7 +600,7 @@ ReturnType parseDateTimeBestEffortImpl(
return ReturnType(true);
}
template <typename ReturnType>
template <typename ReturnType, bool is_us_style>
ReturnType parseDateTime64BestEffortImpl(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone)
{
time_t whole;
@ -608,12 +608,12 @@ ReturnType parseDateTime64BestEffortImpl(DateTime64 & res, UInt32 scale, ReadBuf
if constexpr (std::is_same_v<ReturnType, bool>)
{
if (!parseDateTimeBestEffortImpl<bool, false>(whole, in, local_time_zone, utc_time_zone, &subsecond))
if (!parseDateTimeBestEffortImpl<bool, is_us_style>(whole, in, local_time_zone, utc_time_zone, &subsecond))
return false;
}
else
{
parseDateTimeBestEffortImpl<ReturnType, false>(whole, in, local_time_zone, utc_time_zone, &subsecond);
parseDateTimeBestEffortImpl<ReturnType, is_us_style>(whole, in, local_time_zone, utc_time_zone, &subsecond);
}
@ -661,12 +661,17 @@ bool tryParseDateTimeBestEffortUS(time_t & res, ReadBuffer & in, const DateLUTIm
void parseDateTime64BestEffort(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone)
{
return parseDateTime64BestEffortImpl<void>(res, scale, in, local_time_zone, utc_time_zone);
return parseDateTime64BestEffortImpl<void, false>(res, scale, in, local_time_zone, utc_time_zone);
}
void parseDateTime64BestEffortUS(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone)
{
return parseDateTime64BestEffortImpl<void, true>(res, scale, in, local_time_zone, utc_time_zone);
}
bool tryParseDateTime64BestEffort(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone)
{
return parseDateTime64BestEffortImpl<bool>(res, scale, in, local_time_zone, utc_time_zone);
return parseDateTime64BestEffortImpl<bool, false>(res, scale, in, local_time_zone, utc_time_zone);
}
}

View File

@ -61,6 +61,7 @@ bool tryParseDateTimeBestEffort(time_t & res, ReadBuffer & in, const DateLUTImpl
void parseDateTimeBestEffortUS(time_t & res, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone);
bool tryParseDateTimeBestEffortUS(time_t & res, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone);
void parseDateTime64BestEffort(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone);
void parseDateTime64BestEffortUS(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone);
bool tryParseDateTime64BestEffort(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone);
}

View File

@ -40,7 +40,7 @@ void CrashLogElement::appendToBlock(MutableColumns & columns) const
{
size_t i = 0;
columns[i++]->insert(DateLUT::instance().toDayNum(event_time));
columns[i++]->insert(DateLUT::instance().toDayNum(event_time).toUnderType());
columns[i++]->insert(event_time);
columns[i++]->insert(timestamp_ns);
columns[i++]->insert(signal);

View File

@ -41,7 +41,7 @@ void MetricLogElement::appendToBlock(MutableColumns & columns) const
{
size_t column_idx = 0;
columns[column_idx++]->insert(DateLUT::instance().toDayNum(event_time));
columns[column_idx++]->insert(DateLUT::instance().toDayNum(event_time).toUnderType());
columns[column_idx++]->insert(event_time);
columns[column_idx++]->insert(event_time_microseconds);
columns[column_idx++]->insert(milliseconds);

View File

@ -49,7 +49,7 @@ void OpenTelemetrySpanLogElement::appendToBlock(MutableColumns & columns) const
columns[i++]->insert(operation_name);
columns[i++]->insert(start_time_us);
columns[i++]->insert(finish_time_us);
columns[i++]->insert(DateLUT::instance().toDayNum(finish_time_us / 1000000));
columns[i++]->insert(DateLUT::instance().toDayNum(finish_time_us / 1000000).toUnderType());
columns[i++]->insert(attribute_names);
// The user might add some ints values, and we will have Int Field, and the
// insert will fail because the column requires Strings. Convert the fields

View File

@ -71,7 +71,7 @@ void PartLogElement::appendToBlock(MutableColumns & columns) const
columns[i++]->insert(query_id);
columns[i++]->insert(event_type);
columns[i++]->insert(DateLUT::instance().toDayNum(event_time));
columns[i++]->insert(DateLUT::instance().toDayNum(event_time).toUnderType());
columns[i++]->insert(event_time);
columns[i++]->insert(event_time_microseconds);
columns[i++]->insert(duration_ms);

View File

@ -119,7 +119,7 @@ void QueryLogElement::appendToBlock(MutableColumns & columns) const
size_t i = 0;
columns[i++]->insert(type);
columns[i++]->insert(DateLUT::instance().toDayNum(event_time));
columns[i++]->insert(DateLUT::instance().toDayNum(event_time).toUnderType());
columns[i++]->insert(event_time);
columns[i++]->insert(event_time_microseconds);
columns[i++]->insert(query_start_time);

View File

@ -76,7 +76,7 @@ void QueryThreadLogElement::appendToBlock(MutableColumns & columns) const
{
size_t i = 0;
columns[i++]->insert(DateLUT::instance().toDayNum(event_time));
columns[i++]->insert(DateLUT::instance().toDayNum(event_time).toUnderType());
columns[i++]->insert(event_time);
columns[i++]->insert(event_time_microseconds);
columns[i++]->insert(query_start_time);

View File

@ -55,7 +55,7 @@ void TextLogElement::appendToBlock(MutableColumns & columns) const
{
size_t i = 0;
columns[i++]->insert(DateLUT::instance().toDayNum(event_time));
columns[i++]->insert(DateLUT::instance().toDayNum(event_time).toUnderType());
columns[i++]->insert(event_time);
columns[i++]->insert(event_time_microseconds);
columns[i++]->insert(microseconds);

View File

@ -42,7 +42,7 @@ void TraceLogElement::appendToBlock(MutableColumns & columns) const
{
size_t i = 0;
columns[i++]->insert(DateLUT::instance().toDayNum(event_time));
columns[i++]->insert(DateLUT::instance().toDayNum(event_time).toUnderType());
columns[i++]->insert(event_time);
columns[i++]->insert(event_time_microseconds);
columns[i++]->insert(timestamp_ns);

View File

@ -141,7 +141,7 @@ Field convertFieldToTypeImpl(const Field & src, const IDataType & type, const ID
/// Conversion between Date and DateTime and vice versa.
if (which_type.isDate() && which_from_type.isDateTime())
{
return static_cast<const DataTypeDateTime &>(*from_type_hint).getTimeZone().toDayNum(src.get<UInt64>());
return static_cast<UInt16>(static_cast<const DataTypeDateTime &>(*from_type_hint).getTimeZone().toDayNum(src.get<UInt64>()).toUnderType());
}
else if (which_type.isDateTime() && which_from_type.isDate())
{

View File

@ -4369,7 +4369,7 @@ static String getPartNamePossiblyFake(MergeTreeDataFormatVersion format_version,
/// The date range is all month long.
const auto & lut = DateLUT::instance();
time_t start_time = lut.YYYYMMDDToDate(parse<UInt32>(part_info.partition_id + "01"));
DayNum left_date = lut.toDayNum(start_time);
DayNum left_date = DayNum{lut.toDayNum(start_time).toUnderType()};
DayNum right_date = DayNum(static_cast<size_t>(left_date) + lut.daysInMonth(start_time) - 1);
return part_info.getPartNameV0(left_date, right_date);
}

View File

@ -5,7 +5,7 @@
int main(int, char **)
{
DayNum today = DateLUT::instance().toDayNum(time(nullptr));
const DayNum today{DateLUT::instance().toDayNum(time(nullptr)).toUnderType()};
for (DayNum date = today; DayNum(date + 10) > today; --date)
{

View File

@ -86,8 +86,7 @@ CAST(N as DateTime64(9, 'Europe/Minsk'))
formatDateTime(N, '%C %d %D %e %F %H %I %j %m %M %p %R %S %T %u %V %w %y %Y %%')
""".splitlines()
# Expanded later to cartesian product of all arguments.
# NOTE: {N} to be turned into N after str.format() for keys (format string), but not for list of values!
# Expanded later to cartesian product of all arguments, using format string.
extra_ops = [
# With same type:
(
@ -179,7 +178,7 @@ def escape_string(s):
def execute_functions_for_types(functions, types):
# TODO: use string.Template here to allow lines that do not contain type, like: SELECT CAST(toDateTime64(1234567890), 'DateTime64')
# NOTE: use string.Template here to allow lines with missing keys, like type, e.g. SELECT CAST(toDateTime64(1234567890), 'DateTime64')
for func in functions:
print(("""SELECT 'SELECT {func}';""".format(func=escape_string(func))))
for dt in types:

View File

@ -1,5 +1,4 @@
SELECT toTimeZone(N, \'UTC\')
Code: 43
"DateTime('UTC')","2019-09-16 16:20:11"
"DateTime64(3, 'UTC')","2019-09-16 16:20:11.234"
@ -35,25 +34,21 @@ SELECT toDayOfWeek(N)
"UInt8",1
------------------------------------------
SELECT toHour(N)
Code: 43
"UInt8",19
"UInt8",19
------------------------------------------
SELECT toMinute(N)
Code: 43
"UInt8",20
"UInt8",20
------------------------------------------
SELECT toSecond(N)
Code: 43
"UInt8",11
"UInt8",11
------------------------------------------
SELECT toUnixTimestamp(N)
Code: 44
"UInt32",1568650811
"UInt32",1568650811
@ -94,31 +89,26 @@ SELECT toStartOfDay(N)
"DateTime('Europe/Minsk')","2019-09-16 00:00:00"
------------------------------------------
SELECT toStartOfHour(N)
Code: 43
"DateTime('Europe/Minsk')","2019-09-16 19:00:00"
"DateTime('Europe/Minsk')","2019-09-16 19:00:00"
------------------------------------------
SELECT toStartOfMinute(N)
Code: 43
"DateTime('Europe/Minsk')","2019-09-16 19:20:00"
"DateTime('Europe/Minsk')","2019-09-16 19:20:00"
------------------------------------------
SELECT toStartOfFiveMinute(N)
Code: 43
"DateTime('Europe/Minsk')","2019-09-16 19:20:00"
"DateTime('Europe/Minsk')","2019-09-16 19:20:00"
------------------------------------------
SELECT toStartOfTenMinutes(N)
Code: 43
"DateTime('Europe/Minsk')","2019-09-16 19:20:00"
"DateTime('Europe/Minsk')","2019-09-16 19:20:00"
------------------------------------------
SELECT toStartOfFifteenMinutes(N)
Code: 43
"DateTime('Europe/Minsk')","2019-09-16 19:15:00"
"DateTime('Europe/Minsk')","2019-09-16 19:15:00"
@ -139,7 +129,6 @@ SELECT toStartOfInterval(N, INTERVAL 1 day)
"DateTime('Europe/Minsk')","2019-09-16 00:00:00"
------------------------------------------
SELECT toStartOfInterval(N, INTERVAL 15 minute)
Code: 43
"DateTime('Europe/Minsk')","2019-09-16 19:15:00"
"DateTime('Europe/Minsk')","2019-09-16 19:15:00"
@ -160,13 +149,11 @@ SELECT date_trunc(\'day\', N)
"DateTime('Europe/Minsk')","2019-09-16 00:00:00"
------------------------------------------
SELECT date_trunc(\'minute\', N)
Code: 43
"DateTime('Europe/Minsk')","2019-09-16 19:20:00"
"DateTime('Europe/Minsk')","2019-09-16 19:20:00"
------------------------------------------
SELECT toTime(N)
Code: 43
"DateTime('Europe/Minsk')","1970-01-02 19:20:11"
"DateTime('Europe/Minsk')","1970-01-02 19:20:11"
@ -232,7 +219,6 @@ SELECT toYearWeek(N)
"UInt32",201937
------------------------------------------
SELECT timeSlot(N)
Code: 43
"DateTime('Europe/Minsk')","2019-09-16 19:00:00"
"DateTime('Europe/Minsk')","2019-09-16 19:00:00"
@ -375,15 +361,11 @@ SELECT formatDateTime(N, \'%C %d %D %e %F %H %I %j %m %M %p %R %S %T %u %V %w %y
SELECT N - N
"Int32",0
"Int32",0
Code: 43
------------------------------------------
SELECT N + N
Code: 43
Code: 43
Code: 43
------------------------------------------
SELECT N != N
@ -417,47 +399,33 @@ SELECT N >= N
"UInt8",1
------------------------------------------
SELECT N - DT
Code: 43
"Int32",0
Code: 43
------------------------------------------
SELECT DT - N
Code: 43
"Int32",0
Code: 43
------------------------------------------
SELECT N - D
"Int32",0
Code: 43
Code: 43
------------------------------------------
SELECT D - N
"Int32",0
Code: 43
Code: 43
------------------------------------------
SELECT N - DT64
Code: 43
Code: 43
Code: 43
------------------------------------------
SELECT DT64 - N
Code: 43
Code: 43
Code: 43
------------------------------------------
SELECT N != DT
@ -726,11 +694,8 @@ SELECT N - toUInt8(1)
"DateTime64(3, 'Europe/Minsk')","2019-09-16 19:20:10.234"
------------------------------------------
SELECT toUInt8(1) - N
Code: 43
Code: 43
Code: 43
------------------------------------------
SELECT N - toInt8(-1)
@ -739,11 +704,8 @@ SELECT N - toInt8(-1)
"DateTime64(3, 'Europe/Minsk')","2019-09-16 19:20:12.234"
------------------------------------------
SELECT toInt8(-1) - N
Code: 43
Code: 43
Code: 43
------------------------------------------
SELECT N - toUInt16(1)
@ -752,11 +714,8 @@ SELECT N - toUInt16(1)
"DateTime64(3, 'Europe/Minsk')","2019-09-16 19:20:10.234"
------------------------------------------
SELECT toUInt16(1) - N
Code: 43
Code: 43
Code: 43
------------------------------------------
SELECT N - toInt16(-1)
@ -765,11 +724,8 @@ SELECT N - toInt16(-1)
"DateTime64(3, 'Europe/Minsk')","2019-09-16 19:20:12.234"
------------------------------------------
SELECT toInt16(-1) - N
Code: 43
Code: 43
Code: 43
------------------------------------------
SELECT N - toUInt32(1)
@ -778,11 +734,8 @@ SELECT N - toUInt32(1)
"DateTime64(3, 'Europe/Minsk')","2019-09-16 19:20:10.234"
------------------------------------------
SELECT toUInt32(1) - N
Code: 43
Code: 43
Code: 43
------------------------------------------
SELECT N - toInt32(-1)
@ -791,11 +744,8 @@ SELECT N - toInt32(-1)
"DateTime64(3, 'Europe/Minsk')","2019-09-16 19:20:12.234"
------------------------------------------
SELECT toInt32(-1) - N
Code: 43
Code: 43
Code: 43
------------------------------------------
SELECT N - toUInt64(1)
@ -804,11 +754,8 @@ SELECT N - toUInt64(1)
"DateTime64(3, 'Europe/Minsk')","2019-09-16 19:20:10.234"
------------------------------------------
SELECT toUInt64(1) - N
Code: 43
Code: 43
Code: 43
------------------------------------------
SELECT N - toInt64(-1)
@ -817,585 +764,486 @@ SELECT N - toInt64(-1)
"DateTime64(3, 'Europe/Minsk')","2019-09-16 19:20:12.234"
------------------------------------------
SELECT toInt64(-1) - N
Code: 43
Code: 43
Code: 43
------------------------------------------
SELECT N == toUInt8(1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toUInt8(1) == N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N == toInt8(-1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toInt8(-1) == N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N == toUInt16(1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toUInt16(1) == N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N == toInt16(-1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toInt16(-1) == N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N == toUInt32(1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toUInt32(1) == N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N == toInt32(-1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toInt32(-1) == N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N == toUInt64(1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toUInt64(1) == N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N == toInt64(-1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toInt64(-1) == N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N != toUInt8(1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toUInt8(1) != N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N != toInt8(-1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toInt8(-1) != N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N != toUInt16(1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toUInt16(1) != N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N != toInt16(-1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toInt16(-1) != N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N != toUInt32(1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toUInt32(1) != N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N != toInt32(-1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toInt32(-1) != N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N != toUInt64(1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toUInt64(1) != N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N != toInt64(-1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toInt64(-1) != N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N < toUInt8(1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toUInt8(1) < N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N < toInt8(-1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toInt8(-1) < N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N < toUInt16(1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toUInt16(1) < N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N < toInt16(-1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toInt16(-1) < N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N < toUInt32(1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toUInt32(1) < N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N < toInt32(-1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toInt32(-1) < N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N < toUInt64(1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toUInt64(1) < N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N < toInt64(-1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toInt64(-1) < N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N <= toUInt8(1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toUInt8(1) <= N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N <= toInt8(-1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toInt8(-1) <= N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N <= toUInt16(1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toUInt16(1) <= N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N <= toInt16(-1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toInt16(-1) <= N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N <= toUInt32(1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toUInt32(1) <= N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N <= toInt32(-1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toInt32(-1) <= N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N <= toUInt64(1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toUInt64(1) <= N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N <= toInt64(-1)
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT toInt64(-1) <= N
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT N > toUInt8(1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toUInt8(1) > N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N > toInt8(-1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toInt8(-1) > N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N > toUInt16(1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toUInt16(1) > N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N > toInt16(-1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toInt16(-1) > N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N > toUInt32(1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toUInt32(1) > N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N > toInt32(-1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toInt32(-1) > N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N > toUInt64(1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toUInt64(1) > N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N > toInt64(-1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toInt64(-1) > N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N >= toUInt8(1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toUInt8(1) >= N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N >= toInt8(-1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toInt8(-1) >= N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N >= toUInt16(1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toUInt16(1) >= N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N >= toInt16(-1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toInt16(-1) >= N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N >= toUInt32(1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toUInt32(1) >= N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N >= toInt32(-1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toInt32(-1) >= N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N >= toUInt64(1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toUInt64(1) >= N
Code: 43
"UInt8",0
"UInt8",0
------------------------------------------
SELECT N >= toInt64(-1)
Code: 43
"UInt8",1
"UInt8",1
------------------------------------------
SELECT toInt64(-1) >= N
Code: 43
"UInt8",0
"UInt8",0

View File

@ -13,4 +13,4 @@ CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
python3 "${CURDIR}"/00921_datetime64_compatibility.python \
| ${CLICKHOUSE_CLIENT} --ignore-error -T -nm --calculate_text_stack_trace 0 --log-level 'error' 2>&1 \
| sed 's/Received exception .*//g; s/^\(Code: [0-9]\+\).*$/\1/g'
| grep -v 'Received exception .*$' | sed 's/^\(Code: [0-9]\+\).*$/\1/g'

View File

@ -1,7 +1,7 @@
2020-01-02 03:04:05 2020-01-02 00:00:00 3
2020-01-02 03:04:05 2020-01-02 00:00:00 3
2020-01-02 03:04:05 2020-01-02 00:00:00 3
2020-01-02 03:04:05 2020-01-02 00:00:00 3
2020-01-02 03:04:05 2020-01-02 00:00:00 3
2020-01-02 03:04:05 2020-01-02 00:00:00 3
2020-01-02 03:04:05 2020-01-02 00:00:00 3
Pacific/Kiritimati 2020-01-02 03:04:05 2020-01-02 00:00:00 3
Africa/El_Aaiun 2020-01-02 03:04:05 2020-01-02 00:00:00 3
Asia/Pyongyang 2020-01-02 03:04:05 2020-01-02 00:00:00 3
Pacific/Kwajalein 2020-01-02 03:04:05 2020-01-02 00:00:00 3
Pacific/Apia 2020-01-02 03:04:05 2020-01-02 00:00:00 3
Pacific/Enderbury 2020-01-02 03:04:05 2020-01-02 00:00:00 3
Pacific/Fakaofo 2020-01-02 03:04:05 2020-01-02 00:00:00 3

View File

@ -1,15 +1,15 @@
SELECT toDateTime('2020-01-02 03:04:05', 'Pacific/Kiritimati') AS x, toStartOfDay(x), toHour(x);
SELECT toDateTime('2020-01-02 03:04:05', 'Africa/El_Aaiun') AS x, toStartOfDay(x), toHour(x);
SELECT toDateTime('2020-01-02 03:04:05', 'Asia/Pyongyang') AS x, toStartOfDay(x), toHour(x);
SELECT toDateTime('2020-01-02 03:04:05', 'Pacific/Kwajalein') AS x, toStartOfDay(x), toHour(x);
SELECT toDateTime('2020-01-02 03:04:05', 'Pacific/Apia') AS x, toStartOfDay(x), toHour(x);
SELECT toDateTime('2020-01-02 03:04:05', 'Pacific/Enderbury') AS x, toStartOfDay(x), toHour(x);
SELECT toDateTime('2020-01-02 03:04:05', 'Pacific/Fakaofo') AS x, toStartOfDay(x), toHour(x);
SELECT 'Pacific/Kiritimati', toDateTime('2020-01-02 03:04:05', 'Pacific/Kiritimati') AS x, toStartOfDay(x), toHour(x);
SELECT 'Africa/El_Aaiun', toDateTime('2020-01-02 03:04:05', 'Africa/El_Aaiun') AS x, toStartOfDay(x), toHour(x);
SELECT 'Asia/Pyongyang', toDateTime('2020-01-02 03:04:05', 'Asia/Pyongyang') AS x, toStartOfDay(x), toHour(x);
SELECT 'Pacific/Kwajalein', toDateTime('2020-01-02 03:04:05', 'Pacific/Kwajalein') AS x, toStartOfDay(x), toHour(x);
SELECT 'Pacific/Apia', toDateTime('2020-01-02 03:04:05', 'Pacific/Apia') AS x, toStartOfDay(x), toHour(x);
SELECT 'Pacific/Enderbury', toDateTime('2020-01-02 03:04:05', 'Pacific/Enderbury') AS x, toStartOfDay(x), toHour(x);
SELECT 'Pacific/Fakaofo', toDateTime('2020-01-02 03:04:05', 'Pacific/Fakaofo') AS x, toStartOfDay(x), toHour(x);
SELECT toHour(toDateTime(rand(), 'Pacific/Kiritimati') AS t) AS h, t FROM numbers(1000000) WHERE h < 0 OR h > 23 ORDER BY h LIMIT 1 BY h;
SELECT toHour(toDateTime(rand(), 'Africa/El_Aaiun') AS t) AS h, t FROM numbers(1000000) WHERE h < 0 OR h > 23 ORDER BY h LIMIT 1 BY h;
SELECT toHour(toDateTime(rand(), 'Asia/Pyongyang') AS t) AS h, t FROM numbers(1000000) WHERE h < 0 OR h > 23 ORDER BY h LIMIT 1 BY h;
SELECT toHour(toDateTime(rand(), 'Pacific/Kwajalein') AS t) AS h, t FROM numbers(1000000) WHERE h < 0 OR h > 23 ORDER BY h LIMIT 1 BY h;
SELECT toHour(toDateTime(rand(), 'Pacific/Apia') AS t) AS h, t FROM numbers(1000000) WHERE h < 0 OR h > 23 ORDER BY h LIMIT 1 BY h;
SELECT toHour(toDateTime(rand(), 'Pacific/Enderbury') AS t) AS h, t FROM numbers(1000000) WHERE h < 0 OR h > 23 ORDER BY h LIMIT 1 BY h;
SELECT toHour(toDateTime(rand(), 'Pacific/Fakaofo') AS t) AS h, t FROM numbers(1000000) WHERE h < 0 OR h > 23 ORDER BY h LIMIT 1 BY h;
SELECT 'Pacific/Kiritimati', rand() as r, toHour(toDateTime(r, 'Pacific/Kiritimati') AS t) AS h, t, toTypeName(t) FROM numbers(1000000) WHERE h < 0 OR h > 23 ORDER BY h LIMIT 1 BY h;
SELECT 'Africa/El_Aaiun', rand() as r, toHour(toDateTime(r, 'Africa/El_Aaiun') AS t) AS h, t, toTypeName(t) FROM numbers(1000000) WHERE h < 0 OR h > 23 ORDER BY h LIMIT 1 BY h;
SELECT 'Asia/Pyongyang', rand() as r, toHour(toDateTime(r, 'Asia/Pyongyang') AS t) AS h, t, toTypeName(t) FROM numbers(1000000) WHERE h < 0 OR h > 23 ORDER BY h LIMIT 1 BY h;
SELECT 'Pacific/Kwajalein', rand() as r, toHour(toDateTime(r, 'Pacific/Kwajalein') AS t) AS h, t, toTypeName(t) FROM numbers(1000000) WHERE h < 0 OR h > 23 ORDER BY h LIMIT 1 BY h;
SELECT 'Pacific/Apia', rand() as r, toHour(toDateTime(r, 'Pacific/Apia') AS t) AS h, t, toTypeName(t) FROM numbers(1000000) WHERE h < 0 OR h > 23 ORDER BY h LIMIT 1 BY h;
SELECT 'Pacific/Enderbury', rand() as r, toHour(toDateTime(r, 'Pacific/Enderbury') AS t) AS h, t, toTypeName(t) FROM numbers(1000000) WHERE h < 0 OR h > 23 ORDER BY h LIMIT 1 BY h;
SELECT 'Pacific/Fakaofo', rand() as r, toHour(toDateTime(r, 'Pacific/Fakaofo') AS t) AS h, t, toTypeName(t) FROM numbers(1000000) WHERE h < 0 OR h > 23 ORDER BY h LIMIT 1 BY h;

View File

@ -1,4 +1,4 @@
0
1970-01-01 2106-02-07 1970-04-11 1970-01-01 2106-02-07
1970-01-01 2106-02-07 1970-04-11 1970-01-01 2149-06-06
1970-01-01 03:00:00 2106-02-07 09:28:15 1970-01-01 03:16:40
2000-01-01 13:12:12

View File

@ -1,2 +1,2 @@
1970-01-01 1
1970-01-01 1
2106-11-11 1
2106-11-12 1

View File

@ -6,6 +6,6 @@ insert into dt_overflow values('2106-11-11', 1);
insert into dt_overflow values('2106-11-12', 1);
select * from dt_overflow;
select * from dt_overflow ORDER BY d;
drop table if exists dt_overflow;

View File

@ -1,4 +1,5 @@
-- { echo }
<<<<<<< HEAD
SELECT toTimeZone(toDateTime(-2, 2), 'Europe/Moscow');
1970-01-01 03:00:00.00
SELECT toDateTime64(-2, 2, 'Europe/Moscow');
@ -15,3 +16,25 @@ SELECT toDateTime64(-2., 2, 'Europe/Moscow');
SELECT toDateTime64(toFloat32(bitShiftLeft(toUInt64(1),33)), 2, 'Europe/Moscow');
2106-02-07 09:00:00.00
SELECT toDateTime64(toFloat64(bitShiftLeft(toUInt64(1),33)), 2, 'Europe/Moscow') FORMAT Null;
=======
-- These values are within the extended range of DateTime64 [1925-01-01, 2284-01-01)
SELECT toDateTime(-2, 2);
1970-01-01 02:59:58.00
SELECT toDateTime64(-2, 2);
1970-01-01 02:59:58.00
SELECT CAST(-1 AS DateTime64);
1970-01-01 02:59:59.000
SELECT CAST('2020-01-01 00:00:00.3' AS DateTime64);
2020-01-01 00:00:00.300
SELECT toDateTime64(bitShiftLeft(toUInt64(1),33), 2);
2242-03-16 15:56:32.00
-- These are outsize of extended range and hence clamped
SELECT toDateTime64(-1 * bitShiftLeft(toUInt64(1),35), 2);
1925-01-01 02:00:00.00
SELECT CAST(-1 * bitShiftLeft(toUInt64(1),35) AS DateTime64);
1925-01-01 02:00:00.000
SELECT CAST(bitShiftLeft(toUInt64(1),35) AS DateTime64);
2282-12-31 03:00:00.000
SELECT toDateTime64(bitShiftLeft(toUInt64(1),35), 2);
2282-12-31 03:00:00.00
>>>>>>> af31042451... Extended range of DateTime64 to years 1925 - 2238

View File

@ -1,4 +1,5 @@
-- { echo }
-- These values are within the extended range of DateTime64 [1925-01-01, 2284-01-01)
SELECT toTimeZone(toDateTime(-2, 2), 'Europe/Moscow');
SELECT toDateTime64(-2, 2, 'Europe/Moscow');
SELECT CAST(-1 AS DateTime64(0, 'Europe/Moscow'));
@ -8,3 +9,9 @@ SELECT toTimeZone(toDateTime(-2., 2), 'Europe/Moscow');
SELECT toDateTime64(-2., 2, 'Europe/Moscow');
SELECT toDateTime64(toFloat32(bitShiftLeft(toUInt64(1),33)), 2, 'Europe/Moscow');
SELECT toDateTime64(toFloat64(bitShiftLeft(toUInt64(1),33)), 2, 'Europe/Moscow') FORMAT Null;
-- These are outsize of extended range and hence clamped
SELECT toDateTime64(-1 * bitShiftLeft(toUInt64(1),35), 2);
SELECT CAST(-1 * bitShiftLeft(toUInt64(1),35) AS DateTime64);
SELECT CAST(bitShiftLeft(toUInt64(1),35) AS DateTime64);
SELECT toDateTime64(bitShiftLeft(toUInt64(1),35), 2);

View File

@ -47,8 +47,9 @@ void run(String part_path, String date_column, String dest_path)
DayNum max_date;
MergeTreePartInfo::parseMinMaxDatesFromPartName(old_part_name, min_date, max_date);
UInt32 yyyymm = DateLUT::instance().toNumYYYYMM(min_date);
if (yyyymm != DateLUT::instance().toNumYYYYMM(max_date))
const auto & time_zone = DateLUT::instance();
UInt32 yyyymm = time_zone.toNumYYYYMM(min_date);
if (yyyymm != time_zone.toNumYYYYMM(max_date))
throw Exception("Part " + old_part_name + " spans different months",
ErrorCodes::BAD_DATA_PART_NAME);