summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhcpp <[email protected]>2022-11-11 16:15:35 +0300
committerhcpp <[email protected]>2022-11-11 16:15:35 +0300
commitaed6befa1e8b55977e692c991fb5a06312fbcfdb (patch)
tree44cf579b52527b899d74b3fb71c2ece14274dc9f
parenteb299967e503717d223751ed6a2f3c834429f60e (diff)
shift has been fixed for path generator
-rw-r--r--ydb/library/yql/minikql/CMakeLists.txt1
-rw-r--r--ydb/library/yql/minikql/datetime/CMakeLists.txt22
-rw-r--r--ydb/library/yql/minikql/datetime/datetime.cpp51
-rw-r--r--ydb/library/yql/minikql/datetime/datetime.h161
-rw-r--r--ydb/library/yql/providers/s3/path_generator/CMakeLists.txt4
-rw-r--r--ydb/library/yql/providers/s3/path_generator/ut/CMakeLists.darwin.txt1
-rw-r--r--ydb/library/yql/providers/s3/path_generator/ut/CMakeLists.linux-aarch64.txt1
-rw-r--r--ydb/library/yql/providers/s3/path_generator/ut/CMakeLists.linux.txt1
-rw-r--r--ydb/library/yql/providers/s3/path_generator/ut/yql_generate_partitioning_rules_ut.cpp4
-rw-r--r--ydb/library/yql/providers/s3/path_generator/yql_s3_path_generator.cpp65
-rw-r--r--ydb/library/yql/udfs/common/datetime2/CMakeLists.txt2
-rw-r--r--ydb/library/yql/udfs/common/datetime2/datetime_udf.cpp256
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; \
}