From e1c9b8c15545ac9a5d69956b6d36d5747f726160 Mon Sep 17 00:00:00 2001 From: kigerzhang Date: Tue, 31 Jan 2023 10:20:59 +0800 Subject: [PATCH] Add new functionality to the function FormatDataTime --- src/Functions/DateTimeTransforms.h | 49 +++++++++++++++++++ src/Functions/formatDateTime.cpp | 48 ++++++++++++++++-- ...6_format_datetime_in_joda_syntax.reference | 26 ++++++++++ .../02496_format_datetime_in_joda_syntax.sql | 22 ++++++--- 4 files changed, 136 insertions(+), 9 deletions(-) diff --git a/src/Functions/DateTimeTransforms.h b/src/Functions/DateTimeTransforms.h index f4163a336ef..9a1fcd3ae75 100644 --- a/src/Functions/DateTimeTransforms.h +++ b/src/Functions/DateTimeTransforms.h @@ -710,6 +710,55 @@ struct ToYearImpl using FactorTransform = ZeroTransform; }; +struct ToWeekYearImpl { + static constexpr auto name = "toWeekYear"; + + static constexpr Int8 week_mode = 3; + + static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone) + { + return time_zone.toYearWeek(t, week_mode).first; + } + static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toYearWeek(t, week_mode).first; + } + static inline UInt16 execute(Int32 d, const DateLUTImpl & time_zone) + { + return time_zone.toYearWeek(ExtendedDayNum(d), week_mode).first; + } + static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toYearWeek(DayNum(d), week_mode).first; + } + + using FactorTransform = ZeroTransform; +}; + +struct ToWeekOfWeekYearImpl +{ + static constexpr auto name = "toWeekOfWeekYear"; + + static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone) + { + return time_zone.toISOWeek(t); + } + static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) + { + return time_zone.toISOWeek(t); + } + static inline UInt16 execute(Int32 d, const DateLUTImpl & time_zone) + { + return time_zone.toISOWeek(ExtendedDayNum(d)); + } + static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone) + { + return time_zone.toISOWeek(DayNum(d)); + } + + using FactorTransform = ZeroTransform; +}; + struct ToQuarterImpl { static constexpr auto name = "toQuarter"; diff --git a/src/Functions/formatDateTime.cpp b/src/Functions/formatDateTime.cpp index e7c9a1b5103..48360f534a3 100644 --- a/src/Functions/formatDateTime.cpp +++ b/src/Functions/formatDateTime.cpp @@ -527,6 +527,16 @@ private: return writeNumberWithPadding(dest, year, min_represent_digits); } + static size_t jodaWeekYear(size_t min_represent_digits, char * dest, Time source, UInt64, UInt32, const DateLUTImpl & timezone) { + auto week_year = ToWeekYearImpl::execute(source, timezone); + return writeNumberWithPadding(dest, week_year, min_represent_digits); + } + + static size_t jodaWeekOfWeekYear(size_t min_represent_digits, char * dest, Time source, UInt64, UInt32, const DateLUTImpl & timezone) { + auto week_of_weekyear = ToWeekOfWeekYearImpl::execute(source, timezone); + return writeNumberWithPadding(dest, week_of_weekyear, min_represent_digits); + } + static size_t jodaDayOfYear(size_t min_represent_digits, char * dest, Time source, UInt64, UInt32, const DateLUTImpl & timezone) { auto day_of_year = ToDayOfYearImpl::execute(source, timezone); @@ -597,6 +607,28 @@ private: return writeNumberWithPadding(dest, second_of_minute, min_represent_digits); } + static size_t jodaFractionOfSecond(size_t min_represent_digits, char * dest, Time /*source*/, UInt64 fractional_second, UInt32 scale, const DateLUTImpl & /*timezone*/) + { + if (fractional_second == 0) + { + for (UInt64 i = 0; i < min_represent_digits; ++i) + dest[i] = '0'; + return min_represent_digits; + } + auto str = toString(fractional_second); + if (min_represent_digits > scale) + { + for (UInt64 i = 0; i < min_represent_digits - scale; ++i) + str += '0'; + } + else if (min_represent_digits < scale) + { + str = str.substr(0, min_represent_digits); + } + memcpy(dest, str.data(), str.size()); + return min_represent_digits; + } + static size_t jodaTimezone(size_t min_represent_digits, char * dest, Time /*source*/, UInt64, UInt32, const DateLUTImpl & timezone) { if (min_represent_digits <= 3) @@ -1145,9 +1177,15 @@ public: reserve_size += repetitions == 2 ? 2 : std::max(repetitions, 4); break; case 'x': - throw Exception("format is not supported for WEEK_YEAR", ErrorCodes::NOT_IMPLEMENTED); + instructions.emplace_back(std::bind_front(&Action::jodaWeekYear, repetitions)); + /// weekyear range [1900, 2299] + reserve_size += std::max(repetitions, 4); + break; case 'w': - throw Exception("format is not supported for WEEK_OF_WEEK_YEAR", ErrorCodes::NOT_IMPLEMENTED); + instructions.emplace_back(std::bind_front(&Action::jodaWeekOfWeekYear, repetitions)); + /// Week of weekyear range [1, 52] + reserve_size += std::max(repetitions, 2); + break; case 'e': instructions.emplace_back(std::bind_front(&Action::jodaDayOfWeek1Based, repetitions)); /// Day of week range [1, 7] @@ -1232,7 +1270,11 @@ public: reserve_size += std::max(repetitions, 2); break; case 'S': - throw Exception("format is not supported for FRACTION_OF_SECOND", ErrorCodes::NOT_IMPLEMENTED); + /// Default fraction of second is 0 + instructions.emplace_back(std::bind_front(&Action::jodaFractionOfSecond, repetitions)); + /// 'S' repetitions range [0, 9] + reserve_size += repetitions <= 9 ? repetitions : 9; + break; case 'z': if (repetitions <= 3) throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Short name time zone is not yet supported"); diff --git a/tests/queries/0_stateless/02496_format_datetime_in_joda_syntax.reference b/tests/queries/0_stateless/02496_format_datetime_in_joda_syntax.reference index c3a931a5ebb..cc6b2f8cbbc 100644 --- a/tests/queries/0_stateless/02496_format_datetime_in_joda_syntax.reference +++ b/tests/queries/0_stateless/02496_format_datetime_in_joda_syntax.reference @@ -121,3 +121,29 @@ with '2018-01-12 22:33:44' as s, toDateTime(s) as datetime, toDateTime64(s, 6) a ADaaa012 ADaaa012 ADaaa012 ADaaa012 with '2018-01-12 22:33:44' as s, toDateTime(s) as datetime, toDateTime64(s, 6) as datetime64, toDate(s) as date, toDate32(s) as date32 SELECT formatDateTimeInJodaSyntax(datetime, 'G\'a\'\'aa\'DDD'), formatDateTimeInJodaSyntax(datetime64, 'G\'a\'\'aa\'DDD'), formatDateTimeInJodaSyntax(date, 'G\'a\'\'aa\'DDD'), formatDateTimeInJodaSyntax(date32, 'G\'a\'\'aa\'DDD'); ADa\'aa012 ADa\'aa012 ADa\'aa012 ADa\'aa012 +with '2018-01-12 22:33:44' as s, toDateTime(s) as datetime, toDateTime64(s, 6) as datetime64, toDate(s) as date, toDate32(s) as date32 SELECT formatDateTimeInJodaSyntax(datetime, 'x'), formatDateTimeInJodaSyntax(datetime64, 'x'), formatDateTimeInJodaSyntax(date, 'x'), formatDateTimeInJodaSyntax(date32, 'x'); +2018 2018 2018 2018 +with '2018-01-12 22:33:44' as s, toDateTime(s) as datetime, toDateTime64(s, 6) as datetime64, toDate(s) as date, toDate32(s) as date32 SELECT formatDateTimeInJodaSyntax(datetime, 'w'), formatDateTimeInJodaSyntax(datetime64, 'w'), formatDateTimeInJodaSyntax(date, 'w'), formatDateTimeInJodaSyntax(date32, 'w'); +2 2 2 2 +with '2018-01-12 22:33:44' as s, toDateTime(s) as datetime, toDateTime64(s, 6) as datetime64, toDate(s) as date, toDate32(s) as date32 SELECT formatDateTimeInJodaSyntax(datetime, 'S'), formatDateTimeInJodaSyntax(datetime64, 'S'), formatDateTimeInJodaSyntax(date, 'S'), formatDateTimeInJodaSyntax(date32, 'S'); +0 0 0 0 +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'S'); +5 +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SS'); +55 +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SSS'); +550 +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SSSS'); +5500 +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SSSSS'); +55000 +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SSSSSS'); +550000 +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SSSSSSS'); +5500000 +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SSSSSSSS'); +55000000 +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SSSSSSSSS'); +550000000 +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SSSSSSSSSS'); +550000000 diff --git a/tests/queries/0_stateless/02496_format_datetime_in_joda_syntax.sql b/tests/queries/0_stateless/02496_format_datetime_in_joda_syntax.sql index 4c1839b04e6..6dc45350c68 100644 --- a/tests/queries/0_stateless/02496_format_datetime_in_joda_syntax.sql +++ b/tests/queries/0_stateless/02496_format_datetime_in_joda_syntax.sql @@ -62,20 +62,30 @@ with '2018-01-12 22:33:44' as s, toDateTime(s) as datetime, toDateTime64(s, 6) a with '2018-01-12 22:33:44' as s, toDateTime(s) as datetime, toDateTime64(s, 6) as datetime64, toDate(s) as date, toDate32(s) as date32 SELECT formatDateTimeInJodaSyntax(datetime, 'G\'\'DDD'), formatDateTimeInJodaSyntax(datetime64, 'G\'\'DDD'), formatDateTimeInJodaSyntax(date, 'G\'\'DDD'), formatDateTimeInJodaSyntax(date32, 'G\'\'DDD'); with '2018-01-12 22:33:44' as s, toDateTime(s) as datetime, toDateTime64(s, 6) as datetime64, toDate(s) as date, toDate32(s) as date32 SELECT formatDateTimeInJodaSyntax(datetime, 'G\'aaa\'DDD'), formatDateTimeInJodaSyntax(datetime64, 'G\'aaa\'DDD'), formatDateTimeInJodaSyntax(date, 'G\'aaa\'DDD'), formatDateTimeInJodaSyntax(date32, 'G\'aaa\'DDD'); with '2018-01-12 22:33:44' as s, toDateTime(s) as datetime, toDateTime64(s, 6) as datetime64, toDate(s) as date, toDate32(s) as date32 SELECT formatDateTimeInJodaSyntax(datetime, 'G\'a\'\'aa\'DDD'), formatDateTimeInJodaSyntax(datetime64, 'G\'a\'\'aa\'DDD'), formatDateTimeInJodaSyntax(date, 'G\'a\'\'aa\'DDD'), formatDateTimeInJodaSyntax(date32, 'G\'a\'\'aa\'DDD'); + +with '2018-01-12 22:33:44' as s, toDateTime(s) as datetime, toDateTime64(s, 6) as datetime64, toDate(s) as date, toDate32(s) as date32 SELECT formatDateTimeInJodaSyntax(datetime, 'x'), formatDateTimeInJodaSyntax(datetime64, 'x'), formatDateTimeInJodaSyntax(date, 'x'), formatDateTimeInJodaSyntax(date32, 'x'); + +with '2018-01-12 22:33:44' as s, toDateTime(s) as datetime, toDateTime64(s, 6) as datetime64, toDate(s) as date, toDate32(s) as date32 SELECT formatDateTimeInJodaSyntax(datetime, 'w'), formatDateTimeInJodaSyntax(datetime64, 'w'), formatDateTimeInJodaSyntax(date, 'w'), formatDateTimeInJodaSyntax(date32, 'w'); + +with '2018-01-12 22:33:44' as s, toDateTime(s) as datetime, toDateTime64(s, 6) as datetime64, toDate(s) as date, toDate32(s) as date32 SELECT formatDateTimeInJodaSyntax(datetime, 'S'), formatDateTimeInJodaSyntax(datetime64, 'S'), formatDateTimeInJodaSyntax(date, 'S'), formatDateTimeInJodaSyntax(date32, 'S'); +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'S'); +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SS'); +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SSS'); +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SSSS'); +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SSSSS'); +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SSSSSS'); +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SSSSSSS'); +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SSSSSSSS'); +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SSSSSSSSS'); +with '2018-01-12 22:33:44.55' as s, toDateTime64(s, 6) as datetime64 SELECT formatDateTimeInJodaSyntax(datetime64, 'SSSSSSSSSS'); -- { echoOff } -SELECT formatDateTimeInJodaSyntax(toDateTime('2018-01-12 22:33:44'), 'x'); -- { serverError 48 } -SELECT formatDateTimeInJodaSyntax(toDateTime('2018-01-12 22:33:44'), 'w'); -- { serverError 48 } -SELECT formatDateTimeInJodaSyntax(toDateTime('2018-01-12 22:33:44'), 'S'); -- { serverError 48 } SELECT formatDateTimeInJodaSyntax(toDateTime('2018-01-12 22:33:44'), 'z'); -- { serverError 48 } SELECT formatDateTimeInJodaSyntax(toDateTime('2018-01-12 22:33:44'), 'zz'); -- { serverError 48 } SELECT formatDateTimeInJodaSyntax(toDateTime('2018-01-12 22:33:44'), 'zzz'); -- { serverError 48 } SELECT formatDateTimeInJodaSyntax(toDateTime('2018-01-12 22:33:44'), 'Z'); -- { serverError 48 } SELECT formatDateTimeInJodaSyntax(toDateTime('2018-01-12 22:33:44'), 'b'); -- { serverError 48 } -SELECT formatDateTimeInJodaSyntax(toDate32('2018-01-12 22:33:44'), 'x'); -- { serverError 48 } -SELECT formatDateTimeInJodaSyntax(toDate32('2018-01-12 22:33:44'), 'w'); -- { serverError 48 } -SELECT formatDateTimeInJodaSyntax(toDate32('2018-01-12 22:33:44'), 'S'); -- { serverError 48 } SELECT formatDateTimeInJodaSyntax(toDate32('2018-01-12 22:33:44'), 'z'); -- { serverError 48 } SELECT formatDateTimeInJodaSyntax(toDate32('2018-01-12 22:33:44'), 'zz'); -- { serverError 48 } SELECT formatDateTimeInJodaSyntax(toDate32('2018-01-12 22:33:44'), 'zzz'); -- { serverError 48 }