From e183fb4c312daa705686e0d3664d763a94fdf69f Mon Sep 17 00:00:00 2001 From: Gerd von Egidy Date: Thu, 29 Jan 2009 19:16:01 +0100 Subject: [PATCH] fix bugs with dst-changes. maybe won't work for other DST-regimes than Europe (e.g. US). So we'll need some other way to get the start of the day. --- src/cron.cpp | 44 ++++++++++++++++++++++++++++++++++++-------- test/test_cron.cpp | 17 +++++++++++++---- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/cron.cpp b/src/cron.cpp index 2869eea..05587cc 100644 --- a/src/cron.cpp +++ b/src/cron.cpp @@ -139,14 +139,27 @@ time_t WeekCron::get_next_point(const time_t calc_from, const int daysec, const // take care of the weekday ft.tm_mday+=Week.days_till_set(static_cast(ft.tm_wday)); + // get a time which is _really_ (=undisturbed by DST) at the day we selected + // 1:59h is a good time for that because it is before DST-change-hours and + // we currently don't have bigger DST-offsets than +-1:59h today + // (double-DST 1949 is not relevant because we use unixtime which is 1970+) + ft.tm_hour=1; + ft.tm_min=59; + ft.tm_sec=0; + + // one roundtrip to get tm_isdst + time_t target=mktime(&ft); + localtime_r(&target,&ft); + + // now dstft.tm_isdst is set correctly for the start of the day we selected + + // calculate start of the day selected ft.tm_hour=0; ft.tm_min=0; - ft.tm_sec=daysec; + ft.tm_sec=0; - // bug: we don't care about tm_isdst - // it can change when adding days or seconds - - time_t target=mktime(&ft); + // get unixtime of start of the day and add daysec + target=mktime(&ft)+daysec; // todays schedule could already been through or now if (todaycheck && target <= calc_from) @@ -154,7 +167,6 @@ time_t WeekCron::get_next_point(const time_t calc_from, const int daysec, const // not today but the next matching weekday localtime_r(&calc_from,&ft); ft.tm_mday++; - return get_next_point(mktime(&ft),daysec,false); } @@ -180,11 +192,27 @@ time_t WeekCron::get_previousnow_point(const time_t calc_from, const int daysec, // take care of the weekday ft.tm_mday-=Week.days_since_set(static_cast(ft.tm_wday)); + // get a time which is _really_ (=undisturbed by DST) at the day we selected + // 1:59h is a good time for that because it is before DST-change-hours and + // we currently don't have bigger DST-offsets than +-1:59h today + // (double-DST 1949 is not relevant because we use unixtime which is 1970+) + ft.tm_hour=1; + ft.tm_min=59; + ft.tm_sec=0; + + // one roundtrip to get tm_isdst + time_t target=mktime(&ft); + localtime_r(&target,&ft); + + // now dstft.tm_isdst is set correctly for the start of the day we selected + + // calculate start of the day selected ft.tm_hour=0; ft.tm_min=0; - ft.tm_sec=daysec; + ft.tm_sec=0; - time_t target=mktime(&ft); + // get unixtime of start of the day and add daysec + target=mktime(&ft)+daysec; // target later than we are looking for // target==calc_from is ok (that's why it is called lastnow...) diff --git a/test/test_cron.cpp b/test/test_cron.cpp index 06fe262..c89f408 100644 --- a/test/test_cron.cpp +++ b/test/test_cron.cpp @@ -45,6 +45,7 @@ class TestCronFunc : public TestFixture CPPUNIT_TEST(EndDSTBackwards3); CPPUNIT_TEST(EndDSTBackwards4); CPPUNIT_TEST(OverDSTBackwards); + CPPUNIT_TEST(OverDSTBackwardsDaychange); CPPUNIT_TEST(LongBeforeDSTForward); CPPUNIT_TEST(BeforeDSTForward); CPPUNIT_TEST(AtDSTForward); @@ -158,8 +159,8 @@ public: { WeekCron cron("0123456",75600); // calc at: Sun Oct 26 00:00:00 CEST 2008 - // expected next run: Sun Oct 26 21:00:00 CET 2008 - CPPUNIT_ASSERT_EQUAL( static_cast(1225051200), cron.get_next_run(1224968400)); + // expected next run: Sun Oct 26 20:00:00 2008 + CPPUNIT_ASSERT_EQUAL( static_cast(1225047600), cron.get_next_run(1224968400)); } void BeforeDSTBackwards() @@ -227,12 +228,20 @@ public: CPPUNIT_ASSERT_EQUAL( static_cast(1225159200), cron.get_next_run(1224903600)); } + void OverDSTBackwardsDaychange() + { + WeekCron cron("234",0); + // calc at: Sat Oct 25 00:00:00 2008 + // expected next run: Tue Oct 28 00:00:00 2008 + CPPUNIT_ASSERT_EQUAL( static_cast(1225148400), cron.get_next_run(1224885600)); + } + void LongBeforeDSTForward() { WeekCron cron("0123456",75600); // calc at: Sat Mar 28 22:00:00 CET 2009 - // expected next run: Sun Mar 29 21:00:00 2009 - CPPUNIT_ASSERT_EQUAL( static_cast(1238353200), cron.get_next_run(1238274000)); + // expected next run: Sun Mar 29 22:00:00 2009 + CPPUNIT_ASSERT_EQUAL( static_cast(1238356800), cron.get_next_run(1238274000)); } void BeforeDSTForward() -- 1.7.1