diff options
author | hcpp <[email protected]> | 2022-11-11 16:15:35 +0300 |
---|---|---|
committer | hcpp <[email protected]> | 2022-11-11 16:15:35 +0300 |
commit | aed6befa1e8b55977e692c991fb5a06312fbcfdb (patch) | |
tree | 44cf579b52527b899d74b3fb71c2ece14274dc9f | |
parent | eb299967e503717d223751ed6a2f3c834429f60e (diff) |
shift has been fixed for path generator
12 files changed, 349 insertions, 220 deletions
diff --git a/ydb/library/yql/minikql/CMakeLists.txt b/ydb/library/yql/minikql/CMakeLists.txt index e91dcfdbd71..b2863b1b876 100644 --- a/ydb/library/yql/minikql/CMakeLists.txt +++ b/ydb/library/yql/minikql/CMakeLists.txt @@ -11,6 +11,7 @@ add_subdirectory(benchmark) add_subdirectory(codegen) add_subdirectory(comp_nodes) add_subdirectory(computation) +add_subdirectory(datetime) add_subdirectory(dom) add_subdirectory(invoke_builtins) add_subdirectory(jsonpath) diff --git a/ydb/library/yql/minikql/datetime/CMakeLists.txt b/ydb/library/yql/minikql/datetime/CMakeLists.txt new file mode 100644 index 00000000000..f330c83c534 --- /dev/null +++ b/ydb/library/yql/minikql/datetime/CMakeLists.txt @@ -0,0 +1,22 @@ + +# This file was gererated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(yql-minikql-datetime) +target_compile_options(yql-minikql-datetime PRIVATE + -DUSE_CURRENT_UDF_ABI_VERSION +) +target_link_libraries(yql-minikql-datetime PUBLIC + contrib-libs-cxxsupp + yutil + library-yql-minikql + yql-minikql-computation +) +target_sources(yql-minikql-datetime PRIVATE + ${CMAKE_SOURCE_DIR}/ydb/library/yql/minikql/datetime/datetime.cpp +) diff --git a/ydb/library/yql/minikql/datetime/datetime.cpp b/ydb/library/yql/minikql/datetime/datetime.cpp new file mode 100644 index 00000000000..cfa9fc1ddee --- /dev/null +++ b/ydb/library/yql/minikql/datetime/datetime.cpp @@ -0,0 +1,51 @@ +#include "datetime.h" + +#include <ydb/library/yql/minikql/mkql_type_ops.h> + +namespace NYql::DateTime { + +bool DoAddMonths(TTMStorage& storage, i64 months, const NUdf::IDateBuilder& builder) { + i64 newMonth = months + storage.Month; + storage.Year += (newMonth - 1) / 12; + newMonth = 1 + (newMonth - 1) % 12; + if (newMonth <= 0) { + storage.Year--; + newMonth += 12; + } + storage.Month = newMonth; + bool isLeap = NKikimr::NMiniKQL::IsLeapYear(storage.Year); + ui32 monthLength = NKikimr::NMiniKQL::GetMonthLength(storage.Month, isLeap); + storage.Day = std::min(monthLength, storage.Day); + return storage.Validate(builder); +} + +bool DoAddYears(TTMStorage& storage, i64 years, const NUdf::IDateBuilder& builder) { + storage.Year += years; + if (storage.Month == 2 && storage.Day == 29) { + bool isLeap = NKikimr::NMiniKQL::IsLeapYear(storage.Year); + if (!isLeap) { + storage.Day--; + } + } + return storage.Validate(builder); +} + +TInstant DoAddMonths(TInstant current, i64 months, const NUdf::IDateBuilder& builder) { + TTMStorage storage; + storage.FromTimestamp(builder, current.GetValue()); + if (!DoAddMonths(storage, months, builder)) { + ythrow yexception() << "Shift error " << current.ToIsoStringLocal() << " by " << months << " months"; + } + return TInstant::FromValue(storage.ToTimestamp(builder)); +} + +TInstant DoAddYears(TInstant current, i64 years, const NUdf::IDateBuilder& builder) { + TTMStorage storage; + storage.FromTimestamp(builder, current.GetValue()); + if (!DoAddYears(storage, years, builder)) { + ythrow yexception() << "Shift error " << current.ToIsoStringLocal() << " by " << years << " years"; + } + return TInstant::FromValue(storage.ToTimestamp(builder)); +} + +} diff --git a/ydb/library/yql/minikql/datetime/datetime.h b/ydb/library/yql/minikql/datetime/datetime.h new file mode 100644 index 00000000000..71363b27cdf --- /dev/null +++ b/ydb/library/yql/minikql/datetime/datetime.h @@ -0,0 +1,161 @@ +#pragma once + +#include <ydb/library/yql/public/udf/udf_value_builder.h> + +#include <util/datetime/base.h> + +namespace NYql::DateTime { + +constexpr size_t MAX_TIMEZONE_NAME_LEN = 64; + +struct TTMStorage { + unsigned int Year : 12; + unsigned int DayOfYear : 9; + unsigned int WeekOfYear : 6; + unsigned int WeekOfYearIso8601 : 6; + unsigned int DayOfWeek : 3; + unsigned int Month : 4; + unsigned int Day : 5; + unsigned int Hour : 5; + unsigned int Minute : 6; + unsigned int Second : 6; + unsigned int Microsecond : 20; + unsigned int TimezoneId : 16; + + TTMStorage() { + Zero(*this); + } + + inline static bool IsUniversal(ui16 timezoneId) { + return timezoneId == 0; + } + + inline void MakeDefault() { + Year = 1970; + Month = 1; + Day = 1; + Hour = 0; + Minute = 0; + Second = 0; + Microsecond = 0; + TimezoneId = 0; + } + + inline void FromDate(const NUdf::IDateBuilder& builder, ui16 value, ui16 timezoneId = 0) { + ui32 year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek; + + if (!builder.FullSplitDate2(value, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek, timezoneId)) { + ythrow yexception() << "Error in FullSplitDate"; + } + + TimezoneId = timezoneId; + + Year = year; + Month = month; + Day = day; + + DayOfYear = dayOfYear; + WeekOfYear = weekOfYear; + WeekOfYearIso8601 = weekOfYearIso8601; + DayOfWeek = dayOfWeek; + } + + inline ui16 ToDate(const NUdf::IDateBuilder& builder, bool local) const { + if (!IsUniversal(TimezoneId)) { + ui32 datetime; + if (!builder.MakeDatetime(Year, Month, Day, local ? 0 : Hour, local ? 0 : Minute, local ? 0 : Second, datetime, TimezoneId)) { + ythrow yexception() << "Error in MakeDatetime"; + } + return datetime / 86400u; + } else { + ui16 date; + if (!builder.MakeDate(Year, Month, Day, date)) { + ythrow yexception() << "Error in MakeDate"; + } + return date; + } + } + + inline void FromDatetime(const NUdf::IDateBuilder& builder, ui32 value, ui16 timezoneId = 0) { + ui32 year, month, day, hour, minute, second, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek; + + if (!builder.FullSplitDatetime2(value, year, month, day, hour, minute, second, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek, timezoneId)) { + ythrow yexception() << "Error in FullSplitDatetime"; + } + + TimezoneId = timezoneId; + Year = year; + Month = month; + Day = day; + Hour = hour; + Minute = minute; + Second = second; + + DayOfYear = dayOfYear; + WeekOfYear = weekOfYear; + WeekOfYearIso8601 = weekOfYearIso8601; + DayOfWeek = dayOfWeek; + } + + inline ui32 ToDatetime(const NUdf::IDateBuilder& builder) const { + ui32 datetime = 0; + if (!builder.MakeDatetime(Year, Month, Day, Hour, Minute, Second, datetime, TimezoneId)) { + ythrow yexception() << "Error in MakeDatetime"; + } + return datetime; + } + + inline void FromTimestamp(const NUdf::IDateBuilder& builder, ui64 value, ui16 timezoneId = 0) { + const ui32 seconds = value / 1000000ull; + FromDatetime(builder, seconds, timezoneId); + Microsecond = value - seconds * 1000000ull; + } + + inline ui64 ToTimestamp(const NUdf::IDateBuilder& builder) const { + return ToDatetime(builder) * 1000000ull + Microsecond; + } + + inline bool Validate(const NUdf::IDateBuilder& builder) { + ui32 datetime; + if (!builder.MakeDatetime(Year, Month, Day, Hour, Minute, Second, datetime, TimezoneId)) { + return false; + } + + ui32 year, month, day, hour, minute, second, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek; + if (!builder.FullSplitDatetime2(datetime, year, month, day, hour, minute, second, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek, TimezoneId)) { + ythrow yexception() << "Error in FullSplitDatetime."; + } + + DayOfYear = dayOfYear; + WeekOfYear = weekOfYear; + WeekOfYearIso8601 = weekOfYearIso8601; + DayOfWeek = dayOfWeek; + + return true; + } + + inline void FromTimeOfDay(ui64 value) { + Hour = value / 3600000000ull; + value -= Hour * 3600000000ull; + Minute = value / 60000000ull; + value -= Minute * 60000000ull; + Second = value / 1000000ull; + Microsecond = value - Second * 1000000ull; + } + + inline ui64 ToTimeOfDay() const { + return ((Hour * 60ull + Minute) * 60ull + Second) * 1000000ull + Microsecond; + } +}; + +static_assert(sizeof(TTMStorage) == 16, "TTMStorage size must be equal to TUnboxedValuePod size"); + +bool DoAddMonths(TTMStorage& storage, i64 months, const NUdf::IDateBuilder& builder); + +bool DoAddYears(TTMStorage& storage, i64 years, const NUdf::IDateBuilder& builder); + +TInstant DoAddMonths(TInstant current, i64 months, const NUdf::IDateBuilder& builder); + +TInstant DoAddYears(TInstant current, i64 years, const NUdf::IDateBuilder& builder); + +} diff --git a/ydb/library/yql/providers/s3/path_generator/CMakeLists.txt b/ydb/library/yql/providers/s3/path_generator/CMakeLists.txt index 8c8cac7332b..2e797ac3ce9 100644 --- a/ydb/library/yql/providers/s3/path_generator/CMakeLists.txt +++ b/ydb/library/yql/providers/s3/path_generator/CMakeLists.txt @@ -9,10 +9,14 @@ add_subdirectory(ut) add_library(providers-s3-path_generator) +target_compile_options(providers-s3-path_generator PRIVATE + -DUSE_CURRENT_UDF_ABI_VERSION +) target_link_libraries(providers-s3-path_generator PUBLIC contrib-libs-cxxsupp yutil library-cpp-scheme + yql-minikql-datetime yql-public-udf tools-enum_parser-enum_serialization_runtime ) diff --git a/ydb/library/yql/providers/s3/path_generator/ut/CMakeLists.darwin.txt b/ydb/library/yql/providers/s3/path_generator/ut/CMakeLists.darwin.txt index 3d2faa56a52..8e2ec3f2466 100644 --- a/ydb/library/yql/providers/s3/path_generator/ut/CMakeLists.darwin.txt +++ b/ydb/library/yql/providers/s3/path_generator/ut/CMakeLists.darwin.txt @@ -22,6 +22,7 @@ target_link_libraries(ydb-library-yql-providers-s3-path_generator-ut PUBLIC providers-s3-path_generator library-yql-minikql udf-service-stub + yql-sql-pg_dummy ) target_link_options(ydb-library-yql-providers-s3-path_generator-ut PRIVATE -Wl,-no_deduplicate diff --git a/ydb/library/yql/providers/s3/path_generator/ut/CMakeLists.linux-aarch64.txt b/ydb/library/yql/providers/s3/path_generator/ut/CMakeLists.linux-aarch64.txt index 9c61559de37..db766a53fd0 100644 --- a/ydb/library/yql/providers/s3/path_generator/ut/CMakeLists.linux-aarch64.txt +++ b/ydb/library/yql/providers/s3/path_generator/ut/CMakeLists.linux-aarch64.txt @@ -22,6 +22,7 @@ target_link_libraries(ydb-library-yql-providers-s3-path_generator-ut PUBLIC providers-s3-path_generator library-yql-minikql udf-service-stub + yql-sql-pg_dummy ) target_link_options(ydb-library-yql-providers-s3-path_generator-ut PRIVATE -ldl diff --git a/ydb/library/yql/providers/s3/path_generator/ut/CMakeLists.linux.txt b/ydb/library/yql/providers/s3/path_generator/ut/CMakeLists.linux.txt index 4209b249dde..9a809469d71 100644 --- a/ydb/library/yql/providers/s3/path_generator/ut/CMakeLists.linux.txt +++ b/ydb/library/yql/providers/s3/path_generator/ut/CMakeLists.linux.txt @@ -24,6 +24,7 @@ target_link_libraries(ydb-library-yql-providers-s3-path_generator-ut PUBLIC providers-s3-path_generator library-yql-minikql udf-service-stub + yql-sql-pg_dummy ) target_link_options(ydb-library-yql-providers-s3-path_generator-ut PRIVATE -ldl diff --git a/ydb/library/yql/providers/s3/path_generator/ut/yql_generate_partitioning_rules_ut.cpp b/ydb/library/yql/providers/s3/path_generator/ut/yql_generate_partitioning_rules_ut.cpp index 0ab1ff286eb..99851fd7bb5 100644 --- a/ydb/library/yql/providers/s3/path_generator/ut/yql_generate_partitioning_rules_ut.cpp +++ b/ydb/library/yql/providers/s3/path_generator/ut/yql_generate_partitioning_rules_ut.cpp @@ -235,11 +235,13 @@ Y_UNIT_TEST_SUITE(TGenerateTests) { )", {"dt"}); auto rules = generator->GetRules(); - UNIT_ASSERT_VALUES_EQUAL(rules.size(), 2); + UNIT_ASSERT_VALUES_EQUAL(rules.size(), 3); UNIT_ASSERT_VALUES_EQUAL(rules[0].Path, "yellow_tripdata_asdf%0 asdf2012%0 444-01.csv"); UNIT_ASSERT_VALUES_EQUAL(rules[0].ColumnValues.size(), 1); UNIT_ASSERT_VALUES_EQUAL(rules[1].Path, "yellow_tripdata_asdf%0 asdf2013%0 444-01.csv"); UNIT_ASSERT_VALUES_EQUAL(rules[1].ColumnValues.size(), 1); + UNIT_ASSERT_VALUES_EQUAL(rules[2].Path, "yellow_tripdata_asdf%0 asdf2014%0 444-01.csv"); + UNIT_ASSERT_VALUES_EQUAL(rules[2].ColumnValues.size(), 1); } Y_UNIT_TEST(TimestampFormatCheck) { diff --git a/ydb/library/yql/providers/s3/path_generator/yql_s3_path_generator.cpp b/ydb/library/yql/providers/s3/path_generator/yql_s3_path_generator.cpp index 3b180e84719..719d2060047 100644 --- a/ydb/library/yql/providers/s3/path_generator/yql_s3_path_generator.cpp +++ b/ydb/library/yql/providers/s3/path_generator/yql_s3_path_generator.cpp @@ -8,6 +8,11 @@ #include <util/string/split.h> #include <util/string/strip.h> +#include <ydb/library/yql/minikql/computation/mkql_value_builder.h> +#include <ydb/library/yql/minikql/datetime/datetime.h> +#include <ydb/library/yql/minikql/mkql_alloc.h> +#include <ydb/library/yql/public/udf/udf_value_builder.h> + namespace NYql::NPathGenerator { namespace { @@ -164,15 +169,47 @@ TDuration FromUnit(int64_t interval, IPathGenerator::EIntervalUnit unit) { return TDuration::Days(interval); case IPathGenerator::EIntervalUnit::WEEKS: return TDuration::Days(interval * 7); - case IPathGenerator::EIntervalUnit::MONTHS: - return TDuration::Seconds(interval * 2629746LL); /// Exactly 1/12 of a year. + case IPathGenerator::EIntervalUnit::MONTHS: // external special handling case IPathGenerator::EIntervalUnit::YEARS: - return TDuration::Seconds(interval * 31556952LL); /// The average length of a Gregorian year is equal to 365.2425 days default: ythrow yexception() << "Only the " << GetEnumAllNames<IPathGenerator::EIntervalUnit>() << " units are supported but got " << unit; } } +TInstant DoAddMonths(TInstant current, i64 months) { + NKikimr::NMiniKQL::TScopedAlloc alloc{__LOCATION__}; + NKikimr::NMiniKQL::TMemoryUsageInfo memInfo("MemoryAddMonths"); + NKikimr::NMiniKQL::THolderFactory holderFactory(alloc.Ref(), memInfo); + NKikimr::NMiniKQL::TDefaultValueBuilder builder(holderFactory); + return DateTime::DoAddMonths(current, months, builder.GetDateBuilder()); +} + +TInstant DoAddYears(TInstant current, i64 years) { + NKikimr::NMiniKQL::TScopedAlloc alloc{__LOCATION__}; + NKikimr::NMiniKQL::TMemoryUsageInfo memInfo("MemoryAddYears"); + NKikimr::NMiniKQL::THolderFactory holderFactory(alloc.Ref(), memInfo); + NKikimr::NMiniKQL::TDefaultValueBuilder builder(holderFactory); + return DateTime::DoAddYears(current, years, builder.GetDateBuilder()); +} + +TInstant AddUnit(TInstant current, int64_t interval, IPathGenerator::EIntervalUnit unit) { + if (unit == IPathGenerator::EIntervalUnit::MONTHS) { + return DoAddMonths(current, interval); + } + + if (unit == IPathGenerator::EIntervalUnit::YEARS) { + return DoAddYears(current, interval); + } + + + const TDuration delta = FromUnit(interval, unit); + if (IsOverflow(current.GetValue(), delta.GetValue())) { + ythrow yexception() << "Timestamp is overflowed"; + } + + return current + delta; +} + TInstant ParseDate(const TString& dateStr, const TInstant& now) { try { size_t idx = 0; @@ -194,7 +231,7 @@ TInstant ParseDate(const TString& dateStr, const TInstant& now) { const TString offset = (it + 4)->str(); const TString unit = (it + 5)->str(); if (sign) { - return now + (sign.front() == '+' ? 1 : -1) * FromUnit(stoll(offset), ToIntervalUnit(unit)); + return AddUnit(now, (sign.front() == '+' ? 1 : -1) * stoll(offset), ToIntervalUnit(unit)); } else { return now; } @@ -535,17 +572,17 @@ private: size_t p = 0) { const auto& rule = rules[p]; const TInstant to = ParseDate(rule.To, now); - const TDuration interval = FromUnit(rule.Interval, rule.IntervalUnit); - for (TInstant current = ParseDate(rule.From, now); current <= to; current += interval) { - TString copyLocationTemplate = locationTemplate; - const TString time = Strftime(rule.Format.c_str(), current); - ReplaceAll(copyLocationTemplate, "${" + rule.Name + "}", time); - columnsWithValue.push_back(TColumnWithValue{.Name=rule.Name, .Type=NUdf::EDataSlot::Date, .Value=Strftime("%F", current)}); - DoGenerate(rules, copyLocationTemplate, columnsWithValue, result, pathsLimit, now, p + 1); - columnsWithValue.pop_back(); - if (IsOverflow(current.GetValue(), interval.GetValue())) { - return; // correct overflow handling + try { + for (TInstant current = ParseDate(rule.From, now); current <= to; current = AddUnit(current, rule.Interval, rule.IntervalUnit)) { + TString copyLocationTemplate = locationTemplate; + const TString time = Strftime(rule.Format.c_str(), current); + ReplaceAll(copyLocationTemplate, "${" + rule.Name + "}", time); + columnsWithValue.push_back(TColumnWithValue{.Name=rule.Name, .Type=NUdf::EDataSlot::Date, .Value=Strftime("%F", current)}); + DoGenerate(rules, copyLocationTemplate, columnsWithValue, result, pathsLimit, now, p + 1); + columnsWithValue.pop_back(); } + } catch (...) { + // correct overflow handling } } diff --git a/ydb/library/yql/udfs/common/datetime2/CMakeLists.txt b/ydb/library/yql/udfs/common/datetime2/CMakeLists.txt index eb0d1e77daa..bd6afb9aed1 100644 --- a/ydb/library/yql/udfs/common/datetime2/CMakeLists.txt +++ b/ydb/library/yql/udfs/common/datetime2/CMakeLists.txt @@ -15,6 +15,7 @@ target_link_libraries(datetime2_udf INTERFACE public-udf-support util-draft library-yql-minikql + yql-minikql-datetime public-udf-tz ) @@ -31,6 +32,7 @@ target_link_libraries(datetime2_udf.global PUBLIC public-udf-support util-draft library-yql-minikql + yql-minikql-datetime public-udf-tz ) target_sources(datetime2_udf.global PRIVATE diff --git a/ydb/library/yql/udfs/common/datetime2/datetime_udf.cpp b/ydb/library/yql/udfs/common/datetime2/datetime_udf.cpp index f0ce659db47..731b2f85c9b 100644 --- a/ydb/library/yql/udfs/common/datetime2/datetime_udf.cpp +++ b/ydb/library/yql/udfs/common/datetime2/datetime_udf.cpp @@ -1,11 +1,13 @@ -#include <ydb/library/yql/public/udf/udf_helpers.h> -#include <ydb/library/yql/public/udf/tz/udf_tz.h> #include <ydb/library/yql/minikql/mkql_type_ops.h> +#include <ydb/library/yql/public/udf/tz/udf_tz.h> +#include <ydb/library/yql/public/udf/udf_helpers.h> +#include <ydb/library/yql/minikql/datetime/datetime.h> #include <util/datetime/base.h> using namespace NKikimr; using namespace NUdf; +using namespace NYql::DateTime; extern const char SplitName[] = "Split"; extern const char ToSecondsName[] = "ToSeconds"; @@ -16,160 +18,37 @@ extern const char TMResourceName[] = "DateTime2.TM"; namespace { - constexpr size_t MAX_TIMEZONE_NAME_LEN = 64; - - struct TTMStorage { - unsigned int Year : 12; - unsigned int DayOfYear : 9; - unsigned int WeekOfYear : 6; - unsigned int WeekOfYearIso8601 : 6; - unsigned int DayOfWeek : 3; - unsigned int Month : 4; - unsigned int Day : 5; - unsigned int Hour : 5; - unsigned int Minute : 6; - unsigned int Second : 6; - unsigned int Microsecond : 20; - unsigned int TimezoneId : 16; - - inline static bool IsUniversal(ui16 timezoneId) { - return timezoneId == 0; - } - - inline void MakeDefault() { - Year = 1970; - Month = 1; - Day = 1; - Hour = 0; - Minute = 0; - Second = 0; - Microsecond = 0; - TimezoneId = 0; - } - - inline void FromDate(const IDateBuilder& builder, ui16 value, ui16 timezoneId = 0) { - ui32 year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek; - - if (!builder.FullSplitDate2(value, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek, timezoneId)) { - ythrow yexception() << "Error in FullSplitDate"; - } - - TimezoneId = timezoneId; - - Year = year; - Month = month; - Day = day; - - DayOfYear = dayOfYear; - WeekOfYear = weekOfYear; - WeekOfYearIso8601 = weekOfYearIso8601; - DayOfWeek = dayOfWeek; - } - - inline ui16 ToDate(const IDateBuilder& builder, bool local) const { - if (!IsUniversal(TimezoneId)) { - ui32 datetime; - if (!builder.MakeDatetime(Year, Month, Day, local ? 0 : Hour, local ? 0 : Minute, local ? 0 : Second, datetime, TimezoneId)) { - ythrow yexception() << "Error in MakeDatetime"; - } - return datetime / 86400u; - } else { - ui16 date; - if (!builder.MakeDate(Year, Month, Day, date)) { - ythrow yexception() << "Error in MakeDate"; - } - return date; - } - } - - inline void FromDatetime(const IDateBuilder& builder, ui32 value, ui16 timezoneId = 0) { - ui32 year, month, day, hour, minute, second, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek; - - if (!builder.FullSplitDatetime2(value, year, month, day, hour, minute, second, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek, timezoneId)) { - ythrow yexception() << "Error in FullSplitDatetime"; - } - - TimezoneId = timezoneId; - Year = year; - Month = month; - Day = day; - Hour = hour; - Minute = minute; - Second = second; - - DayOfYear = dayOfYear; - WeekOfYear = weekOfYear; - WeekOfYearIso8601 = weekOfYearIso8601; - DayOfWeek = dayOfWeek; - } - - inline ui32 ToDatetime(const IDateBuilder& builder) const { - ui32 datetime = 0; - if (!builder.MakeDatetime(Year, Month, Day, Hour, Minute, Second, datetime, TimezoneId)) { - ythrow yexception() << "Error in MakeDatetime"; - } - return datetime; - } - - inline void FromTimestamp(const IDateBuilder& builder, ui64 value, ui16 timezoneId = 0) { - const ui32 seconds = value / 1000000ull; - FromDatetime(builder, seconds, timezoneId); - Microsecond = value - seconds * 1000000ull; - } - - inline ui64 ToTimestamp(const IDateBuilder& builder) const { - return ToDatetime(builder) * 1000000ull + Microsecond; - } - - inline bool Validate(const IDateBuilder& builder) { - ui32 datetime; - if (!builder.MakeDatetime(Year, Month, Day, Hour, Minute, Second, datetime, TimezoneId)) { - return false; - } - - ui32 year, month, day, hour, minute, second, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek; - if (!builder.FullSplitDatetime2(datetime, year, month, day, hour, minute, second, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek, TimezoneId)) { - ythrow yexception() << "Error in FullSplitDatetime."; - } - - DayOfYear = dayOfYear; - WeekOfYear = weekOfYear; - WeekOfYearIso8601 = weekOfYearIso8601; - DayOfWeek = dayOfWeek; - - return true; - } - - inline void FromTimeOfDay(ui64 value) { - Hour = value / 3600000000ull; - value -= Hour * 3600000000ull; - Minute = value / 60000000ull; - value -= Minute * 60000000ull; - Second = value / 1000000ull; - Microsecond = value - Second * 1000000ull; - } - - inline ui64 ToTimeOfDay() const { - return ((Hour * 60ull + Minute) * 60ull + Second) * 1000000ull + Microsecond; - } - - static const TTMStorage& Reference(const TUnboxedValuePod& value) { - return *reinterpret_cast<const TTMStorage*>(value.GetRawPtr()); - } +const TTMStorage& Reference(const NUdf::TUnboxedValuePod& value) { + return *reinterpret_cast<const TTMStorage*>(value.GetRawPtr()); +} - static TTMStorage& Reference(TUnboxedValuePod& value) { - return *reinterpret_cast<TTMStorage*>(value.GetRawPtr()); - } - }; +TTMStorage& Reference(NUdf::TUnboxedValuePod& value) { + return *reinterpret_cast<TTMStorage*>(value.GetRawPtr()); +} - static_assert(sizeof(TTMStorage) == 16, "TTMStorage size must be equal to TUnboxedValuePod size"); +NUdf::TUnboxedValuePod DoAddMonths(const NUdf::TUnboxedValuePod& date, i64 months, const NUdf::IDateBuilder& builder) { + auto result = date; + auto& storage = Reference(result); + if (!NYql::DateTime::DoAddMonths(storage, months, builder)) { + return NUdf::TUnboxedValuePod{}; + } + return result; +} +NUdf::TUnboxedValuePod DoAddYears(const NUdf::TUnboxedValuePod& date, i64 years, const NUdf::IDateBuilder& builder) { + auto result = date; + auto& storage = Reference(result); + if (!NYql::DateTime::DoAddYears(storage, years, builder)) { + return NUdf::TUnboxedValuePod{}; + } + return result; +} #define ACCESSORS(field, type) \ inline type Get##field(const TUnboxedValuePod& tm) { \ - return (type)TTMStorage::Reference(tm).field; \ + return (type)Reference(tm).field; \ } \ Y_DECLARE_UNUSED inline void Set##field(TUnboxedValuePod& tm, type value) { \ - TTMStorage::Reference(tm).field = value; \ + Reference(tm).field = value; \ } ACCESSORS(Year, ui16) @@ -330,7 +209,7 @@ namespace { auto& builder = valueBuilder->GetDateBuilder(); TUnboxedValuePod result(0); - auto& storage = TTMStorage::Reference(result); + auto& storage = Reference(result); storage.FromDate(builder, args[0].Get<ui16>()); return result; } catch (const std::exception& e) { @@ -348,7 +227,7 @@ namespace { auto& builder = valueBuilder->GetDateBuilder(); TUnboxedValuePod result(0); - auto& storage = TTMStorage::Reference(result); + auto& storage = Reference(result); storage.FromDatetime(builder, args[0].Get<ui32>()); return result; } catch (const std::exception& e) { @@ -366,7 +245,7 @@ namespace { auto& builder = valueBuilder->GetDateBuilder(); TUnboxedValuePod result(0); - auto& storage = TTMStorage::Reference(result); + auto& storage = Reference(result); storage.FromTimestamp(builder, args[0].Get<ui64>()); return result; } catch (const std::exception& e) { @@ -384,7 +263,7 @@ namespace { auto& builder = valueBuilder->GetDateBuilder(); TUnboxedValuePod result(0); - auto& storage = TTMStorage::Reference(result); + auto& storage = Reference(result); storage.FromDate(builder, args[0].Get<ui16>(), args[0].GetTimezoneId()); return result; } catch (const std::exception& e) { @@ -402,7 +281,7 @@ namespace { auto& builder = valueBuilder->GetDateBuilder(); TUnboxedValuePod result(0); - auto& storage = TTMStorage::Reference(result); + auto& storage = Reference(result); storage.FromDatetime(builder, args[0].Get<ui32>(), args[0].GetTimezoneId()); return result; } catch (const std::exception& e) { @@ -420,7 +299,7 @@ namespace { auto& builder = valueBuilder->GetDateBuilder(); TUnboxedValuePod result(0); - auto& storage = TTMStorage::Reference(result); + auto& storage = Reference(result); storage.FromTimestamp(builder, args[0].Get<ui64>(), args[0].GetTimezoneId()); return result; } catch (const std::exception& e) { @@ -432,25 +311,25 @@ namespace { SIMPLE_UDF(TMakeDate, TDate(TAutoMap<TResource<TMResourceName>>)) { auto& builder = valueBuilder->GetDateBuilder(); - auto& storage = TTMStorage::Reference(args[0]); + auto& storage = Reference(args[0]); return TUnboxedValuePod(storage.ToDate(builder, false)); } SIMPLE_UDF(TMakeDatetime, TDatetime(TAutoMap<TResource<TMResourceName>>)) { auto& builder = valueBuilder->GetDateBuilder(); - auto& storage = TTMStorage::Reference(args[0]); + auto& storage = Reference(args[0]); return TUnboxedValuePod(storage.ToDatetime(builder)); } SIMPLE_UDF(TMakeTimestamp, TTimestamp(TAutoMap<TResource<TMResourceName>>)) { auto& builder = valueBuilder->GetDateBuilder(); - auto& storage = TTMStorage::Reference(args[0]); + auto& storage = Reference(args[0]); return TUnboxedValuePod(storage.ToTimestamp(builder)); } SIMPLE_UDF(TMakeTzDate, TTzDate(TAutoMap<TResource<TMResourceName>>)) { auto& builder = valueBuilder->GetDateBuilder(); - auto& storage = TTMStorage::Reference(args[0]); + auto& storage = Reference(args[0]); TUnboxedValuePod result(storage.ToDate(builder, true)); result.SetTimezoneId(storage.TimezoneId); return result; @@ -458,7 +337,7 @@ namespace { SIMPLE_UDF(TMakeTzDatetime, TTzDatetime(TAutoMap<TResource<TMResourceName>>)) { auto& builder = valueBuilder->GetDateBuilder(); - auto& storage = TTMStorage::Reference(args[0]); + auto& storage = Reference(args[0]); TUnboxedValuePod result(storage.ToDatetime(builder)); result.SetTimezoneId(storage.TimezoneId); return result; @@ -466,7 +345,7 @@ namespace { SIMPLE_UDF(TMakeTzTimestamp, TTzTimestamp(TAutoMap<TResource<TMResourceName>>)) { auto& builder = valueBuilder->GetDateBuilder(); - auto& storage = TTMStorage::Reference(args[0]); + auto& storage = Reference(args[0]); TUnboxedValuePod result(storage.ToTimestamp(builder)); result.SetTimezoneId(storage.TimezoneId); return result; @@ -626,7 +505,7 @@ namespace { } auto& builder = valueBuilder->GetDateBuilder(); - auto& storage = TTMStorage::Reference(result); + auto& storage = Reference(result); if (!storage.Validate(builder)) { return TUnboxedValuePod(); } @@ -828,7 +707,7 @@ namespace { SIMPLE_UDF(TStartOfYear, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>)) { auto result = args[0]; - auto& storage = TTMStorage::Reference(result); + auto& storage = Reference(result); storage.Month = 1; storage.Day = 1; storage.Hour = 0; @@ -845,7 +724,7 @@ namespace { SIMPLE_UDF(TStartOfQuarter, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>)) { auto result = args[0]; - auto& storage = TTMStorage::Reference(result); + auto& storage = Reference(result); storage.Month = (storage.Month - 1) / 3 * 3 + 1; storage.Day = 1; storage.Hour = 0; @@ -862,7 +741,7 @@ namespace { SIMPLE_UDF(TStartOfMonth, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>)) { auto result = args[0]; - auto& storage = TTMStorage::Reference(result); + auto& storage = Reference(result); storage.Day = 1; storage.Hour = 0; storage.Minute = 0; @@ -878,7 +757,7 @@ namespace { SIMPLE_UDF(TStartOfWeek, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>)) { auto result = args[0]; - auto& storage = TTMStorage::Reference(result); + auto& storage = Reference(result); auto& builder = valueBuilder->GetDateBuilder(); const auto date = storage.ToDatetime(builder); @@ -897,7 +776,7 @@ namespace { SIMPLE_UDF(TStartOfDay, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>)) { auto result = args[0]; - auto& storage = TTMStorage::Reference(result); + auto& storage = Reference(result); storage.Hour = 0; storage.Minute = 0; storage.Second = 0; @@ -916,7 +795,7 @@ namespace { if (interval == 0) { return result; } - auto& storage = TTMStorage::Reference(result); + auto& storage = Reference(result); if (interval >= 86400000000ull) { // treat as StartOfDay storage.Hour = 0; @@ -938,47 +817,14 @@ namespace { SIMPLE_UDF(TTimeOfDay, TInterval(TAutoMap<TResource<TMResourceName>>)) { Y_UNUSED(valueBuilder); - auto& storage = TTMStorage::Reference(args[0]); + auto& storage = Reference(args[0]); return TUnboxedValuePod((i64)storage.ToTimeOfDay()); } // Add ... SIMPLE_UDF(TShiftYears, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>, i32)) { - auto result = args[0]; - auto& storage = TTMStorage::Reference(result); - storage.Year += args[1].Get<i32>(); - if (storage.Month == 2 && storage.Day == 29) { - bool isLeap = NKikimr::NMiniKQL::IsLeapYear(storage.Year); - if (!isLeap) { - storage.Day--; - } - } - auto& builder = valueBuilder->GetDateBuilder(); - if (!storage.Validate(builder)) { - return TUnboxedValuePod(); - } - return result; - } - - TUnboxedValuePod DoAddMonths(const TUnboxedValuePod& date, i64 months, const IDateBuilder& builder) { - auto result = date; - auto& storage = TTMStorage::Reference(result); - i64 newMonth = months + storage.Month; - storage.Year += (newMonth - 1) / 12; - newMonth = 1 + (newMonth - 1) % 12; - if (newMonth <= 0) { - storage.Year--; - newMonth += 12; - } - storage.Month = newMonth; - bool isLeap = NKikimr::NMiniKQL::IsLeapYear(storage.Year); - ui32 monthLength = NKikimr::NMiniKQL::GetMonthLength(storage.Month, isLeap); - storage.Day = std::min(monthLength, storage.Day); - if (!storage.Validate(builder)) { - return TUnboxedValuePod(); - } - return result; + return DoAddYears(args[0], args[1].Get<i32>(), valueBuilder->GetDateBuilder()); } SIMPLE_UDF(TShiftQuarters, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>, i32)) { @@ -1401,7 +1247,7 @@ namespace { const std::string_view buffer = args[0].AsStringRef(); TUnboxedValuePod result(0); - auto& storage = TTMStorage::Reference(result); + auto& storage = Reference(result); storage.MakeDefault(); auto& builder = valueBuilder->GetDateBuilder(); @@ -1629,7 +1475,7 @@ namespace { } \ auto& builder = valueBuilder->GetDateBuilder(); \ TUnboxedValuePod result(0); \ - auto& storage = TTMStorage::Reference(result); \ + auto& storage = Reference(result); \ storage.FromTimestamp(builder, instant.MicroSeconds()); \ return result; \ } |