aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/cron_expression/ut/cron_expression_ut.cpp
diff options
context:
space:
mode:
authorPavel Bashkirov <pavel@nebius.com>2025-06-26 12:44:04 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2025-06-26 12:57:52 +0300
commit0b47b15628153922f04000ad1219c3e0df829385 (patch)
tree1b6dc9a984a2d1cc9dfc2513a7e9c6721a137b38 /library/cpp/cron_expression/ut/cron_expression_ut.cpp
parenteb4cc660850b42db63b573cb25a6fdd36d4d508d (diff)
downloadydb-0b47b15628153922f04000ad1219c3e0df829385.tar.gz
Use CRON to set the schedule of queues export
# Description Currently the interval of queues export can only be set as "Every N units". This sometimes does not work well as it always starts the count from the time `0` (January 1st, 1970). It means that, for instance, if the customer wants to set an export to "Every week", it will happen every Thursday. This PR fixes the problem by providing a CRON way to set the schedule which is proven to be very flexible and meeting (almost) any requirement the user may have. * Changelog entry Type: feature Component: queue-agent Support CRON schedules for queue exports. --- Pull Request resolved: https://github.com/ytsaurus/ytsaurus/pull/1239 Co-authored-by: apachee <apachee@yandex-team.com> Co-authored-by: apachee <apachee@yandex-team.com> Co-authored-by: apachee <apachee@yandex-team.com> Co-authored-by: apachee <apachee@yandex-team.com> Co-authored-by: apachee <apachee@yandex-team.com> commit_hash:6a536f5edc17b3ad8d2243d55d876994141d38b0
Diffstat (limited to 'library/cpp/cron_expression/ut/cron_expression_ut.cpp')
-rw-r--r--library/cpp/cron_expression/ut/cron_expression_ut.cpp775
1 files changed, 775 insertions, 0 deletions
diff --git a/library/cpp/cron_expression/ut/cron_expression_ut.cpp b/library/cpp/cron_expression/ut/cron_expression_ut.cpp
new file mode 100644
index 00000000000..999f1e00260
--- /dev/null
+++ b/library/cpp/cron_expression/ut/cron_expression_ut.cpp
@@ -0,0 +1,775 @@
+#include <library/cpp/cron_expression/cron_expression.h>
+
+#include <util/datetime/base.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+namespace {
+
+void TestNext(const TStringBuf cron, const TStringBuf date, const TStringBuf ans) {
+ TInstant ansTI = TInstant::ParseIso8601(ans);
+ TInstant dateTI = TInstant::ParseIso8601(date);
+ NDatetime::TCivilSecond ansTZ = NDatetime::Convert(ansTI, "UTC");
+ NDatetime::TCivilSecond dateTZ = NDatetime::Convert(dateTI, "UTC");
+ TCronExpression cronConverter(cron);
+ UNIT_ASSERT_VALUES_EQUAL(cronConverter.CronNext(dateTZ), ansTZ);
+}
+
+void TestPrev(const TStringBuf cron, const TStringBuf date, const TStringBuf ans) {
+ TInstant ansTI = TInstant::ParseIso8601(ans);
+ TInstant dateTI = TInstant::ParseIso8601(date);
+ NDatetime::TCivilSecond ansTZ = NDatetime::Convert(ansTI, "UTC");
+ NDatetime::TCivilSecond dateTZ = NDatetime::Convert(dateTI, "UTC");
+ TCronExpression cronConverter(cron);
+ UNIT_ASSERT_VALUES_EQUAL(cronConverter.CronPrev(dateTZ), ansTZ);
+}
+
+void TestNextCron(TCronExpression* cron, const TStringBuf date, const TStringBuf ans) {
+ TInstant ansTI = TInstant::ParseIso8601(ans);
+ TInstant dateTI = TInstant::ParseIso8601(date);
+ NDatetime::TCivilSecond ansTZ = NDatetime::Convert(ansTI, "UTC");
+ NDatetime::TCivilSecond dateTZ = NDatetime::Convert(dateTI, "UTC");
+ UNIT_ASSERT_VALUES_EQUAL(cron->CronNext(dateTZ), ansTZ);
+}
+
+void TestPrevCron(TCronExpression* cron, const TStringBuf date, const TStringBuf ans) {
+ TInstant ansTI = TInstant::ParseIso8601(ans);
+ TInstant dateTI = TInstant::ParseIso8601(date);
+ NDatetime::TCivilSecond ansTZ = NDatetime::Convert(ansTI, "UTC");
+ NDatetime::TCivilSecond dateTZ = NDatetime::Convert(dateTI, "UTC");
+ UNIT_ASSERT_VALUES_EQUAL(cron->CronPrev(dateTZ), ansTZ);
+}
+
+void TestNextCronBadRequest(TCronExpression* cron, const TStringBuf date) {
+ TInstant dateTI = TInstant::ParseIso8601(date);
+ NDatetime::TCivilSecond dateTZ = NDatetime::Convert(dateTI, "UTC");
+ UNIT_ASSERT_EXCEPTION(cron->CronNext(dateTZ), yexception);
+}
+
+void TestPrevCronBadRequest(TCronExpression* cron, const TStringBuf date) {
+ TInstant dateTI = TInstant::ParseIso8601(date);
+ NDatetime::TCivilSecond dateTZ = NDatetime::Convert(dateTI, "UTC");
+ UNIT_ASSERT_EXCEPTION(cron->CronPrev(dateTZ), yexception);
+}
+
+Y_UNIT_TEST_SUITE(TestNext) {
+ Y_UNIT_TEST(Basic) {
+ TestNext("* * * * * *", "2022-12-29T23:59:59Z", "2022-12-30T00:00:00Z");
+ TestNext("* * * * * *", "2022-12-30T08:10:23Z", "2022-12-30T08:10:24Z");
+ TestNext("* * * * * *", "2100-01-01T15:12:42Z", "2100-01-01T15:12:43Z");
+ TestNext("* * * * * *", "2198-01-01T15:12:42Z", "2198-01-01T15:12:43Z");
+ TestNext("* * * * * *", "2199-01-01T15:12:42Z", "2199-01-01T15:12:43Z");
+ TestNext("* * * 1 * *", "2024-02-03T15:12:42Z", "2024-03-01T00:00:00Z");
+ TestNext("* * * 1 1 * *", "1970-01-01T15:12:42Z", "1970-01-01T15:12:43Z");
+ TestNext("* * * 1 1 * 1970,2100,2193,2199", "1970-01-01T15:12:42Z", "1970-01-01T15:12:43Z");
+ TestNext("* * * 1 1 * 1970,2100,2193,2199", "1971-01-01T15:12:42Z", "2100-01-01T00:00:00Z");
+ TestNext("* * * 1 1 * 1970,2100,2193,2199", "2195-01-01T15:12:42Z", "2199-01-01T00:00:00Z");
+ TestNext("* * * 1 1 * 2020", "2011-02-02T15:12:42Z", "2020-01-01T00:00:00Z");
+ }
+
+ Y_UNIT_TEST(WorkingDays) {
+ TestNext("* * * 1W * *", "2011-01-01T15:12:42Z", "2011-01-03T00:00:00Z");
+ TestNext("* * * 31W * *", "2010-01-01T15:12:42Z", "2010-01-29T00:00:00Z");
+ TestNext("* * * LW * *", "2010-01-01T15:12:42Z", "2010-01-29T00:00:00Z");
+ TestNext("* * * LW * *", "2010-02-03T15:12:42Z", "2010-02-26T00:00:00Z");
+ TestNext("* * * LW * *", "2010-03-06T15:12:42Z", "2010-03-31T00:00:00Z");
+ TestNext("* * * LW * *", "2010-04-09T15:12:42Z", "2010-04-30T00:00:00Z");
+ TestNext("* * * LW * *", "2010-05-12T15:12:42Z", "2010-05-31T00:00:00Z");
+ TestNext("* * * LW * *", "2010-06-15T15:12:42Z", "2010-06-30T00:00:00Z");
+ TestNext("* * * LW * *", "2010-07-18T15:12:42Z", "2010-07-30T00:00:00Z");
+ TestNext("* * * LW * *", "2010-08-21T15:12:42Z", "2010-08-31T00:00:00Z");
+ TestNext("* * * LW * *", "2010-09-24T15:12:42Z", "2010-09-30T00:00:00Z");
+ TestNext("* * * LW * *", "2010-10-27T15:12:42Z", "2010-10-29T00:00:00Z");
+ TestNext("* * * LW * *", "2010-11-30T15:12:42Z", "2010-11-30T15:12:43Z");
+ TestNext("* * * LW * *", "2010-12-31T15:12:42Z", "2010-12-31T15:12:43Z");
+ TestNext("* * * 15W * *", "2010-01-01T15:12:42Z", "2010-01-15T00:00:00Z");
+ TestNext("* * * 15W * *", "2010-02-03T15:12:42Z", "2010-02-15T00:00:00Z");
+ TestNext("* * * 15W * *", "2010-03-06T15:12:42Z", "2010-03-15T00:00:00Z");
+ TestNext("* * * 15W * *", "2010-04-09T15:12:42Z", "2010-04-15T00:00:00Z");
+ TestNext("* * * 15W * *", "2010-05-12T15:12:42Z", "2010-05-14T00:00:00Z");
+ TestNext("* * * 15W * *", "2010-06-15T15:12:42Z", "2010-06-15T15:12:43Z");
+ TestNext("* * * 15W * *", "2010-07-18T15:12:42Z", "2010-08-16T00:00:00Z");
+ TestNext("* * * 15W * *", "2010-08-21T15:12:42Z", "2010-09-15T00:00:00Z");
+ TestNext("* * * 15W * *", "2010-09-24T15:12:42Z", "2010-10-15T00:00:00Z");
+ TestNext("* * * 15W * *", "2010-10-27T15:12:42Z", "2010-11-15T00:00:00Z");
+ TestNext("* * * 15W * *", "2010-11-30T15:12:42Z", "2010-12-15T00:00:00Z");
+ TestNext("* * * 15W * *", "2010-12-31T15:12:42Z", "2011-01-14T00:00:00Z");
+ }
+
+ Y_UNIT_TEST(LastDaysOfMonth) {
+ TestNext("* * * L-3 * *", "2010-01-01T15:12:42Z", "2010-01-28T00:00:00Z");
+ TestNext("* * * L-1 * *", "2010-01-01T15:12:42Z", "2010-01-30T00:00:00Z");
+ TestNext("* * * L-1 * *", "2010-02-03T15:12:42Z", "2010-02-27T00:00:00Z");
+ TestNext("* * * L-1 * *", "2010-03-06T15:12:42Z", "2010-03-30T00:00:00Z");
+ TestNext("* * * L-1 * *", "2010-04-09T15:12:42Z", "2010-04-29T00:00:00Z");
+ TestNext("* * * L-1 * *", "2010-05-12T15:12:42Z", "2010-05-30T00:00:00Z");
+ TestNext("* * * L-1 * *", "2010-06-15T15:12:42Z", "2010-06-29T00:00:00Z");
+ TestNext("* * * L-1 * *", "2010-07-18T15:12:42Z", "2010-07-30T00:00:00Z");
+ TestNext("* * * L-1 * *", "2010-08-21T15:12:42Z", "2010-08-30T00:00:00Z");
+ TestNext("* * * L-1 * *", "2010-09-24T15:12:42Z", "2010-09-29T00:00:00Z");
+ TestNext("* * * L-1 * *", "2010-10-27T15:12:42Z", "2010-10-30T00:00:00Z");
+ TestNext("* * * L-1 * *", "2010-11-30T15:12:42Z", "2010-12-30T00:00:00Z");
+ TestNext("* * * L-1 * *", "2010-12-31T15:12:42Z", "2011-01-30T00:00:00Z");
+ TestNext("* * * L * *", "2010-01-01T15:12:42Z", "2010-01-31T00:00:00Z");
+ TestNext("* * * L * *", "2010-02-03T15:12:42Z", "2010-02-28T00:00:00Z");
+ TestNext("* * * L * *", "2010-03-06T15:12:42Z", "2010-03-31T00:00:00Z");
+ TestNext("* * * L * *", "2010-04-09T15:12:42Z", "2010-04-30T00:00:00Z");
+ TestNext("* * * L * *", "2010-05-12T15:12:42Z", "2010-05-31T00:00:00Z");
+ TestNext("* * * L * *", "2010-06-15T15:12:42Z", "2010-06-30T00:00:00Z");
+ TestNext("* * * L * *", "2010-07-18T15:12:42Z", "2010-07-31T00:00:00Z");
+ TestNext("* * * L * *", "2010-08-21T15:12:42Z", "2010-08-31T00:00:00Z");
+ TestNext("* * * L * *", "2010-09-24T15:12:42Z", "2010-09-30T00:00:00Z");
+ TestNext("* * * L * *", "2010-10-27T15:12:42Z", "2010-10-31T00:00:00Z");
+ TestNext("* * * L * *", "2010-11-30T15:12:42Z", "2010-11-30T15:12:43Z");
+ TestNext("* * * L * *", "2010-12-31T15:12:42Z", "2010-12-31T15:12:43Z");
+ }
+
+ Y_UNIT_TEST(Everys) {
+ TestNext("* * * * * 1#-5", "2010-09-03T15:12:42Z", "2010-11-01T00:00:00Z");
+ TestNext("* * * * * 1#-4", "2010-09-03T15:12:42Z", "2010-09-06T00:00:00Z");
+ TestNext("* * * * * 1#-3", "2010-09-03T15:12:42Z", "2010-09-13T00:00:00Z");
+ TestNext("* * * * * 1#-2", "2010-09-03T15:12:42Z", "2010-09-20T00:00:00Z");
+ TestNext("* * * * * 1#1", "2010-09-03T15:12:42Z", "2010-09-06T00:00:00Z");
+ TestNext("* * * * * 1#2", "2010-09-03T15:12:42Z", "2010-09-13T00:00:00Z");
+ TestNext("* * * * * 1#3", "2010-09-03T15:12:42Z", "2010-09-20T00:00:00Z");
+ TestNext("* * * * * 1#4", "2010-09-03T15:12:42Z", "2010-09-27T00:00:00Z");
+ TestNext("* * * * * 1#5", "2010-09-03T15:12:42Z", "2010-11-29T00:00:00Z");
+
+ TestNext("* * * * * 2#-5", "2010-09-03T15:12:42Z", "2010-11-02T00:00:00Z");
+ TestNext("* * * * * 2#-4", "2010-09-03T15:12:42Z", "2010-09-07T00:00:00Z");
+ TestNext("* * * * * 2#-3", "2010-09-03T15:12:42Z", "2010-09-14T00:00:00Z");
+ TestNext("* * * * * 2#-2", "2010-09-03T15:12:42Z", "2010-09-21T00:00:00Z");
+ TestNext("* * * * * 2#1", "2010-09-03T15:12:42Z", "2010-09-07T00:00:00Z");
+ TestNext("* * * * * 2#2", "2010-09-03T15:12:42Z", "2010-09-14T00:00:00Z");
+ TestNext("* * * * * 2#3", "2010-09-03T15:12:42Z", "2010-09-21T00:00:00Z");
+ TestNext("* * * * * 2#4", "2010-09-03T15:12:42Z", "2010-09-28T00:00:00Z");
+ TestNext("* * * * * 2#5", "2010-09-03T15:12:42Z", "2010-11-30T00:00:00Z");
+
+ TestNext("* * * * * 3#-5", "2010-09-03T15:12:42Z", "2010-12-01T00:00:00Z");
+ TestNext("* * * * * 3#-4", "2010-09-03T15:12:42Z", "2010-09-08T00:00:00Z");
+ TestNext("* * * * * 3#-3", "2010-09-03T15:12:42Z", "2010-09-15T00:00:00Z");
+ TestNext("* * * * * 3#-2", "2010-09-03T15:12:42Z", "2010-09-22T00:00:00Z");
+ TestNext("* * * * * 3#1", "2010-09-03T15:12:42Z", "2010-10-06T00:00:00Z");
+ TestNext("* * * * * 3#2", "2010-09-03T15:12:42Z", "2010-09-08T00:00:00Z");
+ TestNext("* * * * * 3#3", "2010-09-03T15:12:42Z", "2010-09-15T00:00:00Z");
+ TestNext("* * * * * 3#4", "2010-09-03T15:12:42Z", "2010-09-22T00:00:00Z");
+ TestNext("* * * * * 3#5", "2010-09-03T15:12:42Z", "2010-09-29T00:00:00Z");
+
+ TestNext("* * * * * 4#-5", "2010-09-03T15:12:42Z", "2010-12-02T00:00:00Z");
+ TestNext("* * * * * 4#-4", "2010-09-03T15:12:42Z", "2010-09-09T00:00:00Z");
+ TestNext("* * * * * 4#-3", "2010-09-03T15:12:42Z", "2010-09-16T00:00:00Z");
+ TestNext("* * * * * 4#-2", "2010-09-03T15:12:42Z", "2010-09-23T00:00:00Z");
+ TestNext("* * * * * 4#1", "2010-09-03T15:12:42Z", "2010-10-07T00:00:00Z");
+ TestNext("* * * * * 4#2", "2010-09-03T15:12:42Z", "2010-09-09T00:00:00Z");
+ TestNext("* * * * * 4#3", "2010-09-03T15:12:42Z", "2010-09-16T00:00:00Z");
+ TestNext("* * * * * 4#4", "2010-09-03T15:12:42Z", "2010-09-23T00:00:00Z");
+ TestNext("* * * * * 4#5", "2010-09-03T15:12:42Z", "2010-09-30T00:00:00Z");
+
+ TestNext("* * * * * 5#-5", "2010-09-03T15:12:42Z", "2010-10-01T00:00:00Z");
+ TestNext("* * * * * 5#-4", "2010-09-03T15:12:42Z", "2010-09-03T15:12:43Z");
+ TestNext("* * * * * 5#-3", "2010-09-03T15:12:42Z", "2010-09-10T00:00:00Z");
+ TestNext("* * * * * 5#-2", "2010-09-03T15:12:42Z", "2010-09-17T00:00:00Z");
+ TestNext("* * * * * 5#1", "2010-09-03T15:12:42Z", "2010-09-03T15:12:43Z");
+ TestNext("* * * * * 5#2", "2010-09-03T15:12:42Z", "2010-09-10T00:00:00Z");
+ TestNext("* * * * * 5#3", "2010-09-03T15:12:42Z", "2010-09-17T00:00:00Z");
+ TestNext("* * * * * 5#4", "2010-09-03T15:12:42Z", "2010-09-24T00:00:00Z");
+ TestNext("* * * * * 5#5", "2010-09-03T15:12:42Z", "2010-10-29T00:00:00Z");
+
+ TestNext("* * * * * 6#-5", "2010-09-03T15:12:42Z", "2010-10-02T00:00:00Z");
+ TestNext("* * * * * 6#-4", "2010-09-03T15:12:42Z", "2010-09-04T00:00:00Z");
+ TestNext("* * * * * 6#-3", "2010-09-03T15:12:42Z", "2010-09-11T00:00:00Z");
+ TestNext("* * * * * 6#-2", "2010-09-03T15:12:42Z", "2010-09-18T00:00:00Z");
+ TestNext("* * * * * 6#1", "2010-09-03T15:12:42Z", "2010-09-04T00:00:00Z");
+ TestNext("* * * * * 6#2", "2010-09-03T15:12:42Z", "2010-09-11T00:00:00Z");
+ TestNext("* * * * * 6#3", "2010-09-03T15:12:42Z", "2010-09-18T00:00:00Z");
+ TestNext("* * * * * 6#4", "2010-09-03T15:12:42Z", "2010-09-25T00:00:00Z");
+ TestNext("* * * * * 6#5", "2010-09-03T15:12:42Z", "2010-10-30T00:00:00Z");
+
+ TestNext("* * * * * 7#-5", "2010-09-03T15:12:42Z", "2010-10-03T00:00:00Z");
+ TestNext("* * * * * 7#-4", "2010-09-03T15:12:42Z", "2010-09-05T00:00:00Z");
+ TestNext("* * * * * 7#-3", "2010-09-03T15:12:42Z", "2010-09-12T00:00:00Z");
+ TestNext("* * * * * 7#-2", "2010-09-03T15:12:42Z", "2010-09-19T00:00:00Z");
+ TestNext("* * * * * 7#1", "2010-09-03T15:12:42Z", "2010-09-05T00:00:00Z");
+ TestNext("* * * * * 7#2", "2010-09-03T15:12:42Z", "2010-09-12T00:00:00Z");
+ TestNext("* * * * * 7#3", "2010-09-03T15:12:42Z", "2010-09-19T00:00:00Z");
+ TestNext("* * * * * 7#4", "2010-09-03T15:12:42Z", "2010-09-26T00:00:00Z");
+ TestNext("* * * * * 7#5", "2010-09-03T15:12:42Z", "2010-10-31T00:00:00Z");
+ }
+
+ Y_UNIT_TEST(LastWeekdays) {
+ TestNext("* * * * * 1L", "2010-09-30T15:12:42Z", "2010-10-25T00:00:00Z");
+ TestNext("* * * * * 2L", "2010-09-30T15:12:42Z", "2010-10-26T00:00:00Z");
+ TestNext("* * * * * 3L", "2010-09-30T15:12:42Z", "2010-10-27T00:00:00Z");
+ TestNext("* * * * * 4L", "2010-09-30T15:12:42Z", "2010-09-30T15:12:43Z");
+ TestNext("* * * * * 5L", "2010-09-30T15:12:42Z", "2010-10-29T00:00:00Z");
+ TestNext("* * * * * 6L", "2010-09-30T15:12:42Z", "2010-10-30T00:00:00Z");
+ TestNext("* * * * * 7L", "2010-09-30T15:12:42Z", "2010-10-31T00:00:00Z");
+ TestNext("* * * * * 1L", "2010-10-27T15:12:42Z", "2010-11-29T00:00:00Z");
+ TestNext("* * * * * 2L", "2010-10-27T15:12:42Z", "2010-11-30T00:00:00Z");
+ TestNext("* * * * * 3L", "2010-10-27T15:12:42Z", "2010-10-27T15:12:43Z");
+ TestNext("* * * * * 4L", "2010-10-27T15:12:42Z", "2010-10-28T00:00:00Z");
+ TestNext("* * * * * 5L", "2010-10-27T15:12:42Z", "2010-10-29T00:00:00Z");
+ TestNext("* * * * * 6L", "2010-10-27T15:12:42Z", "2010-10-30T00:00:00Z");
+ TestNext("* * * * * 7L", "2010-10-27T15:12:42Z", "2010-10-31T00:00:00Z");
+
+ TestNext("* * * * * 1L", "2010-10-30T15:12:42Z", "2010-11-29T00:00:00Z");
+ TestNext("* * * * * 2L", "2010-10-30T15:12:42Z", "2010-11-30T00:00:00Z");
+ TestNext("* * * * * 3L", "2010-10-30T15:12:42Z", "2010-11-24T00:00:00Z");
+ TestNext("* * * * * 4L", "2010-10-30T15:12:42Z", "2010-11-25T00:00:00Z");
+ TestNext("* * * * * 5L", "2010-10-30T15:12:42Z", "2010-11-26T00:00:00Z");
+ TestNext("* * * * * 6L", "2010-10-30T15:12:42Z", "2010-10-30T15:12:43Z");
+ TestNext("* * * * * 7L", "2010-10-30T15:12:42Z", "2010-10-31T00:00:00Z");
+ TestNext("* * * * * 1L", "2010-11-27T15:12:42Z", "2010-11-29T00:00:00Z");
+ TestNext("* * * * * 2L", "2010-11-27T15:12:42Z", "2010-11-30T00:00:00Z");
+ TestNext("* * * * * 3L", "2010-11-27T15:12:42Z", "2010-12-29T00:00:00Z");
+ TestNext("* * * * * 4L", "2010-11-27T15:12:42Z", "2010-12-30T00:00:00Z");
+ TestNext("* * * * * 5L", "2010-11-27T15:12:42Z", "2010-12-31T00:00:00Z");
+ TestNext("* * * * * 6L", "2010-11-27T15:12:42Z", "2010-11-27T15:12:43Z");
+ TestNext("* * * * * 7L", "2010-11-27T15:12:42Z", "2010-11-28T00:00:00Z");
+ }
+
+ Y_UNIT_TEST(ComplicatedCases) {
+ TestNext("10-45/3 30-50/7 10,12,13,14,22,23 */2 * 1-5", "2024-04-23T09:42:45Z", "2024-04-23T10:30:10Z");
+ TestNext("10-45/3 30-50/7 10,12,13,14,22,23 */2 * 1-5", "2024-04-22T09:42:45Z", "2024-04-23T10:30:10Z");
+ TestNext("10-45/3 30-50/7 10,12,13,14,22,23 */2 * 1-5", "2024-04-20T04:30:13Z", "2024-04-23T10:30:10Z");
+ TestNext("10-45/3 30-50/7 10,12,13,14,22,23 */2 * 1-5", "2024-04-23T11:32:00Z", "2024-04-23T12:30:10Z");
+ TestNext("10-45/3 30-50/7 10,12,13,14,22,23 */2 * 1-5", "2024-04-23T12:32:17Z", "2024-04-23T12:37:10Z");
+ TestNext("10-45/3 30-50/7 10,12,13,14,22,23 30 * 1#5", "2024-04-23T12:32:17Z", "2024-09-30T10:30:10Z");
+ TestNext("10-45/3 30-50/7 10,12,13,14,22,23 L * 1", "2024-04-23T10:31:11Z", "2024-09-30T10:30:10Z");
+ TestNext("* * 10 L * 5", "2024-04-23T10:31:11Z", "2024-05-31T10:00:00Z");
+ TestNext("* * 10 L-1 * 4", "2024-04-23T10:31:11Z", "2024-05-30T10:00:00Z");
+ TestNext("* * 10 L-2 * 3", "2024-04-23T10:31:11Z", "2024-05-29T10:00:00Z");
+ TestNext("* * 10 L-3 * 2", "2024-04-23T10:31:11Z", "2024-05-28T10:00:00Z");
+ TestNext("* * 10 L-4 * 1", "2024-04-23T10:31:11Z", "2024-05-27T10:00:00Z");
+ TestNext("* * 10 L-5 * 0", "2024-04-23T10:31:11Z", "2024-05-26T10:00:00Z");
+ TestNext("* * 10 L-6 * 6", "2024-04-23T10:31:11Z", "2024-05-25T10:00:00Z");
+ }
+
+ Y_UNIT_TEST(DifferentCases) {
+ TestNext("10-45/3 * * * * *", "2012-12-01T09:42:19Z", "2012-12-01T09:42:22Z");
+ TestNext("10-45/3 * * * * *", "2012-12-01T09:42:45Z", "2012-12-01T09:43:10Z");
+ TestNext("* * 19/2 * * *", "2012-12-01T09:42:45Z", "2012-12-01T19:00:00Z");
+ TestNext("* * 19/2 * * *", "2012-12-01T19:42:45Z", "2012-12-01T19:42:46Z");
+ TestNext("37 * 19/2 * * *", "2012-12-01T19:42:45Z", "2012-12-01T19:43:37Z");
+ TestNext("37 * 19/2 * * *", "2012-12-01T19:59:45Z", "2012-12-01T21:00:37Z");
+ TestNext("37 * 19/2 * * *", "2012-12-01T19:59:37Z", "2012-12-01T21:00:37Z");
+ TestNext("37 * 18/2 * * *", "2012-12-01T23:00:00Z", "2012-12-02T18:00:37Z");
+ TestNext("37 * 18/2 * * *", "2012-12-01T22:59:37Z", "2012-12-02T18:00:37Z");
+ TestNext("0 0 7 W * *", "2009-09-26T00:42:55Z", "2009-09-28T07:00:00Z");
+ TestNext("0 0 7 W * *", "2009-09-28T07:00:00Z", "2009-09-29T07:00:00Z");
+ TestNext("* * * * * L", "2010-10-25T15:12:42Z", "2010-10-31T00:00:00Z");
+ TestNext("* * * * * L", "2010-10-20T15:12:42Z", "2010-10-24T00:00:00Z");
+ TestNext("* * * * * L", "2010-10-27T15:12:42Z", "2010-10-31T00:00:00Z");
+ TestNext("* 15 11 * * *", "2019-03-09T11:43:00Z", "2019-03-10T11:15:00Z");
+ TestNext("*/15 * 1-4 * * *", "2012-07-01T09:53:50Z", "2012-07-02T01:00:00Z");
+ TestNext("*/15 * 1-4 * * *", "2012-07-01T09:53:00Z", "2012-07-02T01:00:00Z");
+ TestNext("3,15,30,45 * 1,2,3,4 * * *", "2012-07-01T01:53:00Z", "2012-07-01T01:53:03Z");
+ TestNext("3,15,30,45 10 * * * *", "2012-07-01T09:53:10Z", "2012-07-01T10:10:03Z");
+ TestNext("3,15,30,45 * 1,2,3,4 * * *", "2012-07-01T09:53:10Z", "2012-07-02T01:00:03Z");
+ TestNext("10,20 1,2,3,4 1,2,3,6 * *", "2012-07-01T09:15:00Z", "2012-07-02T01:10:00Z");
+ TestNext("0 */2 1-4 * * *", "2012-07-01T09:00:00Z", "2012-07-02T01:00:00Z");
+ TestNext("0 */2 * * * *", "2012-07-01T09:00:00Z", "2012-07-01T09:02:00Z");
+ TestNext("0 */2 * * * *", "2013-07-01T09:00:00Z", "2013-07-01T09:02:00Z");
+ TestNext("0 */2 * * * *", "2018-09-14T14:24:00Z", "2018-09-14T14:26:00Z");
+ TestNext("0 */2 * * * *", "2018-09-14T14:25:00Z", "2018-09-14T14:26:00Z");
+ TestNext("0 */20 * * * *", "2018-09-14T14:24:00Z", "2018-09-14T14:40:00Z");
+ TestNext("* * * * * *", "2012-07-01T09:00:00Z", "2012-07-01T09:00:01Z");
+ TestNext("* * * * * *", "2012-12-01T09:00:58Z", "2012-12-01T09:00:59Z");
+ TestNext("10 * * * * *", "2012-12-01T09:42:09Z", "2012-12-01T09:42:10Z");
+ TestNext("11 * * * * *", "2012-12-01T09:42:10Z", "2012-12-01T09:42:11Z");
+ TestNext("10 * * * * *", "2012-12-01T09:42:10Z", "2012-12-01T09:43:10Z");
+ TestNext("10-15 * * * * *", "2012-12-01T09:42:09Z", "2012-12-01T09:42:10Z");
+ TestNext("10-15 * * * * *", "2012-12-01T21:42:14Z", "2012-12-01T21:42:15Z");
+ TestNext("0 * * * * *", "2012-12-01T21:10:42Z", "2012-12-01T21:11:00Z");
+ TestNext("0 * * * * *", "2012-12-01T21:11:00Z", "2012-12-01T21:12:00Z");
+ TestNext("0 11 * * * *", "2012-12-01T21:10:42Z", "2012-12-01T21:11:00Z");
+ TestNext("0 10 * * * *", "2012-12-01T21:11:00Z", "2012-12-01T22:10:00Z");
+ TestNext("0 0 * * * *", "2012-09-30T11:01:00Z", "2012-09-30T12:00:00Z");
+ TestNext("0 0 * * * *", "2012-09-30T12:00:00Z", "2012-09-30T13:00:00Z");
+ TestNext("0 0 * * * *", "2012-09-10T23:01:00Z", "2012-09-11T00:00:00Z");
+ TestNext("0 0 * * * *", "2012-09-11T00:00:00Z", "2012-09-11T01:00:00Z");
+ TestNext("0 0 0 * * *", "2012-09-01T14:42:43Z", "2012-09-02T00:00:00Z");
+ TestNext("0 0 0 * * *", "2012-09-02T00:00:00Z", "2012-09-03T00:00:00Z");
+ TestNext("* * * 10 * *", "2012-10-09T15:12:42Z", "2012-10-10T00:00:00Z");
+ TestNext("* * * 10 * *", "2012-10-11T15:12:42Z", "2012-11-10T00:00:00Z");
+ TestNext("0 0 0 * * *", "2012-09-30T15:12:42Z", "2012-10-01T00:00:00Z");
+ TestNext("0 0 0 * * *", "2012-10-01T00:00:00Z", "2012-10-02T00:00:00Z");
+ TestNext("0 0 0 * * *", "2012-08-30T15:12:42Z", "2012-08-31T00:00:00Z");
+ TestNext("0 0 0 * * *", "2012-08-31T00:00:00Z", "2012-09-01T00:00:00Z");
+ TestNext("0 0 0 * * *", "2012-10-30T15:12:42Z", "2012-10-31T00:00:00Z");
+ TestNext("0 0 0 * * *", "2012-10-31T00:00:00Z", "2012-11-01T00:00:00Z");
+ TestNext("0 0 0 1 * *", "2012-10-30T15:12:42Z", "2012-11-01T00:00:00Z");
+ TestNext("0 0 0 1 * *", "2012-11-01T00:00:00Z", "2012-12-01T00:00:00Z");
+ TestNext("0 0 0 1 * *", "2010-12-31T15:12:42Z", "2011-01-01T00:00:00Z");
+ TestNext("0 0 0 1 * *", "2011-01-01T00:00:00Z", "2011-02-01T00:00:00Z");
+ TestNext("0 0 0 31 * *", "2011-10-30T15:12:42Z", "2011-10-31T00:00:00Z");
+ TestNext("0 0 0 1 * *", "2011-10-30T15:12:42Z", "2011-11-01T00:00:00Z");
+ TestNext("* * * * * 2", "2010-10-25T15:12:42Z", "2010-10-26T00:00:00Z");
+ TestNext("* * * * * 2", "2010-10-20T15:12:42Z", "2010-10-26T00:00:00Z");
+ TestNext("* * * * * 2", "2010-10-27T15:12:42Z", "2010-11-02T00:00:00Z");
+ TestNext("55 5 * * * *", "2010-10-27T15:04:54Z", "2010-10-27T15:05:55Z");
+ TestNext("55 5 * * * *", "2010-10-27T15:05:55Z", "2010-10-27T16:05:55Z");
+ TestNext("55 * 10 * * *", "2010-10-27T09:04:54Z", "2010-10-27T10:00:55Z");
+ TestNext("55 * 10 * * *", "2010-10-27T10:00:55Z", "2010-10-27T10:01:55Z");
+ TestNext("* 5 10 * * *", "2010-10-27T09:04:55Z", "2010-10-27T10:05:00Z");
+ TestNext("* 5 10 * * *", "2010-10-27T10:05:00Z", "2010-10-27T10:05:01Z");
+ TestNext("55 * * 3 * *", "2010-10-02T10:05:54Z", "2010-10-03T00:00:55Z");
+ TestNext("55 * * 3 * *", "2010-10-03T00:00:55Z", "2010-10-03T00:01:55Z");
+ TestNext("* * * 3 11 *", "2010-10-02T14:42:55Z", "2010-11-03T00:00:00Z");
+ TestNext("* * * 3 11 *", "2010-11-03T00:00:00Z", "2010-11-03T00:00:01Z");
+ TestNext("0 0 0 29 2 *", "2007-02-10T14:42:55Z", "2008-02-29T00:00:00Z");
+ TestNext("0 0 0 29 2 *", "2008-02-29T00:00:00Z", "2012-02-29T00:00:00Z");
+ TestNext("0 0 7 ? * MON-FRI", "2009-09-26T00:42:55Z", "2009-09-28T07:00:00Z");
+ TestNext("0 0 7 ? * MON-FRI", "2009-09-28T07:00:00Z", "2009-09-29T07:00:00Z");
+ TestNext("0 0 7 ? * 6-0", "2024-05-02T15:37:04Z", "2024-05-04T07:00:00Z");
+ TestNext("0 30 23 30 1/3 ?", "2010-12-30T00:00:00Z", "2011-01-30T23:30:00Z");
+ TestNext("0 30 23 30 1/3 ?", "2011-01-30T23:30:00Z", "2011-04-30T23:30:00Z");
+ TestNext("0 30 23 30 1/3 ?", "2011-04-30T23:30:00Z", "2011-07-30T23:30:00Z");
+ TestNext("* * * * * *", "2020-12-31T23:59:59Z", "2021-01-01T00:00:00Z");
+ TestNext("0 0 * * * *", "2020-02-28T23:00:00Z", "2020-02-29T00:00:00Z");
+ TestNext("0 0 0 * * *", "2020-02-29T01:02:03Z", "2020-03-01T00:00:00Z");
+ TestNext("0 0 0 ? 11-12 *", "2022-05-31T00:00:00Z", "2022-11-01T00:00:00Z");
+ TestNext("0 0 0 ? 11-12 *", "2022-07-31T00:00:00Z", "2022-11-01T00:00:00Z");
+ TestNext("0 0 0 ? 11-12 *", "2022-08-31T00:00:00Z", "2022-11-01T00:00:00Z");
+ TestNext("0 0 0 ? 11-12 *", "2022-10-31T00:00:00Z", "2022-11-01T00:00:00Z");
+ TestNext("0 0 0 ? 6-7 *", "2022-05-31T00:00:00Z", "2022-06-01T00:00:00Z");
+ TestNext("0 0 0 ? 8-9 *", "2022-07-31T00:00:00Z", "2022-08-01T00:00:00Z");
+ TestNext("0 0 0 ? 9-10 *", "2022-08-31T00:00:00Z", "2022-09-01T00:00:00Z");
+ TestNext("0 0 0 ? 2-3 *", "2022-01-31T00:00:00Z", "2022-02-01T00:00:00Z");
+ TestNext("0 0 0 ? 4-5 *", "2022-03-31T00:00:00Z", "2022-04-01T00:00:00Z");
+ TestNext("* * * 29 2 *", "2021-12-07T12:00:00Z", "2024-02-29T00:00:00Z");
+ }
+
+ Y_UNIT_TEST(TypedDates) {
+ TestNext("@annually", "2021-12-07T12:00:00Z", "2022-01-01T00:00:00Z");
+ TestNext("@yearly", "2021-12-07T12:00:00Z", "2022-01-01T00:00:00Z");
+ TestNext("@monthly", "2021-11-07T12:23:00Z", "2021-12-01T00:00:00Z");
+ TestNext("@weekly", "2024-04-22T16:05:32Z", "2024-04-28T00:00:00Z");
+ TestNext("@daily", "2024-04-22T16:05:32Z", "2024-04-23T00:00:00Z");
+ TestNext("@hourly", "2021-12-07T12:20:07Z", "2021-12-07T13:00:00Z");
+ TestNext("@minutely", "2024-04-22T16:05:32Z", "2024-04-22T16:06:00Z");
+ TestNext("@secondly", "2021-12-07T12:00:00Z", "2021-12-07T12:00:01Z");
+ }
+}
+
+Y_UNIT_TEST_SUITE(TestPrev) {
+ Y_UNIT_TEST(DifferentCases) {
+ TestPrev("* 15 11 * * *", "2019-03-09T11:43:00Z", "2019-03-09T11:15:59Z");
+ TestPrev("*/15 * 1-4 * * *", "2012-07-01T09:53:50Z", "2012-07-01T04:59:45Z");
+ TestPrev("*/15 * 1-4 * * *", "2012-07-01T01:00:14Z", "2012-07-01T01:00:00Z");
+ TestPrev("*/15 * 1-4 * * *", "2012-07-01T01:00:00Z", "2012-06-30T04:59:45Z");
+ TestPrev("* * * * * *", "2012-07-01T09:00:00Z", "2012-07-01T08:59:59Z");
+ TestPrev("* * * * * *", "2021-01-01T00:00:00Z", "2020-12-31T23:59:59Z");
+ TestPrev("0 0 * * * *", "2020-02-29T00:00:00Z", "2020-02-28T23:00:00Z");
+ TestPrev("0 0 0 * * *", "2020-03-01T00:00:00Z", "2020-02-29T00:00:00Z");
+ TestPrev("0 0 * * * *", "2020-03-01T00:00:00Z", "2020-02-29T23:00:00Z");
+
+ TestPrev("* * * 29 2 *", "2021-12-07T12:00:00Z", "2020-02-29T23:59:59Z");
+
+ TestPrev("* * * 1 2 *", "2023-11-01T00:00:00Z", "2023-02-01T23:59:59Z");
+ TestPrev("* * * 2 2 *", "2023-11-01T00:00:00Z", "2023-02-02T23:59:59Z");
+ TestPrev("* * * 3 2 *", "2023-11-01T00:00:00Z", "2023-02-03T23:59:59Z");
+ TestPrev("* * * 4 2 *", "2023-11-01T00:00:00Z", "2023-02-04T23:59:59Z");
+
+ TestPrev("* * * 1 4 *", "2023-10-01T00:00:00Z", "2023-04-01T23:59:59Z");
+ TestPrev("* * * 2 4 *", "2023-10-01T00:00:00Z", "2023-04-02T23:59:59Z");
+ TestPrev("* * * 3 4 *", "2023-10-01T00:00:00Z", "2023-04-03T23:59:59Z");
+ TestPrev("* * * 4 4 *", "2023-10-01T00:00:00Z", "2023-04-04T23:59:59Z");
+
+ TestPrev("0 0 20 1 2 *", "2022-12-30T08:10:23Z", "2022-02-01T20:00:00Z");
+ TestPrev("0 0 20 2 2 *", "2022-12-30T08:10:23Z", "2022-02-02T20:00:00Z");
+ TestPrev("0 0 20 3 2 *", "2022-12-30T08:10:23Z", "2022-02-03T20:00:00Z");
+ TestPrev("0 0 20 1 2 *", "2022-12-31T08:10:23Z", "2022-02-01T20:00:00Z");
+ TestPrev("0 0 20 2 2 *", "2022-12-31T08:10:23Z", "2022-02-02T20:00:00Z");
+ TestPrev("0 0 20 3 2 *", "2022-12-31T08:10:23Z", "2022-02-03T20:00:00Z");
+ TestPrev("0 0 20 1 2 *", "2023-01-01T08:10:23Z", "2022-02-01T20:00:00Z");
+ TestPrev("0 0 20 2 2 *", "2023-01-01T08:10:23Z", "2022-02-02T20:00:00Z");
+ TestPrev("0 0 20 3 2 *", "2023-01-01T08:10:23Z", "2022-02-03T20:00:00Z");
+
+ TestPrev("0 0 17 * 2 2-4", "2023-08-31T18:00:00Z", "2023-02-28T17:00:00Z");
+ TestPrev("0 0 17 * 2 2-4", "2023-09-01T18:00:00Z", "2023-02-28T17:00:00Z");
+ TestPrev("0 0 17 * 2 2-4", "2023-09-02T18:00:00Z", "2023-02-28T17:00:00Z");
+ TestPrev("0 0 17 * 2 2-4", "2023-09-03T18:00:00Z", "2023-02-28T17:00:00Z");
+ TestPrev("0 0 17 * 2 2-4", "2023-09-04T18:00:00Z", "2023-02-28T17:00:00Z");
+ TestPrev("0 0 17 * 2 2-4", "2023-09-05T18:00:00Z", "2023-02-28T17:00:00Z");
+
+ TestPrev("0 0 17 * 3 1-5", "2023-03-02T17:00:00Z", "2023-03-01T17:00:00Z");
+ TestPrev("0 0 17 * 3 1-5", "2023-03-02T17:00:01Z", "2023-03-02T17:00:00Z");
+ TestPrev("0 0 17 * 3 1-5", "2023-03-02T18:00:00Z", "2023-03-02T17:00:00Z");
+ TestPrev("0 0 17 * 3 1-5", "2023-03-03T18:00:00Z", "2023-03-03T17:00:00Z");
+ TestPrev("0 0 17 * 3 1-5", "2023-03-04T18:00:00Z", "2023-03-03T17:00:00Z");
+ TestPrev("0 0 17 * 3 1-5", "2023-03-05T18:00:00Z", "2023-03-03T17:00:00Z");
+ TestPrev("0 0 17 * 3 1-5", "2023-03-06T18:00:00Z", "2023-03-06T17:00:00Z");
+
+ TestPrev("0 30 9 * 4 6", "2024-04-05T18:00:00Z", "2023-04-29T09:30:00Z");
+ TestPrev("0 30 9 * 4 6", "2024-04-06T09:29:59Z", "2023-04-29T09:30:00Z");
+ TestPrev("0 30 9 * 4 6", "2024-04-06T09:30:00Z", "2023-04-29T09:30:00Z");
+ TestPrev("0 30 9 * 4 6", "2024-04-06T09:30:01Z", "2024-04-06T09:30:00Z");
+ TestPrev("0 30 9 * 4 6", "2024-04-06T18:00:00Z", "2024-04-06T09:30:00Z");
+ TestPrev("0 30 9 * 4 6", "2024-04-07T18:00:00Z", "2024-04-06T09:30:00Z");
+ TestPrev("0 30 9 * 4 6", "2024-04-26T18:00:00Z", "2024-04-20T09:30:00Z");
+ TestPrev("0 30 9 * 4 6", "2024-04-27T18:00:00Z", "2024-04-27T09:30:00Z");
+ TestPrev("0 30 9 * 4 6", "2024-04-28T18:00:00Z", "2024-04-27T09:30:00Z");
+ TestPrev("0 30 9 * 4 6", "2024-05-01T18:00:00Z", "2024-04-27T09:30:00Z");
+
+ TestPrev("0 30 11 * * 6", "2020-02-27T10:00:00Z", "2020-02-22T11:30:00Z");
+ TestPrev("0 30 11 * * 6", "2020-02-28T10:00:00Z", "2020-02-22T11:30:00Z");
+ TestPrev("0 30 11 * * 6", "2020-02-29T10:00:00Z", "2020-02-22T11:30:00Z");
+ TestPrev("0 30 11 * * 6", "2020-02-29T11:31:00Z", "2020-02-29T11:30:00Z");
+ TestPrev("0 30 11 * * 6", "2020-03-01T10:00:00Z", "2020-02-29T11:30:00Z");
+ TestPrev("0 30 11 * * 6", "2020-03-01T12:00:00Z", "2020-02-29T11:30:00Z");
+
+ TestPrev("0 0 10 * * *", "2020-02-29T09:59:59Z", "2020-02-28T10:00:00Z");
+ TestPrev("0 0 10 * * *", "2020-02-29T10:00:00Z", "2020-02-28T10:00:00Z");
+ TestPrev("0 0 10 * * *", "2020-02-29T10:00:01Z", "2020-02-29T10:00:00Z");
+ TestPrev("0 0 10 * * *", "2022-02-28T09:59:59Z", "2022-02-27T10:00:00Z");
+ TestPrev("0 0 10 * * *", "2022-02-28T10:00:00Z", "2022-02-27T10:00:00Z");
+ TestPrev("0 0 10 * * *", "2022-02-28T10:00:01Z", "2022-02-28T10:00:00Z");
+ TestPrev("0 0 10 * * *", "2022-12-31T09:59:59Z", "2022-12-30T10:00:00Z");
+ TestPrev("0 0 10 * * *", "2022-12-31T10:00:00Z", "2022-12-30T10:00:00Z");
+ TestPrev("0 0 10 * * *", "2022-12-31T10:00:01Z", "2022-12-31T10:00:00Z");
+ TestPrev("0 0 10 * * *", "2022-12-31T23:59:59Z", "2022-12-31T10:00:00Z");
+ TestPrev("0 0 10 * * *", "2023-01-01T00:00:00Z", "2022-12-31T10:00:00Z");
+ TestPrev("0 0 10 * * *", "2023-01-01T00:00:01Z", "2022-12-31T10:00:00Z");
+ TestPrev("0 0 10 * * *", "2023-01-01T09:59:59Z", "2022-12-31T10:00:00Z");
+ TestPrev("0 0 10 * * *", "2023-01-01T10:00:00Z", "2022-12-31T10:00:00Z");
+ TestPrev("0 0 10 * * *", "2023-01-01T10:00:01Z", "2023-01-01T10:00:00Z");
+
+ TestPrev("30 50 23 20,21,22 * *", "2023-07-01T12:34:56Z", "2023-06-22T23:50:30Z");
+ TestPrev("30 50 23 20,21,22 * *", "2023-07-19T12:34:56Z", "2023-06-22T23:50:30Z");
+ TestPrev("30 50 23 20,21,22 * *", "2023-07-20T12:34:56Z", "2023-06-22T23:50:30Z");
+ TestPrev("30 50 23 20,21,22 * *", "2023-07-21T12:34:56Z", "2023-07-20T23:50:30Z");
+ TestPrev("30 50 23 20,21,22 * *", "2023-07-22T12:34:56Z", "2023-07-21T23:50:30Z");
+ TestPrev("30 50 23 20,21,22 * *", "2023-07-23T12:34:56Z", "2023-07-22T23:50:30Z");
+ }
+}
+
+Y_UNIT_TEST_SUITE(AliceBasicUsageExamples) {
+ Y_UNIT_TEST(First) {
+ TCronExpression cronConverter("*/10 * * * *");
+
+ TestNextCron(&cronConverter, "2023-07-20T12:34:56Z", "2023-07-20T12:40:00Z");
+ TestNextCron(&cronConverter, "2023-07-20T12:40:00Z", "2023-07-20T12:50:00Z");
+ TestNextCron(&cronConverter, "2023-07-20T23:50:00Z", "2023-07-21T00:00:00Z");
+
+ TestPrevCron(&cronConverter, "2023-07-20T23:50:00Z", "2023-07-20T23:40:00Z");
+ TestPrevCron(&cronConverter, "2023-07-20T00:00:01Z", "2023-07-20T00:00:00Z");
+ TestPrevCron(&cronConverter, "2023-07-20T00:00:00Z", "2023-07-19T23:50:00Z");
+ }
+
+ Y_UNIT_TEST(Second) {
+ TCronExpression cronConverter("0 6 * * 7");
+
+ TestNextCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-04-28T06:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-21T16:05:32Z", "2024-04-28T06:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-21T01:01:32Z", "2024-04-21T06:00:00Z");
+
+ TestPrevCron(&cronConverter, "2024-04-30T23:50:00Z", "2024-04-28T06:00:00Z");
+ TestPrevCron(&cronConverter, "2024-04-28T06:00:00Z", "2024-04-21T06:00:00Z");
+ TestPrevCron(&cronConverter, "2024-04-21T06:00:01Z", "2024-04-21T06:00:00Z");
+ }
+
+ Y_UNIT_TEST(Third) {
+ TCronExpression cronConverter("0 0 1 1 *");
+
+ TestNextCron(&cronConverter, "2024-04-22T16:05:32Z", "2025-01-01T00:00:00Z");
+ TestNextCron(&cronConverter, "2024-01-01T00:00:00Z", "2025-01-01T00:00:00Z");
+ TestNextCron(&cronConverter, "2024-12-31T23:59:59Z", "2025-01-01T00:00:00Z");
+
+ TestPrevCron(&cronConverter, "2025-04-22T16:05:32Z", "2025-01-01T00:00:00Z");
+ TestPrevCron(&cronConverter, "2025-01-01T00:00:01Z", "2025-01-01T00:00:00Z");
+ TestPrevCron(&cronConverter, "2026-01-01T00:00:00Z", "2025-01-01T00:00:00Z");
+ }
+
+ Y_UNIT_TEST(Fourth) {
+ TCronExpression cronConverter("30 15 * * 1-5");
+
+ TestNextCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-04-23T15:30:00Z");
+ TestNextCron(&cronConverter, "2024-04-20T16:05:32Z", "2024-04-22T15:30:00Z");
+ TestNextCron(&cronConverter, "2024-03-30T11:05:32Z", "2024-04-01T15:30:00Z");
+
+ TestPrevCron(&cronConverter, "2024-04-23T16:05:32Z", "2024-04-23T15:30:00Z");
+ TestPrevCron(&cronConverter, "2024-04-28T16:05:32Z", "2024-04-26T15:30:00Z");
+ TestPrevCron(&cronConverter, "2024-04-02T11:05:32Z", "2024-04-01T15:30:00Z");
+ }
+
+ Y_UNIT_TEST(Fifth) {
+ TCronExpression cronConverter("0 22 * * *");
+
+ TestNextCron(&cronConverter, "2024-04-20T16:05:32Z", "2024-04-20T22:00:00Z");
+ TestNextCron(&cronConverter, "2024-12-31T22:00:00Z", "2025-01-01T22:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-20T00:05:32Z", "2024-04-20T22:00:00Z");
+
+ TestPrevCron(&cronConverter, "2024-04-21T16:05:32Z", "2024-04-20T22:00:00Z");
+ TestPrevCron(&cronConverter, "2025-01-01T22:00:00Z", "2024-12-31T22:00:00Z");
+ TestPrevCron(&cronConverter, "2024-04-20T23:05:32Z", "2024-04-20T22:00:00Z");
+ }
+
+ Y_UNIT_TEST(Sixth) {
+ TCronExpression cronConverter("0 12 L * *");
+
+ TestNextCron(&cronConverter, "2024-04-20T16:05:32Z", "2024-04-30T12:00:00Z");
+ TestNextCron(&cronConverter, "2024-02-20T12:05:43Z", "2024-02-29T12:00:00Z");
+ TestNextCron(&cronConverter, "2021-02-01T22:05:32Z", "2021-02-28T12:00:00Z");
+
+ TestPrevCron(&cronConverter, "2024-05-20T16:05:32Z", "2024-04-30T12:00:00Z");
+ TestPrevCron(&cronConverter, "2024-03-20T12:05:43Z", "2024-02-29T12:00:00Z");
+ TestPrevCron(&cronConverter, "2021-03-01T22:05:32Z", "2021-02-28T12:00:00Z");
+ }
+
+ Y_UNIT_TEST(Seventh) {
+ TCronExpression cronConverter("0 8 * * 1-5");
+
+ TestNextCron(&cronConverter, "2024-04-22T07:59:59Z", "2024-04-22T08:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-20T07:59:59Z", "2024-04-22T08:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-22T14:29:54Z", "2024-04-23T08:00:00Z");
+
+ TestPrevCron(&cronConverter, "2024-04-22T08:00:01Z", "2024-04-22T08:00:00Z");
+ TestPrevCron(&cronConverter, "2024-04-23T07:59:59Z", "2024-04-22T08:00:00Z");
+ TestPrevCron(&cronConverter, "2024-04-22T06:29:54Z", "2024-04-19T08:00:00Z");
+ }
+
+ Y_UNIT_TEST(Eigths) {
+ TCronExpression cronConverter("0 */2 * * 7");
+
+ TestNextCron(&cronConverter, "2024-04-21T07:59:59Z", "2024-04-21T08:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-21T14:59:59Z", "2024-04-21T16:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-16T21:03:25Z", "2024-04-21T00:00:00Z");
+ }
+
+ Y_UNIT_TEST(Ninth) {
+ TCronExpression cronConverter("45 21 5 * *");
+
+ TestNextCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-05-05T21:45:00Z");
+ TestNextCron(&cronConverter, "2024-04-05T22:05:32Z", "2024-05-05T21:45:00Z");
+ TestNextCron(&cronConverter, "2024-04-05T16:05:32Z", "2024-04-05T21:45:00Z");
+
+ TestPrevCron(&cronConverter, "2024-05-22T16:05:32Z", "2024-05-05T21:45:00Z");
+ TestPrevCron(&cronConverter, "2024-05-05T22:05:32Z", "2024-05-05T21:45:00Z");
+ TestPrevCron(&cronConverter, "2024-05-05T16:05:32Z", "2024-04-05T21:45:00Z");
+ }
+
+ Y_UNIT_TEST(Tenth) {
+ TCronExpression cronConverter("0 3 * * 1-6");
+
+ TestNextCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-04-23T03:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-23T02:05:32Z", "2024-04-23T03:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-21T02:05:32Z", "2024-04-22T03:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-20T12:05:32Z", "2024-04-22T03:00:00Z");
+
+ TestPrevCron(&cronConverter, "2024-04-23T16:05:32Z", "2024-04-23T03:00:00Z");
+ TestPrevCron(&cronConverter, "2024-04-23T02:05:32Z", "2024-04-22T03:00:00Z");
+ TestPrevCron(&cronConverter, "2024-04-22T02:05:32Z", "2024-04-20T03:00:00Z");
+ TestPrevCron(&cronConverter, "2024-04-21T12:05:32Z", "2024-04-20T03:00:00Z");
+ }
+
+ Y_UNIT_TEST(Eleventh) {
+ TCronExpression cronConverter("0 17 * * 3");
+
+ TestNextCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-04-24T17:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-27T16:05:32Z", "2024-05-01T17:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-24T17:00:00Z", "2024-05-01T17:00:00Z");
+ TestNextCron(&cronConverter, "2023-12-28T19:45:32Z", "2024-01-03T17:00:00Z");
+
+ TestPrevCron(&cronConverter, "2024-05-01T16:05:32Z", "2024-04-24T17:00:00Z");
+ TestPrevCron(&cronConverter, "2024-05-01T18:05:32Z", "2024-05-01T17:00:00Z");
+ TestPrevCron(&cronConverter, "2024-05-01T17:00:00Z", "2024-04-24T17:00:00Z");
+ TestPrevCron(&cronConverter, "2024-01-02T19:45:32Z", "2023-12-27T17:00:00Z");
+ }
+
+ Y_UNIT_TEST(Twelvth) {
+ TCronExpression cronConverter("0 10,22 * * *");
+
+ TestNextCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-04-22T22:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-22T22:05:32Z", "2024-04-23T10:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-30T23:05:32Z", "2024-05-01T10:00:00Z");
+
+ TestPrevCron(&cronConverter, "2024-04-22T23:05:32Z", "2024-04-22T22:00:00Z");
+ TestPrevCron(&cronConverter, "2024-04-22T21:05:32Z", "2024-04-22T10:00:00Z");
+ TestPrevCron(&cronConverter, "2024-05-01T06:05:32Z", "2024-04-30T22:00:00Z");
+ }
+
+ Y_UNIT_TEST(Thirteenth) {
+ TCronExpression cronConverter("* * 1-5 * *");
+
+ TestNextCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-05-01T00:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-04T16:05:32Z", "2024-04-04T16:06:00Z");
+ TestNextCron(&cronConverter, "2024-04-04T16:05:00Z", "2024-04-04T16:06:00Z");
+ TestNextCron(&cronConverter, "2024-04-05T23:59:21Z", "2024-05-01T00:00:00Z");
+
+ TestPrevCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-04-05T23:59:00Z");
+ TestPrevCron(&cronConverter, "2024-04-04T16:05:32Z", "2024-04-04T16:05:00Z");
+ TestPrevCron(&cronConverter, "2024-04-04T16:05:00Z", "2024-04-04T16:04:00Z");
+ TestPrevCron(&cronConverter, "2024-04-01T00:00:00Z", "2024-03-05T23:59:00Z");
+ }
+
+ Y_UNIT_TEST(Fourteenth) {
+ TCronExpression cronConverter("*/15 * * * 1-5");
+
+ TestNextCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-04-22T16:15:00Z");
+ TestNextCron(&cronConverter, "2024-04-22T16:15:00Z", "2024-04-22T16:30:00Z");
+ TestNextCron(&cronConverter, "2024-04-20T16:05:32Z", "2024-04-22T00:00:00Z");
+
+ TestPrevCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-04-22T16:00:00Z");
+ TestPrevCron(&cronConverter, "2024-04-22T16:15:00Z", "2024-04-22T16:00:00Z");
+ TestPrevCron(&cronConverter, "2024-04-20T16:05:32Z", "2024-04-19T23:45:00Z");
+ }
+
+ Y_UNIT_TEST(Fifteenth) {
+ TCronExpression cronConverter("0 0 * * 6");
+
+ TestNextCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-04-27T00:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-27T00:00:00Z", "2024-05-04T00:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-27T16:05:32Z", "2024-05-04T00:00:00Z");
+
+ TestPrevCron(&cronConverter, "2024-05-02T16:05:32Z", "2024-04-27T00:00:00Z");
+ TestPrevCron(&cronConverter, "2024-05-04T00:00:00Z", "2024-04-27T00:00:00Z");
+ TestPrevCron(&cronConverter, "2024-04-27T16:05:32Z", "2024-04-27T00:00:00Z");
+ }
+
+ Y_UNIT_TEST(Sixteenth) {
+ TCronExpression cronConverter("20 14 * * 0-5");
+
+ TestNextCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-04-23T14:20:00Z");
+ TestNextCron(&cronConverter, "2024-04-22T11:05:32Z", "2024-04-22T14:20:00Z");
+ TestNextCron(&cronConverter, "2024-04-20T02:05:32Z", "2024-04-21T14:20:00Z");
+ TestNextCron(&cronConverter, "2024-04-19T14:20:00Z", "2024-04-21T14:20:00Z");
+
+ TestPrevCron(&cronConverter, "2024-04-24T11:05:32Z", "2024-04-23T14:20:00Z");
+ TestPrevCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-04-22T14:20:00Z");
+ TestPrevCron(&cronConverter, "2024-04-21T02:05:32Z", "2024-04-19T14:20:00Z");
+ TestPrevCron(&cronConverter, "2024-04-21T14:20:00Z", "2024-04-19T14:20:00Z");
+ }
+
+ Y_UNIT_TEST(Seventeenth) {
+ TCronExpression cronConverter("0 9,18 * * *");
+
+ TestNextCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-04-22T18:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-22T22:05:32Z", "2024-04-23T09:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-30T23:05:32Z", "2024-05-01T09:00:00Z");
+
+ TestPrevCron(&cronConverter, "2024-04-22T18:00:00Z", "2024-04-22T09:00:00Z");
+ TestPrevCron(&cronConverter, "2024-04-22T08:05:32Z", "2024-04-21T18:00:00Z");
+ TestPrevCron(&cronConverter, "2024-05-01T06:05:32Z", "2024-04-30T18:00:00Z");
+ }
+
+ Y_UNIT_TEST(Eighteenth) {
+ TCronExpression cronConverter("*/5 10 * * *");
+
+ TestNextCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-04-23T10:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-22T10:05:32Z", "2024-04-22T10:10:00Z");
+ TestNextCron(&cronConverter, "2024-04-22T10:15:00Z", "2024-04-22T10:20:00Z");
+ TestNextCron(&cronConverter, "2024-04-22T10:55:23Z", "2024-04-23T10:00:00Z");
+
+ TestPrevCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-04-22T10:55:00Z");
+ TestPrevCron(&cronConverter, "2024-04-22T10:10:32Z", "2024-04-22T10:10:00Z");
+ TestPrevCron(&cronConverter, "2024-04-22T10:25:00Z", "2024-04-22T10:20:00Z");
+ TestPrevCron(&cronConverter, "2024-04-23T08:55:23Z", "2024-04-22T10:55:00Z");
+ }
+
+ Y_UNIT_TEST(Nineteenth) {
+ TCronExpression cronConverter("30 7 * * 2,4");
+
+ TestNextCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-04-23T07:30:00Z");
+ TestNextCron(&cronConverter, "2024-04-23T16:05:32Z", "2024-04-25T07:30:00Z");
+ TestNextCron(&cronConverter, "2024-04-25T16:05:32Z", "2024-04-30T07:30:00Z");
+ TestNextCron(&cronConverter, "2024-04-23T04:05:32Z", "2024-04-23T07:30:00Z");
+
+ TestPrevCron(&cronConverter, "2024-04-24T16:05:32Z", "2024-04-23T07:30:00Z");
+ TestPrevCron(&cronConverter, "2024-04-29T16:05:32Z", "2024-04-25T07:30:00Z");
+ TestPrevCron(&cronConverter, "2024-04-30T16:05:32Z", "2024-04-30T07:30:00Z");
+ TestPrevCron(&cronConverter, "2024-04-23T04:05:32Z", "2024-04-18T07:30:00Z");
+ }
+
+ Y_UNIT_TEST(Twentieth) {
+ TCronExpression cronConverter("0 0 1,15 * *");
+
+ TestNextCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-05-01T00:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-15T00:00:00Z", "2024-05-01T00:00:00Z");
+ TestNextCron(&cronConverter, "2024-04-30T23:59:59Z", "2024-05-01T00:00:00Z");
+
+ TestPrevCron(&cronConverter, "2024-04-22T16:05:32Z", "2024-04-15T00:00:00Z");
+ TestPrevCron(&cronConverter, "2024-04-15T00:00:00Z", "2024-04-01T00:00:00Z");
+ TestPrevCron(&cronConverter, "2024-04-02T00:00:00Z", "2024-04-01T00:00:00Z");
+ }
+}
+
+Y_UNIT_TEST_SUITE(InvalidTests) {
+ Y_UNIT_TEST(InvalidFieldsAmount) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TCronExpression(""), yexception, "Invalid empty expression");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TCronExpression(" "), yexception, "Invalid number of fields, expression must consist of 5-7 fields but has: 0");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TCronExpression("* * * * * * * *"), yexception, "Invalid number of fields, expression must consist of 5-7 fields but has: 8");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TCronExpression("1 1 1 "), yexception, "Invalid number of fields, expression must consist of 5-7 fields but has: 3");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TCronExpression(" C S K A "), yexception, "Invalid number of fields, expression must consist of 5-7 fields but has: 4");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TCronExpression(" chemp i on "), yexception, "Invalid number of fields, expression must consist of 5-7 fields but has: 3");
+ }
+
+ Y_UNIT_TEST(InvalidTypedCrons) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TCronExpression("@@@@"), yexception, "Unknown typed cron");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TCronExpression("@ */2 * * 3 *"), yexception, "Unknown typed cron");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TCronExpression("@everyfriday13"), yexception, "Unknown typed cron");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TCronExpression("@milisecondly"), yexception, "Unknown typed cron");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TCronExpression("@reboot"), yexception, "@reboot not implemented");
+ }
+
+ Y_UNIT_TEST(InvalidCrons) {
+ UNIT_ASSERT_EXCEPTION(TCronExpression("1- * * * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("-4/3 * * * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("1-100 * * * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("-5-30/4 * * * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * * * * fRi-MO"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * * * * FR"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("0 0 1,15 * W"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("0 W 1,15 * W"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("W * * * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* W * * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * W * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * * * W *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * * * * W"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("L * * * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* L * * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * L * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * * * L *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * * * 13 *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("77 * * * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * -1 * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * * 32 2 * 2020"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * * * * 8"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * * * * * 1969"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("0 0 1,15 * 20492049"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("5-2 0 1,15 * W"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * * * * * 2021-2019"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * * * -4 *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* */-2 * * W *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("*/0.5 * * * W *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * * LW-1 * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("radio goo goo radio gaa gaa"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * 23-28 * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("*/0 1 * * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("/5 * * * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* 1 1 0 * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * * * * * 3050"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("60 * * * * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* 60 * * * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * 24 * * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * * 32 * * *"), yexception);
+ UNIT_ASSERT_EXCEPTION(TCronExpression("* * * * 13 * *"), yexception);
+ }
+
+ Y_UNIT_TEST(InvalidRequestInPastOrFuture) {
+ TCronExpression cronConverter("0 0 1,15 * * * 2020");
+
+ TestNextCronBadRequest(&cronConverter, "2030-02-22T16:05:32Z");
+ TestNextCronBadRequest(&cronConverter, "2020-12-31T15:00:00Z");
+ TestPrevCronBadRequest(&cronConverter, "2020-01-01T01:00:00Z");
+ TestPrevCronBadRequest(&cronConverter, "1970-02-22T16:05:32Z");
+ }
+
+ Y_UNIT_TEST(InvalidRequestDoesNotExist) {
+ TCronExpression cronConverter("0 0 7 30 2 * *");
+
+ TestNextCronBadRequest(&cronConverter, "2030-02-22T16:05:32Z");
+ }
+}
+
+} // namespace
+