diff --git a/README.md b/README.md index 8fc295a..24f4f1b 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ # libcron A C++ scheduling library using cron formatting. -# Time zones +# Local time vs UTC -This library uses `std::chrono::system_clock::timepoint` as its time unit, thus all calculations are in UTC. +This library uses `std::chrono::system_clock::timepoint` as its time unit. While that is UTC by default, the Cron-class +uses a `LocalClock` by default which offsets `system_clock::now()` by the current UTC-offset. If you wish to work in +UTC, then construct the Cron instance, passing it a `libcron::UTCClock`. # Supported formatting @@ -67,5 +69,5 @@ the '?'-character unless one field already is something other than '*'. # Third party libraries -Howard Hinnant's [date.h](https://github.com/HowardHinnant/date/) +Howard Hinnant's [date libraries](https://github.com/HowardHinnant/date/) diff --git a/libcron/Cron.h b/libcron/Cron.h index 0d50b50..2efbd1a 100644 --- a/libcron/Cron.h +++ b/libcron/Cron.h @@ -13,7 +13,7 @@ namespace libcron { public: - explicit Cron(std::unique_ptr clock = std::make_unique()) + explicit Cron(std::unique_ptr clock = std::make_unique()) : clock(std::move(clock)) { } diff --git a/libcron/CronClock.h b/libcron/CronClock.h index b833b60..71b02c4 100644 --- a/libcron/CronClock.h +++ b/libcron/CronClock.h @@ -2,12 +2,16 @@ #include +using namespace std::chrono; +using namespace date; + namespace libcron { class ICronClock { public: virtual std::chrono::system_clock::time_point now() = 0; + virtual std::chrono::seconds utc_offset(std::chrono::system_clock::time_point now) = 0; }; class UTCClock @@ -18,5 +22,33 @@ namespace libcron { return std::chrono::system_clock::now(); } + + std::chrono::seconds utc_offset(std::chrono::system_clock::time_point) override + { + return 0s; + } + }; + + class LocalClock + : public ICronClock + { + public: + std::chrono::system_clock::time_point now() override + { + auto now = system_clock::now(); + return now + utc_offset(now); + } + + std::chrono::seconds utc_offset(std::chrono::system_clock::time_point now) override + { + auto t = system_clock::to_time_t(now); + tm tm{}; +#ifdef __WIN32 + localtime_s(&tm, &t); +#else + localtime_r(&t, &tm); +#endif + return seconds{tm.tm_gmtoff}; + } }; } \ No newline at end of file diff --git a/test/CronScheduleTest.cpp b/test/CronScheduleTest.cpp index 44ff14a..c13351f 100644 --- a/test/CronScheduleTest.cpp +++ b/test/CronScheduleTest.cpp @@ -16,7 +16,7 @@ system_clock::time_point DT(year_month_day ymd, hours h = hours{0}, minutes m = } bool test(const std::string& schedule, system_clock::time_point from, - std::vector expected_next) + const std::vector& expected_next) { auto c = CronData::create(schedule); bool res = c.is_valid(); @@ -209,22 +209,6 @@ SCENARIO("Examples from README.md") })); } -//SCENARIO("Daylight Savings Time") -//{ -// // In sweden when local standard time is about to reach -// //Sunday, 25 March 2018, 02:00:00 clocks are turned forward 1 hour to -// //Sunday, 25 March 2018, 03:00:00 local daylight time instead. -// -// REQUIRE(test("0 0 * * * ?", DT(2018_y / 3 / 25, hours{0}), -// { -// DT(2018_y / 3 / 25, hours{0}), -// DT(2018_y / 3 / 25, hours{1}), -// // This hour disappear! DT(2018_y / 3 / 25, hours{2}), -// DT(2018_y / 3 / 25, hours{3}), -// DT(2018_y / 3 / 25, hours{4}) -// })); -//} - SCENARIO("Unable to calculate time point") { // TODO: Find a schedule that is unsolvable. diff --git a/test/CronTest.cpp b/test/CronTest.cpp index 5e4b169..b496cfd 100644 --- a/test/CronTest.cpp +++ b/test/CronTest.cpp @@ -6,9 +6,9 @@ using namespace libcron; using namespace std::chrono; -std::string create_schedule_expiring_in(hours h, minutes m, seconds s) +std::string create_schedule_expiring_in(std::shared_ptr clock, hours h, minutes m, seconds s) { - auto now = system_clock::now() + h + m + s; + auto now = clock->now() + h + m + s; auto dt = CronSchedule::to_calendar_time(now); std::string res{}; @@ -66,7 +66,7 @@ SCENARIO("Adding a task that expires in the future") auto expired = false; Cron c; - REQUIRE(c.add_schedule("A task", create_schedule_expiring_in(hours{0}, minutes{0}, seconds{3}), + REQUIRE(c.add_schedule("A task", create_schedule_expiring_in(c.get_clock(), hours{0}, minutes{0}, seconds{3}), [&expired]() { expired = true; @@ -107,14 +107,14 @@ SCENARIO("Task priority") Cron c; - REQUIRE(c.add_schedule("Five", create_schedule_expiring_in(hours{0}, minutes{0}, seconds{5}), + REQUIRE(c.add_schedule("Five", create_schedule_expiring_in(c.get_clock(), hours{0}, minutes{0}, seconds{5}), [&_5_second_expired]() { _5_second_expired++; }) ); - REQUIRE(c.add_schedule("Three", create_schedule_expiring_in(hours{0}, minutes{0}, seconds{3}), + REQUIRE(c.add_schedule("Three", create_schedule_expiring_in(c.get_clock(), hours{0}, minutes{0}, seconds{3}), [&_3_second_expired]() { _3_second_expired++;