diff --git a/src/Common/DateLUTImpl.h b/src/Common/DateLUTImpl.h index df70fc3fa7e..e9220c46af9 100644 --- a/src/Common/DateLUTImpl.h +++ b/src/Common/DateLUTImpl.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -216,7 +217,6 @@ private: Time offset_at_start_of_lut; bool offset_is_whole_number_of_hours_during_epoch; bool offset_is_whole_number_of_minutes_during_epoch; - bool offset_is_whole_number_of_seconds_during_epoch; /// Time zone name. std::string time_zone; @@ -593,17 +593,28 @@ public: return time % 60; } - unsigned toMillisecond(Time t) const + template + unsigned toMillisecond(const DateOrTime & datetime, Int64 scale_multiplier) const { - if (t >= 0 && offset_is_whole_number_of_hours_during_epoch) - return (t % 60) * 1000; + const auto microsecond_multiplier = 1000000; + const auto millisecond_multiplier = 1000; - LUTIndex index = findIndex(t); - Time time = t - lut[index].date; + auto components = DB::DecimalUtils::splitWithScaleMultiplier(datetime, scale_multiplier); - if (time >= lut[index].time_at_offset_change()) - time += lut[index].amount_of_offset_change(); - return (time % 60) * 1000; + if (datetime.value < 0 && components.fractional) + { + components.fractional = scale_multiplier + (components.whole ? Int64(-1) : Int64(1)) * components.fractional; + --components.whole; + } + Int64 fractional = components.fractional; + if (scale_multiplier > microsecond_multiplier) + fractional = fractional / (scale_multiplier / microsecond_multiplier); + else if (scale_multiplier < microsecond_multiplier) + fractional = fractional * (microsecond_multiplier / scale_multiplier); + + constexpr Int64 divider = microsecond_multiplier / millisecond_multiplier; + UInt16 millisecond = static_cast(fractional / divider); + return millisecond; } unsigned toMinute(Time t) const diff --git a/src/Functions/DateTimeTransforms.h b/src/Functions/DateTimeTransforms.h index 9f55e472704..af37e0d1e0d 100644 --- a/src/Functions/DateTimeTransforms.h +++ b/src/Functions/DateTimeTransforms.h @@ -6,6 +6,7 @@ #include #include #include +#include "base/Decimal.h" #include #include #include @@ -1522,13 +1523,14 @@ struct ToMillisecondImpl { static constexpr auto name = "toMillisecond"; - static UInt16 execute(Int64 t, const DateLUTImpl & time_zone) + static UInt16 execute(const DateTime64 & datetime64, Int64 scale_multiplier, const DateLUTImpl & time_zone) { - return time_zone.toMillisecond(t); + return time_zone.toMillisecond(datetime64, scale_multiplier); } - static UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + + static UInt16 execute(UInt32, const DateLUTImpl &) { - return time_zone.toMillisecond(t); + return 0; /// Only DateTime64 type will give a value for milliseconds } static UInt16 execute(Int32, const DateLUTImpl &) { @@ -1540,7 +1542,7 @@ struct ToMillisecondImpl } static constexpr bool hasPreimage() { return false; } - using FactorTransform = ToStartOfSecondImpl; + using FactorTransform = ZeroTransform; }; struct ToISOYearImpl diff --git a/src/Functions/toMillisecond.cpp b/src/Functions/toMillisecond.cpp index 10c7d59f09c..e15b56cc555 100644 --- a/src/Functions/toMillisecond.cpp +++ b/src/Functions/toMillisecond.cpp @@ -1,8 +1,6 @@ #include #include #include -#include - namespace DB { diff --git a/tests/queries/0_stateless/02998_to_milliseconds.reference b/tests/queries/0_stateless/02998_to_milliseconds.reference index 24a4fa896a7..05139c19d1d 100644 --- a/tests/queries/0_stateless/02998_to_milliseconds.reference +++ b/tests/queries/0_stateless/02998_to_milliseconds.reference @@ -1,7 +1,8 @@ -2023-04-21 10:20:30 30000 30000 -2023-04-21 10:20:30 30000 30000 -2023-04-21 10:20:30.123 30000 30000 -2023-04-21 10:20:30.123456 30000 30000 -30000 -2023-04-21 10:20:30 30000 -2023-04-21 10:20:30 30000 +2023-04-21 10:20:30 0 0 +2023-04-21 10:20:30 0 0 +2023-04-21 10:20:30.123 123 123 +2023-04-21 10:20:30.123456 123 123 +2023-04-21 10:20:30.123456789 123 123 +120 +2023-04-21 10:20:30 0 +2023-04-21 10:20:30 0