@@ -1395,6 +1395,17 @@ TValue DoAddYears(const TValue& date, i64 years, const NUdf::IDateBuilder& build
13951395 }
13961396 };
13971397
1398+ template <auto Core>
1399+ TUnboxedValue SimpleDatetimeToDatetimeUdf (const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) {
1400+ auto result = args[0 ];
1401+ auto & storage = Reference (result);
1402+ if (auto res = Core (storage, *valueBuilder)) {
1403+ storage = res.GetRef ();
1404+ return result;
1405+ }
1406+ return TUnboxedValuePod{};
1407+ }
1408+
13981409 TMaybe<TTMStorage> StartOfYear (TTMStorage storage, const IValueBuilder& valueBuilder) {
13991410 storage.Month = 1 ;
14001411 storage.Day = 1 ;
@@ -1408,16 +1419,31 @@ TValue DoAddYears(const TValue& date, i64 years, const NUdf::IDateBuilder& build
14081419 return storage;
14091420 }
14101421 BEGIN_SIMPLE_STRICT_ARROW_UDF (TStartOfYear, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>)) {
1411- auto result = args[0 ];
1412- auto & storage = Reference (result);
1413- if (auto res = StartOfYear (storage, *valueBuilder)) {
1414- storage = res.GetRef ();
1415- return result;
1416- }
1417- return TUnboxedValuePod{};
1422+ return SimpleDatetimeToDatetimeUdf<StartOfYear>(valueBuilder, args);
14181423 }
14191424 END_SIMPLE_ARROW_UDF (TStartOfYear, TStartOfKernelExec<StartOfYear>::Do);
14201425
1426+ void SetEndOfDay (TTMStorage& storage) {
1427+ storage.Hour = 23 ;
1428+ storage.Minute = 59 ;
1429+ storage.Second = 59 ;
1430+ storage.Microsecond = 999999 ;
1431+ }
1432+
1433+ TMaybe<TTMStorage> EndOfYear (TTMStorage storage, const IValueBuilder& valueBuilder) {
1434+ storage.Month = 12 ;
1435+ storage.Day = 31 ;
1436+ SetEndOfDay (storage);
1437+ if (!storage.Validate (valueBuilder.GetDateBuilder ())) {
1438+ return {};
1439+ }
1440+ return storage;
1441+ }
1442+ BEGIN_SIMPLE_STRICT_ARROW_UDF (TEndOfYear, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>)) {
1443+ return SimpleDatetimeToDatetimeUdf<EndOfYear>(valueBuilder, args);
1444+ }
1445+ END_SIMPLE_ARROW_UDF (TEndOfYear, TStartOfKernelExec<EndOfYear>::Do);
1446+
14211447 TMaybe<TTMStorage> StartOfQuarter (TTMStorage storage, const IValueBuilder& valueBuilder) {
14221448 storage.Month = (storage.Month - 1 ) / 3 * 3 + 1 ;
14231449 storage.Day = 1 ;
@@ -1431,16 +1457,24 @@ TValue DoAddYears(const TValue& date, i64 years, const NUdf::IDateBuilder& build
14311457 return storage;
14321458 }
14331459 BEGIN_SIMPLE_STRICT_ARROW_UDF (TStartOfQuarter, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>)) {
1434- auto result = args[0 ];
1435- auto & storage = Reference (result);
1436- if (auto res = StartOfQuarter (storage, *valueBuilder)) {
1437- storage = res.GetRef ();
1438- return result;
1439- }
1440- return TUnboxedValuePod{};
1460+ return SimpleDatetimeToDatetimeUdf<StartOfQuarter>(valueBuilder, args);
14411461 }
14421462 END_SIMPLE_ARROW_UDF (TStartOfQuarter, TStartOfKernelExec<StartOfQuarter>::Do);
14431463
1464+ TMaybe<TTMStorage> EndOfQuarter (TTMStorage storage, const IValueBuilder& valueBuilder) {
1465+ storage.Month = ((storage.Month - 1 ) / 3 + 1 ) * 3 ;
1466+ storage.Day = NMiniKQL::GetMonthLength (storage.Month , NMiniKQL::IsLeapYear (storage.Year ));
1467+ SetEndOfDay (storage);
1468+ if (!storage.Validate (valueBuilder.GetDateBuilder ())) {
1469+ return {};
1470+ }
1471+ return storage;
1472+ }
1473+ BEGIN_SIMPLE_STRICT_ARROW_UDF (TEndOfQuarter, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>)) {
1474+ return SimpleDatetimeToDatetimeUdf<EndOfQuarter>(valueBuilder, args);
1475+ }
1476+ END_SIMPLE_ARROW_UDF (TEndOfQuarter, TStartOfKernelExec<EndOfQuarter>::Do);
1477+
14441478 TMaybe<TTMStorage> StartOfMonth (TTMStorage storage, const IValueBuilder& valueBuilder) {
14451479 storage.Day = 1 ;
14461480 storage.Hour = 0 ;
@@ -1453,37 +1487,21 @@ TValue DoAddYears(const TValue& date, i64 years, const NUdf::IDateBuilder& build
14531487 return storage;
14541488 }
14551489 BEGIN_SIMPLE_STRICT_ARROW_UDF (TStartOfMonth, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>)) {
1456- auto result = args[0 ];
1457- auto & storage = Reference (result);
1458- if (auto res = StartOfMonth (storage, *valueBuilder)) {
1459- storage = res.GetRef ();
1460- return result;
1461- }
1462- return TUnboxedValuePod{};
1490+ return SimpleDatetimeToDatetimeUdf<StartOfMonth>(valueBuilder, args);
14631491 }
14641492 END_SIMPLE_ARROW_UDF (TStartOfMonth, TStartOfKernelExec<StartOfMonth>::Do);
14651493
14661494 TMaybe<TTMStorage> EndOfMonth (TTMStorage storage, const IValueBuilder& valueBuilder) {
14671495 storage.Day = NMiniKQL::GetMonthLength (storage.Month , NMiniKQL::IsLeapYear (storage.Year ));
1468- storage.Hour = 0 ;
1469- storage.Minute = 0 ;
1470- storage.Second = 0 ;
1471- storage.Microsecond = 0 ;
1472-
1496+ SetEndOfDay (storage);
14731497 if (!storage.Validate (valueBuilder.GetDateBuilder ())) {
14741498 return {};
14751499 }
14761500 return storage;
14771501 }
14781502
14791503 BEGIN_SIMPLE_STRICT_ARROW_UDF (TEndOfMonth, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>)) {
1480- auto result = args[0 ];
1481- auto & storage = Reference (result);
1482- if (auto res = EndOfMonth (storage, *valueBuilder)) {
1483- storage = res.GetRef ();
1484- return result;
1485- }
1486- return TUnboxedValuePod{};
1504+ return SimpleDatetimeToDatetimeUdf<EndOfMonth>(valueBuilder, args);
14871505 }
14881506 END_SIMPLE_ARROW_UDF (TEndOfMonth, TStartOfKernelExec<EndOfMonth>::Do);
14891507
@@ -1497,20 +1515,36 @@ TValue DoAddYears(const TValue& date, i64 years, const NUdf::IDateBuilder& build
14971515 storage.Minute = 0 ;
14981516 storage.Second = 0 ;
14991517 storage.Microsecond = 0 ;
1518+ if (!storage.Validate (valueBuilder.GetDateBuilder ())) {
1519+ return {};
1520+ }
15001521 return storage;
15011522 }
15021523
15031524 BEGIN_SIMPLE_STRICT_ARROW_UDF (TStartOfWeek, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>)) {
1504- auto result = args[0 ];
1505- auto & storage = Reference (result);
1506- if (auto res = StartOfWeek (storage, *valueBuilder)) {
1507- storage = res.GetRef ();
1508- return result;
1509- }
1510- return TUnboxedValuePod{};
1525+ return SimpleDatetimeToDatetimeUdf<StartOfWeek>(valueBuilder, args);
15111526 }
15121527 END_SIMPLE_ARROW_UDF (TStartOfWeek, TStartOfKernelExec<StartOfWeek>::Do);
15131528
1529+ TMaybe<TTMStorage> EndOfWeek (TTMStorage storage, const IValueBuilder& valueBuilder) {
1530+ const ui32 shift = 86400u * (7u - storage.DayOfWeek );
1531+ auto dt = storage.ToDatetime (valueBuilder.GetDateBuilder ());
1532+ if (NUdf::MAX_DATETIME - shift <= dt) {
1533+ return {};
1534+ }
1535+ storage.FromDatetime (valueBuilder.GetDateBuilder (), dt + shift, storage.TimezoneId );
1536+ SetEndOfDay (storage);
1537+ if (!storage.Validate (valueBuilder.GetDateBuilder ())) {
1538+ return {};
1539+ }
1540+ return storage;
1541+ }
1542+
1543+ BEGIN_SIMPLE_STRICT_ARROW_UDF (TEndOfWeek, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>)) {
1544+ return SimpleDatetimeToDatetimeUdf<EndOfWeek>(valueBuilder, args);
1545+ }
1546+ END_SIMPLE_ARROW_UDF (TEndOfWeek, TStartOfKernelExec<EndOfWeek>::Do);
1547+
15141548 TMaybe<TTMStorage> StartOfDay (TTMStorage storage, const IValueBuilder& valueBuilder) {
15151549 storage.Hour = 0 ;
15161550 storage.Minute = 0 ;
@@ -1524,16 +1558,24 @@ TValue DoAddYears(const TValue& date, i64 years, const NUdf::IDateBuilder& build
15241558 }
15251559
15261560 BEGIN_SIMPLE_STRICT_ARROW_UDF (TStartOfDay, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>)) {
1527- auto result = args[0 ];
1528- auto & storage = Reference (result);
1529- if (auto res = StartOfDay (storage, *valueBuilder)) {
1530- storage = res.GetRef ();
1531- return result;
1532- }
1533- return TUnboxedValuePod{};
1561+ return SimpleDatetimeToDatetimeUdf<StartOfDay>(valueBuilder, args);
15341562 }
15351563 END_SIMPLE_ARROW_UDF (TStartOfDay, TStartOfKernelExec<StartOfDay>::Do);
15361564
1565+ TMaybe<TTMStorage> EndOfDay (TTMStorage storage, const IValueBuilder& valueBuilder) {
1566+ SetEndOfDay (storage);
1567+ auto & builder = valueBuilder.GetDateBuilder ();
1568+ if (!storage.Validate (builder)) {
1569+ return {};
1570+ }
1571+ return storage;
1572+ }
1573+
1574+ BEGIN_SIMPLE_STRICT_ARROW_UDF (TEndOfDay, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>)) {
1575+ return SimpleDatetimeToDatetimeUdf<EndOfDay>(valueBuilder, args);
1576+ }
1577+ END_SIMPLE_ARROW_UDF (TEndOfDay, TStartOfKernelExec<EndOfDay>::Do);
1578+
15371579 TMaybe<TTMStorage> StartOf (TTMStorage storage, ui64 interval, const IValueBuilder& valueBuilder) {
15381580 if (interval >= 86400000000ull ) {
15391581 // treat as StartOfDay
@@ -2375,7 +2417,11 @@ TValue DoAddYears(const TValue& date, i64 years, const NUdf::IDateBuilder& build
23752417 TShiftQuarters,
23762418 TShiftMonths,
23772419
2420+ TEndOfYear,
2421+ TEndOfQuarter,
23782422 TEndOfMonth,
2423+ TEndOfWeek,
2424+ TEndOfDay,
23792425
23802426 TToUnits<ToSecondsName, ui32, 1 >,
23812427 TToUnits<ToMillisecondsName, ui64, 1000 >,
0 commit comments