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