fix bugs with dst-changes. maybe won't work for other DST-regimes
authorGerd von Egidy <gerd.von.egidy@intra2net.com>
Thu, 29 Jan 2009 18:16:01 +0000 (19:16 +0100)
committerGerd von Egidy <gerd.von.egidy@intra2net.com>
Thu, 29 Jan 2009 18:16:01 +0000 (19:16 +0100)
than Europe (e.g. US). So we'll need some other way to get the
start of the day.

src/cron.cpp
test/test_cron.cpp

index 2869eea..05587cc 100644 (file)
@@ -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<Week::WeekDay>(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<Week::WeekDay>(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...)
index 06fe262..c89f408 100644 (file)
@@ -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<time_t>(1225051200), cron.get_next_run(1224968400));
+        // expected next run: Sun Oct 26 20:00:00 2008
+        CPPUNIT_ASSERT_EQUAL( static_cast<time_t>(1225047600), cron.get_next_run(1224968400));
     }
 
     void BeforeDSTBackwards()
@@ -227,12 +228,20 @@ public:
         CPPUNIT_ASSERT_EQUAL( static_cast<time_t>(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<time_t>(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<time_t>(1238353200), cron.get_next_run(1238274000));
+        // expected next run: Sun Mar 29 22:00:00 2009
+        CPPUNIT_ASSERT_EQUAL( static_cast<time_t>(1238356800), cron.get_next_run(1238274000));
     }
 
     void BeforeDSTForward()