Browse Source

YQL-18303: Introduce Split and MakeTz* overloads
commit_hash:16a38d1b1de0cc97c5cbf97176331ea6691e23be

imunkin 2 weeks ago
parent
commit
6b6e4dc3a6

+ 11 - 0
yql/essentials/core/type_ann/type_ann_core.cpp

@@ -368,6 +368,17 @@ namespace NTypeAnnImpl {
                     .Build(), ctx.MakeType<TDataExprType>(EDataSlot::TzTimestamp) };
             }
 
+            if (resType->GetTag() == "DateTime2.TM64") {
+                return { ctx.Builder(input->Pos())
+                    .Callable("Apply")
+                        .Callable(0, "Udf")
+                            .Atom(0, "DateTime2.MakeTzTimestamp64", TNodeFlags::Default)
+                        .Seal()
+                        .Add(1, input)
+                    .Seal()
+                    .Build(), ctx.MakeType<TDataExprType>(EDataSlot::TzTimestamp64) };
+            }
+
             if (resType->GetTag() == "JsonNode") {
                 return { ctx.Builder(input->Pos())
                     .Callable("Apply")

+ 2 - 0
yql/essentials/core/type_ann/type_ann_list.cpp

@@ -2400,11 +2400,13 @@ namespace {
                 case EDataSlot::Date:
                 case EDataSlot::TzDate:
                 case EDataSlot::Date32:
+                case EDataSlot::TzDate32:
                     value = ctx.Expr.NewAtom(input->Pos(), "86400000000", TNodeFlags::Default);
                     break;
                 case EDataSlot::Datetime:
                 case EDataSlot::TzDatetime:
                 case EDataSlot::Datetime64:
+                case EDataSlot::TzDatetime64:
                     value = ctx.Expr.NewAtom(input->Pos(), "1000000", TNodeFlags::Default);
                     break;
                 default:

+ 13 - 2
yql/essentials/core/yql_expr_type_annotation.cpp

@@ -335,21 +335,26 @@ IGraphTransformer::TStatus TryConvertToImpl(TExprContext& ctx, TExprNode::TPtr&
         } else if (from == EDataSlot::Date && (
                     to == EDataSlot::Date32 ||
                     to == EDataSlot::TzDate ||
+                    to == EDataSlot::TzDate32 ||
                     to == EDataSlot::Datetime ||
                     to == EDataSlot::Timestamp ||
                     to == EDataSlot::TzDatetime ||
                     to == EDataSlot::TzTimestamp ||
                     to == EDataSlot::Datetime64 ||
-                    to == EDataSlot::Timestamp64))
+                    to == EDataSlot::Timestamp64 ||
+                    to == EDataSlot::TzDatetime64 ||
+                    to == EDataSlot::TzTimestamp64))
         {
             allow = true;
             useCast = true;
         } else if (from == EDataSlot::Datetime && (
                     to == EDataSlot::Datetime64 ||
                     to == EDataSlot::TzDatetime ||
+                    to == EDataSlot::TzDatetime64 ||
                     to == EDataSlot::Timestamp ||
                     to == EDataSlot::TzTimestamp ||
-                    to == EDataSlot::Timestamp64))
+                    to == EDataSlot::Timestamp64 ||
+                    to == EDataSlot::TzTimestamp64))
         {
             allow = true;
             useCast = true;
@@ -365,9 +370,15 @@ IGraphTransformer::TStatus TryConvertToImpl(TExprContext& ctx, TExprNode::TPtr&
         } else if (from == EDataSlot::Date32 && (to == EDataSlot::Datetime64 || to == EDataSlot::Timestamp64)) {
             allow = true;
             useCast = true;
+        } else if (from == EDataSlot::TzDate32 && (to == EDataSlot::TzDatetime64 || to == EDataSlot::TzTimestamp64)) {
+            allow = true;
+            useCast = true;
         } else if (from == EDataSlot::Datetime64 && (to == EDataSlot::Timestamp64)) {
             allow = true;
             useCast = true;
+        } else if (from == EDataSlot::TzDatetime64 && to == EDataSlot::TzTimestamp64) {
+            allow = true;
+            useCast = true;
         } else if (from == EDataSlot::Interval && (to == EDataSlot::Interval64)) {
             allow = true;
             useCast = true;

+ 26 - 6
yql/essentials/minikql/datetime/datetime64.h

@@ -106,13 +106,26 @@ struct TTM64Storage {
         Microsecond = value - datetime * 1000000ll;
     }
 
-    i32 ToDate32(const NUdf::IDateBuilder& builder) const {
-        i32 date;
-        if (!builder.MakeTzDate32(Year, Month, Day, date, TimezoneId)) {
-            ythrow yexception() << "Error in MakeTzDate32 tzId " << TimezoneId
-                << " " << Year << "-" << Month << "-" << Day;
+    i32 ToDate32(const NUdf::IDateBuilder& builder, bool local) const {
+        if (!IsUniversal(TimezoneId)) {
+            i64 datetime;
+            ui32 hour = local ? 0 : Hour;
+            ui32 minute = local ? 0 : Minute;
+            ui32 second = local ? 0 : Second;
+            if (!builder.MakeTzDatetime64(Year, Month, Day, hour, minute, second, datetime, TimezoneId)) {
+                ythrow yexception() << "Error in MakeTzDatetime64 tzId "
+                    << TimezoneId << " " << Year << "-" << Month << "-" << Day
+                    << "T" << hour << ":" << minute << ":" << second;
+            }
+            return datetime / 86400u;
+        } else {
+            i32 date;
+            if (!builder.MakeTzDate32(Year, Month, Day, date, TimezoneId)) {
+                ythrow yexception() << "Error in MakeTzDate32 tzId "
+                    << TimezoneId << " " << Year << "-" << Month << "-" << Day;
+            }
+            return date;
         }
-        return date;
     }
 
     i64 ToDatetime64(const NUdf::IDateBuilder& builder) const {
@@ -160,6 +173,13 @@ struct TTM64Storage {
     inline ui64 ToTimeOfDay() const {
         return ((Hour * 60ull + Minute) * 60ull + Second) * 1000000ull + Microsecond;
     }
+
+    const TString ToString() const {
+        const auto& tzName = NUdf::GetTimezones()[TimezoneId];
+        return Sprintf("%8d-%02d-%02dT%02d:%02d:%02d.%06d,%.*s",
+                       Year, Month, Day, Hour, Minute, Second, Microsecond,
+                       static_cast<int>(tzName.size()), tzName.data());
+    }
 };
 
 }

+ 24 - 11
yql/essentials/minikql/mkql_type_ops.cpp

@@ -894,8 +894,7 @@ public:
     {
         if (tzId) {
             ui32 hour, min, sec;
-            i64 utcSeconds = (date >= 0) ? ((date + 1) * 86400ll - 1) : (date * 86400ll);
-            ToLocalTime64(utcSeconds, tzId, year, month, day, hour, min, sec);
+            ToLocalTime64(86400ll * ++date - 1, tzId, year, month, day, hour, min, sec);
             if (year <= 0) {
                 year--;
             }
@@ -924,7 +923,7 @@ public:
             if (year <= 0) {
                 year--;
             }
-            if (!MakeDate32(year, month, day, date)) {
+            if (!GetDate32Offset(year, month, day, date)) {
                 return false;
             }
             SplitDate32(date, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek);
@@ -986,8 +985,12 @@ public:
         return true;
     }
 
-    bool MakeDate32(i32 year, ui32 month, ui32 day, i32& value) const {
-        if (Y_UNLIKELY(year == 0 || year < NUdf::MIN_YEAR32 || year >= NUdf::MAX_YEAR32)) {
+    bool GetDate32Offset(i32 year, ui32 month, ui32 day, i32& value) const {
+        if (Y_UNLIKELY(year < NUdf::MIN_YEAR32 - 1 || year > NUdf::MAX_YEAR32
+            || (year == NUdf::MAX_YEAR32 && (day > 1U || month > 1U))
+            || (year == NUdf::MIN_YEAR32 - 1 && (day < 31U || month < 12U))
+            || year == 0))
+        {
             return false;
         }
         auto isLeap = IsLeapYear(year);
@@ -1015,6 +1018,16 @@ public:
         return true;
     }
 
+    bool MakeDate32(i32 year, ui32 month, ui32 day, i32& value) const {
+        if (Y_UNLIKELY(year == 0 || year < NUdf::MIN_YEAR32 || year >= NUdf::MAX_YEAR32)) {
+            return false;
+        }
+        if (Y_UNLIKELY(!GetDate32Offset(year, month, day, value))) {
+            return false;
+        }
+        return true;
+    }
+
     bool MakeTzDate32(i32 year, ui32 month, ui32 day, i32& value, ui16 tzId) const {
         if (tzId == 0) {
             return MakeDate32(year, month, day, value);
@@ -1766,7 +1779,7 @@ NUdf::TUnboxedValuePod ParseDatetime(NUdf::TStringRef buf) {
     }
 
     bool waiting_for_z = true;
-    
+
     ui32 offset_hours = 0;
     ui32 offset_minutes = 0;
     bool is_offset_negative = false;
@@ -1776,12 +1789,12 @@ NUdf::TUnboxedValuePod ParseDatetime(NUdf::TStringRef buf) {
         // Skip sign
         ++pos;
 
-        if (!ParseNumber(pos, buf, offset_hours, 2) || 
+        if (!ParseNumber(pos, buf, offset_hours, 2) ||
             pos == buf.Size() || buf.Data()[pos] != ':')
         {
             return NUdf::TUnboxedValuePod();
         }
- 
+
         // Skip ':'
         ++pos;
 
@@ -2049,12 +2062,12 @@ NUdf::TUnboxedValuePod ParseTimestamp(NUdf::TStringRef buf) {
         // Skip sign
         ++pos;
 
-        if (!ParseNumber(pos, buf, offset_hours, 2) || 
+        if (!ParseNumber(pos, buf, offset_hours, 2) ||
             pos == buf.Size() || buf.Data()[pos] != ':')
         {
             return NUdf::TUnboxedValuePod();
         }
- 
+
         // Skip ':'
         ++pos;
 
@@ -2085,7 +2098,7 @@ NUdf::TUnboxedValuePod ParseTimestamp(NUdf::TStringRef buf) {
     }
 
     ui64 value = dateValue * 86400000000ull + timeValue * 1000000ull + microseconds;
-    
+
     if (is_offset_negative) {
         if (UINT64_MAX - value < offset_value) {
             return NUdf::TUnboxedValuePod();

+ 101 - 84
yql/essentials/minikql/mkql_type_ops_ut.cpp

@@ -1,4 +1,5 @@
 #include <yql/essentials/parser/pg_wrapper/pg_compat.h>
+#include <yql/essentials/public/udf/tz/udf_tz.h>
 
 #include "mkql_type_ops.h"
 #include "mkql_alloc.h"
@@ -68,88 +69,104 @@ Y_UNIT_TEST_SUITE(TMiniKQLTypeOps) {
         }
     }
 
-    void TestSplitMakeTzDate16vs32(ui16 tzId) {
-        ui32 year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek;
-        i32 y;
-        ui32 m, d, doy, woy, woyIso, dow;
-
-        for (ui16 value = 0; value < NUdf::MAX_DATE; ++value) {
-            UNIT_ASSERT(SplitTzDate(value, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek, tzId));
-            ui16 date;
-            UNIT_ASSERT(MakeTzDate(year, month, day, date, tzId));
-            UNIT_ASSERT_VALUES_EQUAL_C(value, date, value);
-            
-            SplitTzDate32(value, y, m, d, doy, woy, woyIso, dow, tzId);
-            UNIT_ASSERT_VALUES_EQUAL(year, y);
-            UNIT_ASSERT_VALUES_EQUAL(month, m);
-            UNIT_ASSERT_VALUES_EQUAL(day, d);
-            UNIT_ASSERT_VALUES_EQUAL(dayOfYear, doy);
-            UNIT_ASSERT_VALUES_EQUAL(dayOfWeek, dow);
-            UNIT_ASSERT_VALUES_EQUAL(weekOfYear, woy);
-            UNIT_ASSERT_VALUES_EQUAL(weekOfYearIso8601, woyIso);
+    using TestFunction = void(*)(ui16 tzId, ui32 beginDate, size_t step);
+    void RunTestForAllTimezones(TestFunction test, size_t step) {
+        std::uniform_int_distribution<ui64> urdist;
+        std::default_random_engine rand;
+        rand.seed(std::time(nullptr));
 
-            i32 date32;
-            UNIT_ASSERT(MakeTzDate32(year, month, day, date32, tzId));
-            UNIT_ASSERT_VALUES_EQUAL(value, date32);
-        }
-    }
+        const ui32 beginDate = urdist(rand) % step;
 
-    Y_UNIT_TEST(SplitMakeTzDate16vs32) {
-        TestSplitMakeTzDate16vs32(0);
-        TestSplitMakeTzDate16vs32(1);
-        // TODO add more timezones
+        const auto timezones = NUdf::GetTimezones();
+        for (size_t tzId = 0; tzId < timezones.size(); tzId++) {
+            // XXX: Several timezones are missing, so skip them.
+            if (timezones[tzId].empty()) {
+                continue;
+            }
+            test(tzId, beginDate, step);
+        }
     }
 
-    void TestSplitMakeTzDatetime32vs64(ui16 tzId, ui32 beginDatetime) {
-        ui32 year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek, hour, min, sec;
-        i32 y;
-        ui32 mon, d, doy, woy, woyIso, dow, h, m, s;
-
-        for (ui32 value = beginDatetime; value < NUdf::MAX_DATETIME; value += 86400u) {
-            UNIT_ASSERT(SplitTzDatetime(value, year, month, day, hour, min, sec, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek, tzId));
-            ui32 dt;
-            UNIT_ASSERT(MakeTzDatetime(year, month, day, hour, min, sec, dt, tzId));
-            UNIT_ASSERT_VALUES_EQUAL(value, dt);
-
-            SplitTzDatetime64(value, y, mon, d, h, m, s, doy, woy, woyIso, dow, tzId);
-            UNIT_ASSERT_VALUES_EQUAL(year, y);
-            UNIT_ASSERT_VALUES_EQUAL(month, mon);
-            UNIT_ASSERT_VALUES_EQUAL(day, d);
-            UNIT_ASSERT_VALUES_EQUAL_C(dayOfYear, doy, value);
-            UNIT_ASSERT_VALUES_EQUAL(dayOfWeek, dow);
-            UNIT_ASSERT_VALUES_EQUAL(weekOfYear, woy);
-            UNIT_ASSERT_VALUES_EQUAL(weekOfYearIso8601, woyIso);
-            UNIT_ASSERT_VALUES_EQUAL(hour, h);
-            UNIT_ASSERT_VALUES_EQUAL(min, m);
-            UNIT_ASSERT_VALUES_EQUAL(sec, s);
-
-            i64 dt64;
-            UNIT_ASSERT(MakeTzDatetime64(year, month, day, hour, min, sec, dt64, tzId));
-            UNIT_ASSERT_VALUES_EQUAL(value, dt64);
+    void TestSplitMakeTzDate16vs32(ui16 tzId, ui32 beginDate, size_t step) {
+        // Narrow date components.
+        ui16 date_n;
+        ui32 year_n;
+        ui32 month_n, day_n, dayOfYear_n, weekOfYear_n, weekOfYearIso8601_n, dayOfWeek_n;
+        // Wide date components.
+        i32 date_w;
+        i32 year_w;
+        ui32 month_w, day_w, dayOfYear_w, weekOfYear_w, weekOfYearIso8601_w, dayOfWeek_w;
+
+        for (ui16 date = beginDate; date < NUdf::MAX_DATE; date += step) {
+            UNIT_ASSERT(SplitTzDate(date, year_n, month_n, day_n, dayOfYear_n,
+                                    weekOfYear_n, weekOfYearIso8601_n,
+                                    dayOfWeek_n, tzId));
+            UNIT_ASSERT(SplitTzDate32(date, year_w, month_w, day_w, dayOfYear_w,
+                                      weekOfYear_w, weekOfYearIso8601_w,
+                                      dayOfWeek_w, tzId));
+
+            UNIT_ASSERT_VALUES_EQUAL(year_n, year_w);
+            UNIT_ASSERT_VALUES_EQUAL(month_n, month_w);
+            UNIT_ASSERT_VALUES_EQUAL(day_n, day_w);
+            UNIT_ASSERT_VALUES_EQUAL(dayOfYear_n, dayOfYear_w);
+            UNIT_ASSERT_VALUES_EQUAL(dayOfWeek_n, dayOfWeek_w);
+            UNIT_ASSERT_VALUES_EQUAL(weekOfYear_n, weekOfYear_w);
+            UNIT_ASSERT_VALUES_EQUAL(weekOfYearIso8601_n, weekOfYearIso8601_w);
+
+            UNIT_ASSERT(MakeTzDate(year_n, month_n, day_n, date_n, tzId));
+            UNIT_ASSERT(MakeTzDate32(year_w, month_w, day_w, date_w, tzId));
+            UNIT_ASSERT_VALUES_EQUAL_C(date_w, date_n, date);
         }
     }
 
-    Y_UNIT_TEST(SplitMakeTzDatetime32vs64) {
-        TestSplitMakeTzDatetime32vs64(0, 0);
-        // TODO add more timezones
+    Y_UNIT_TEST(SplitMakeTzDate16vs32) {
+        constexpr size_t dateStep = 100;
+        RunTestForAllTimezones(TestSplitMakeTzDate16vs32, dateStep);
     }
 
-    void TestSplitMakeTzDate32(ui16 tzId) {
-        i32 year;
-        ui32 month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek;
-
-        for (i32 value = -719528; value < 0; ++value) {
-            SplitTzDate32(value, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek, tzId);
-            i32 date32;
-            UNIT_ASSERT(MakeTzDate32(year, month, day, date32, tzId));
-            UNIT_ASSERT_VALUES_EQUAL(value, date32);
+    void TestSplitMakeTzDatetime32vs64(ui16 tzId, ui32 beginDatetime, size_t step) {
+        // Narrow datetime components.
+        ui32 datetime_n;
+        ui32 year_n;
+        ui32 month_n, day_n, hour_n, minute_n, second_n;
+        ui32 dayOfYear_n, weekOfYear_n, weekOfYearIso8601_n, dayOfWeek_n;
+        // Wide datetime components.
+        i64 datetime_w;
+        i32 year_w;
+        ui32 month_w, day_w, hour_w, minute_w, second_w;
+        ui32 dayOfYear_w, weekOfYear_w, weekOfYearIso8601_w, dayOfWeek_w;
+
+        for (ui32 datetime = beginDatetime; datetime < NUdf::MAX_DATETIME; datetime += step) {
+            UNIT_ASSERT(SplitTzDatetime(datetime, year_n, month_n, day_n, hour_n,
+                                        minute_n, second_n, dayOfYear_n,
+                                        weekOfYear_n, weekOfYearIso8601_n,
+                                        dayOfWeek_n, tzId));
+            UNIT_ASSERT(SplitTzDatetime64(datetime, year_w, month_w, day_w, hour_w,
+                                          minute_w, second_w, dayOfYear_w,
+                                          weekOfYear_w, weekOfYearIso8601_w,
+                                          dayOfWeek_w, tzId));
+            UNIT_ASSERT_VALUES_EQUAL(year_n, year_w);
+            UNIT_ASSERT_VALUES_EQUAL(month_n, month_w);
+            UNIT_ASSERT_VALUES_EQUAL(day_n, day_w);
+            UNIT_ASSERT_VALUES_EQUAL(dayOfYear_n, dayOfYear_w);
+            UNIT_ASSERT_VALUES_EQUAL(dayOfWeek_n, dayOfWeek_w);
+            UNIT_ASSERT_VALUES_EQUAL(weekOfYear_n, weekOfYear_w);
+            UNIT_ASSERT_VALUES_EQUAL(weekOfYearIso8601_n, weekOfYearIso8601_w);
+            UNIT_ASSERT_VALUES_EQUAL(hour_n, hour_w);
+            UNIT_ASSERT_VALUES_EQUAL(minute_n, minute_w);
+            UNIT_ASSERT_VALUES_EQUAL(second_n, second_w);
+
+            UNIT_ASSERT(MakeTzDatetime(year_n, month_n, day_n, hour_n, minute_n,
+                                       second_n, datetime_n, tzId));
+            UNIT_ASSERT(MakeTzDatetime64(year_w, month_w, day_w, hour_w,
+                                         minute_w, second_w, datetime_w, tzId));
+            UNIT_ASSERT_VALUES_EQUAL_C(datetime_w, datetime_n, datetime);
         }
     }
 
-    Y_UNIT_TEST(SplitMakeTzDate32) {
-        TestSplitMakeTzDate32(1);
-        TestSplitMakeTzDate32(451);
-        // TODO add more timezones
+    Y_UNIT_TEST(SplitMakeTzDatetime32vs64) {
+        constexpr size_t datetimeStep = 100 * 86400;
+        RunTestForAllTimezones(TestSplitMakeTzDatetime32vs64, datetimeStep);
     }
 
     Y_UNIT_TEST(SplitMakeTzDateSingle) {
@@ -171,12 +188,12 @@ Y_UNIT_TEST_SUITE(TMiniKQLTypeOps) {
         i32 y;
         ui32 month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek;
         ui16 tzId = 1;
-        i32 value = 1;
+        i32 value = 0;
 
-        SplitTzDate32(value, y, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek, tzId);
+        UNIT_ASSERT(SplitTzDate32(value, y, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek, tzId));
         UNIT_ASSERT_VALUES_EQUAL(y, 1970);
         UNIT_ASSERT_VALUES_EQUAL(month, 1);
-        UNIT_ASSERT_VALUES_EQUAL(day, 3);
+        UNIT_ASSERT_VALUES_EQUAL(day, 2);
 
         i32 d32;
         UNIT_ASSERT(MakeTzDate32(y, month, day, d32, tzId));
@@ -187,7 +204,7 @@ Y_UNIT_TEST_SUITE(TMiniKQLTypeOps) {
         i32 year;
         ui32 month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek;
 
-        SplitDate32(NYql::NUdf::MIN_DATE32, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek);
+        UNIT_ASSERT(SplitDate32(NYql::NUdf::MIN_DATE32, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek));
         UNIT_ASSERT_VALUES_EQUAL(NYql::NUdf::MIN_YEAR32, year);
         UNIT_ASSERT_VALUES_EQUAL(1, month);
         UNIT_ASSERT_VALUES_EQUAL(1, day);
@@ -196,7 +213,7 @@ Y_UNIT_TEST_SUITE(TMiniKQLTypeOps) {
         UNIT_ASSERT_VALUES_EQUAL(1, weekOfYear);
         UNIT_ASSERT_VALUES_EQUAL(52, weekOfYearIso8601);
 
-        SplitDate32(NYql::NUdf::MAX_DATE32, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek);
+        UNIT_ASSERT(SplitDate32(NYql::NUdf::MAX_DATE32, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek));
         UNIT_ASSERT_VALUES_EQUAL(NYql::NUdf::MAX_YEAR32 - 1, year);
         UNIT_ASSERT_VALUES_EQUAL(12, month);
         UNIT_ASSERT_VALUES_EQUAL(31, day);
@@ -206,7 +223,7 @@ Y_UNIT_TEST_SUITE(TMiniKQLTypeOps) {
         UNIT_ASSERT_VALUES_EQUAL(52, weekOfYearIso8601);
 
         // -4713-11-24
-        SplitDate32(DATETIME_MIN_JULIAN - UNIX_EPOCH_JDATE, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek);
+        UNIT_ASSERT(SplitDate32(DATETIME_MIN_JULIAN - UNIX_EPOCH_JDATE, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek));
         UNIT_ASSERT_VALUES_EQUAL(JULIAN_MINYEAR - 1, year);
         UNIT_ASSERT_VALUES_EQUAL(JULIAN_MINMONTH, month);
         UNIT_ASSERT_VALUES_EQUAL(JULIAN_MINDAY, day);
@@ -216,7 +233,7 @@ Y_UNIT_TEST_SUITE(TMiniKQLTypeOps) {
         UNIT_ASSERT_VALUES_EQUAL(48, weekOfYearIso8601);
 
         // 0001-01-01
-        SplitDate32(-719162, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek);
+        UNIT_ASSERT(SplitDate32(-719162, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek));
         UNIT_ASSERT_VALUES_EQUAL(1, year);
         UNIT_ASSERT_VALUES_EQUAL(1, month);
         UNIT_ASSERT_VALUES_EQUAL(1, day);
@@ -225,7 +242,7 @@ Y_UNIT_TEST_SUITE(TMiniKQLTypeOps) {
         UNIT_ASSERT_VALUES_EQUAL(1, weekOfYear);
         UNIT_ASSERT_VALUES_EQUAL(1, weekOfYearIso8601);
 
-        SplitDate32(0, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek);
+        UNIT_ASSERT(SplitDate32(0, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek));
         UNIT_ASSERT_VALUES_EQUAL(1970, year);
         UNIT_ASSERT_VALUES_EQUAL(1, month);
         UNIT_ASSERT_VALUES_EQUAL(1, day);
@@ -234,7 +251,7 @@ Y_UNIT_TEST_SUITE(TMiniKQLTypeOps) {
         UNIT_ASSERT_VALUES_EQUAL(1, weekOfYear);
         UNIT_ASSERT_VALUES_EQUAL(1, weekOfYearIso8601);
 
-        SplitDate32(-1, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek);
+        UNIT_ASSERT(SplitDate32(-1, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek));
         UNIT_ASSERT_VALUES_EQUAL(1969, year);
         UNIT_ASSERT_VALUES_EQUAL(12, month);
         UNIT_ASSERT_VALUES_EQUAL(31, day);
@@ -268,7 +285,7 @@ Y_UNIT_TEST_SUITE(TMiniKQLTypeOps) {
             }
             UNIT_ASSERT(MakeDate32(year, static_cast<ui32>(month), static_cast<ui32>(day), date32));
             UNIT_ASSERT_VALUES_EQUAL(date32, value - UNIX_EPOCH_JDATE);
-            
+
             ui32 dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek;
             i32 y;
             ui32 m, d;
@@ -426,10 +443,10 @@ Y_UNIT_TEST_SUITE(TMiniKQLTypeOps) {
         UNIT_ASSERT(!ParseTimestamp("2020-07-28T21:46:05."));
         UNIT_ASSERT(!ParseTimestamp("2020-07-28T21:46:05.Z"));
         UNIT_ASSERT(!ParseTimestamp("2020-071-28T21:46:05.1Z"));
-        
+
         UNIT_ASSERT(!!ParseTimestamp("2020-07-28T21:46:05.1Z"));
         UNIT_ASSERT(!!ParseTimestamp("2020-07-28T21:46:05.1+01:00"));
-        
+
         UNIT_ASSERT(!ParseTimestamp("4294969318-09-4294967318T14:28:17Z"));
         const auto& val1 = ParseTimestamp("2022-09-15T16:42:01.123456Z");
         const auto& val2 = ParseTimestamp("2022-09-15T16:42:01.123456131231223Z");
@@ -456,10 +473,10 @@ Y_UNIT_TEST_SUITE(TMiniKQLTypeOps) {
         UNIT_ASSERT(!ParseDatetime("2020-07-28T21:46:05"));
         UNIT_ASSERT(!ParseDatetime("2020-07-28T21:46:05."));
         UNIT_ASSERT(!ParseDatetime("2020-071-28T21:46:05Z"));
-        
+
         UNIT_ASSERT(!!ParseDatetime("2020-07-28T21:46:05Z"));
         UNIT_ASSERT(!!ParseDatetime("2020-07-28T21:46:05+01:00"));
-        
+
         UNIT_ASSERT(!ParseDatetime("4294969318-09-4294967318T14:28:17Z"));
 
         const auto& val1 = ParseDatetime("2022-09-15T04:08:01Z");

+ 7 - 1
yql/essentials/providers/common/codec/yql_json_codec.cpp

@@ -215,6 +215,9 @@ void WriteValueToJson(TJsonWriter& writer, const NKikimr::NUdf::TUnboxedValuePod
             case NUdf::TDataType<NUdf::TDatetime64>::Id:
             case NUdf::TDataType<NUdf::TTimestamp64>::Id:
             case NUdf::TDataType<NUdf::TInterval64>::Id:
+            case NUdf::TDataType<NUdf::TTzDate32>::Id:
+            case NUdf::TDataType<NUdf::TTzDatetime64>::Id:
+            case NUdf::TDataType<NUdf::TTzTimestamp64>::Id:
             case NUdf::TDataType<NUdf::TJsonDocument>::Id: {
                 const NUdf::TUnboxedValue out(ValueToString(*dataType->GetDataSlot(), value));
                 writer.Write(out.AsStringRef());
@@ -522,7 +525,10 @@ NKikimr::NUdf::TUnboxedValue ReadJsonValue(TJsonValue& json, NKikimr::NMiniKQL::
             case NUdf::TDataType<NUdf::TDate32>::Id:
             case NUdf::TDataType<NUdf::TDatetime64>::Id:
             case NUdf::TDataType<NUdf::TTimestamp64>::Id:
-            case NUdf::TDataType<NUdf::TInterval64>::Id: {
+            case NUdf::TDataType<NUdf::TInterval64>::Id:
+            case NUdf::TDataType<NUdf::TTzDate32>::Id:
+            case NUdf::TDataType<NUdf::TTzDatetime64>::Id:
+            case NUdf::TDataType<NUdf::TTzTimestamp64>::Id: {
                 YQL_ENSURE(json.IsString(), "Unexpected json type (expected string, but got " << jsonType << ")");
                 YQL_ENSURE(IsValidStringValue(*dataType->GetDataSlot(), json.GetString()), "Invalid date format (expected ISO-8601)");
                 return ValueFromString(*dataType->GetDataSlot(), json.GetString());

+ 14 - 0
yql/essentials/tests/sql/minirun/part0/canondata/result.json

@@ -195,6 +195,20 @@
             "uri": "https://{canondata_backend}/1775319/5ca29359a027472a1be524a83343d503bb8612ac/resource.tar.gz#test.test_aggr_factory-multi_list_nulls-default.txt-Results_/results.txt"
         }
     ],
+    "test.test[bigdate-date_tz_bounds_scale-default.txt-Debug]": [
+        {
+            "checksum": "7c3321778e9b3d987012a3db4b5c543f",
+            "size": 2195,
+            "uri": "https://{canondata_backend}/995452/d75b3fef2c2936a3787295c659edce4b671679fc/resource.tar.gz#test.test_bigdate-date_tz_bounds_scale-default.txt-Debug_/opt.yql"
+        }
+    ],
+    "test.test[bigdate-date_tz_bounds_scale-default.txt-Results]": [
+        {
+            "checksum": "27d2bfc3ef714803f4cfcf0febebb488",
+            "size": 8420,
+            "uri": "https://{canondata_backend}/995452/d75b3fef2c2936a3787295c659edce4b671679fc/resource.tar.gz#test.test_bigdate-date_tz_bounds_scale-default.txt-Results_/results.txt"
+        }
+    ],
     "test.test[bigdate-input_date32-default.txt-Debug]": [
         {
             "checksum": "3697f94ae078bc6ebce40104eaef5799",

+ 14 - 0
yql/essentials/tests/sql/minirun/part5/canondata/result.json

@@ -265,6 +265,20 @@
             "uri": "https://{canondata_backend}/1881367/57bfc4a1435f10934d7710509072254b7f260723/resource.tar.gz#test.test_bigdate-compare_big_small-default.txt-Results_/results.txt"
         }
     ],
+    "test.test[bigdate-date_tz_bounds-default.txt-Debug]": [
+        {
+            "checksum": "dec2c4d54fb7c1a53a110ff49dbec892",
+            "size": 1087,
+            "uri": "https://{canondata_backend}/1689644/3a1411ab3bd6130e98b94fea4f31201df5666c4f/resource.tar.gz#test.test_bigdate-date_tz_bounds-default.txt-Debug_/opt.yql"
+        }
+    ],
+    "test.test[bigdate-date_tz_bounds-default.txt-Results]": [
+        {
+            "checksum": "2c42b564a2df7662b5094053d9a5f291",
+            "size": 4420,
+            "uri": "https://{canondata_backend}/1689644/3a1411ab3bd6130e98b94fea4f31201df5666c4f/resource.tar.gz#test.test_bigdate-date_tz_bounds-default.txt-Results_/results.txt"
+        }
+    ],
     "test.test[bigdate-int_cast-default.txt-Debug]": [
         {
             "checksum": "fc1d1363c15fa7cd4db864e30c2039cf",

+ 36 - 0
yql/essentials/tests/sql/sql2yql/canondata/result.json

@@ -1091,6 +1091,27 @@
             "uri": "https://{canondata_backend}/1942173/99e88108149e222741552e7e6cddef041d6a2846/resource.tar.gz#test_sql2yql.test_bigdate-const_timestamp64_/sql.yql"
         }
     ],
+    "test_sql2yql.test[bigdate-date_tz_bounds]": [
+        {
+            "checksum": "7e6319138c451a9af0fab81161b22c28",
+            "size": 3131,
+            "uri": "https://{canondata_backend}/1880306/7ab74c806ebfa825c90d696b230a4fba9939dddd/resource.tar.gz#test_sql2yql.test_bigdate-date_tz_bounds_/sql.yql"
+        }
+    ],
+    "test_sql2yql.test[bigdate-date_tz_bounds_scale]": [
+        {
+            "checksum": "21dcb7017ac0fa052b508230f773ecad",
+            "size": 6261,
+            "uri": "https://{canondata_backend}/1880306/7ab74c806ebfa825c90d696b230a4fba9939dddd/resource.tar.gz#test_sql2yql.test_bigdate-date_tz_bounds_scale_/sql.yql"
+        }
+    ],
+    "test_sql2yql.test[bigdate-date_tz_impossible_cast]": [
+        {
+            "checksum": "96261bbea3e8e2d39aa2f6a88862e07a",
+            "size": 1128,
+            "uri": "https://{canondata_backend}/1900335/95072b0ab538df1cd8fe21db18063639e62a6b12/resource.tar.gz#test_sql2yql.test_bigdate-date_tz_impossible_cast_/sql.yql"
+        }
+    ],
     "test_sql2yql.test[bigdate-explicit_cast]": [
         {
             "checksum": "cdd5d03853871d3eb099ce8f7bf3c490",
@@ -8052,6 +8073,21 @@
             "uri": "file://test_sql_format.test_bigdate-const_timestamp64_/formatted.sql"
         }
     ],
+    "test_sql_format.test[bigdate-date_tz_bounds]": [
+        {
+            "uri": "file://test_sql_format.test_bigdate-date_tz_bounds_/formatted.sql"
+        }
+    ],
+    "test_sql_format.test[bigdate-date_tz_bounds_scale]": [
+        {
+            "uri": "file://test_sql_format.test_bigdate-date_tz_bounds_scale_/formatted.sql"
+        }
+    ],
+    "test_sql_format.test[bigdate-date_tz_impossible_cast]": [
+        {
+            "uri": "file://test_sql_format.test_bigdate-date_tz_impossible_cast_/formatted.sql"
+        }
+    ],
     "test_sql_format.test[bigdate-explicit_cast]": [
         {
             "uri": "file://test_sql_format.test_bigdate-explicit_cast_/formatted.sql"

Some files were not shown because too many files changed in this diff