scheduling class can do intervals now, some fixes
authorGerd v. Egidy <gerd.von.egidy@intra2net.com>
Wed, 28 Jan 2009 01:32:17 +0000 (02:32 +0100)
committerGerd v. Egidy <gerd.von.egidy@intra2net.com>
Wed, 28 Jan 2009 01:32:17 +0000 (02:32 +0100)
src/cron.cpp
src/cron.hpp
src/timefunc.cpp
src/timefunc.hxx
test/test_cron.cpp

index f3103bf..c85c680 100644 (file)
@@ -13,6 +13,9 @@
 
 #include <cron.hpp>
 
+/**
+    @brief checks if the values are usable
+*/
 bool WeekCron::is_sane()
 {
     if (begin < 0 || begin > 86399)
@@ -21,7 +24,7 @@ bool WeekCron::is_sane()
     if (every != -1)
     {
         if (end < 0 || end > 86399 ||
-            every < 0 || every > 86399 ||
+            every < 1 || every > 86399 ||
             begin > end)
             return false;
     }
@@ -29,6 +32,11 @@ bool WeekCron::is_sane()
     return true;
 }
 
+/**
+    @brief returns the next point in time the item is scheduled for
+    @param calc_from unix-time to start calculating from (0 means now)
+    @note if it is scheduled for calc_from we return the next schedule, not now!
+*/
 time_t WeekCron::get_next_run(time_t calc_from)
 {
     if (!calc_from)
@@ -46,17 +54,36 @@ time_t WeekCron::get_next_run(time_t calc_from)
     if (every == -1)
     {
         // point in time
-        return get_next_point(calc_from);
+        return get_next_point(calc_from,begin,true);
     }
     else
     {
         // interval
-
-        // TODO
+        if (get_next_point(calc_from,begin,true) > get_next_point(calc_from,end,true))
+        {
+            // next begin > next end means we are at the begin or within the interval
+
+            time_t interval_begin=get_lastnow_point(calc_from,begin,true);
+
+            time_t within_interval=calc_from - interval_begin;
+            time_t since_lastrun=within_interval % every;
+            time_t next_exec=calc_from+(every-since_lastrun);
+
+            // next step after end?
+            if (next_exec > get_next_point(calc_from,end,true))
+                return get_next_point(calc_from,begin,true);
+            else
+                return next_exec;
+        }
+        else
+        {
+            // next begin < next end means we are out of the interval: next begin is next run
+            return get_next_point(calc_from,begin,true);
+        }
     }
 }
 
-time_t WeekCron::get_next_point(time_t calc_from)
+time_t WeekCron::get_next_point(time_t calc_from, int daysec, bool todaycheck)
 {
     struct tm ft;
     localtime_r(&calc_from,&ft);
@@ -66,18 +93,46 @@ time_t WeekCron::get_next_point(time_t calc_from)
 
     ft.tm_hour=0;
     ft.tm_min=0;
-    ft.tm_sec=begin;
+    ft.tm_sec=daysec;
 
     time_t target=mktime(&ft);
 
-    // todays schedule could already been through
-    if (target < calc_from)
+    // todays schedule could already been through or now
+    if (todaycheck && target <= calc_from)
     {
+        // not today but the next matching weekday
+        localtime_r(&calc_from,&ft);
         ft.tm_mday++;
-        target=mktime(&ft);
+        return get_next_point(mktime(&ft),daysec,false);
     }
 
     return target;
 }
 
+time_t WeekCron::get_lastnow_point(time_t calc_from, int daysec, bool todaycheck)
+{
+    struct tm ft;
+    localtime_r(&calc_from,&ft);
+
+    // take care of the weekday
+    ft.tm_mday-=week.days_since_set(static_cast<WEEK::WEEKDAY>(ft.tm_wday));
+
+    ft.tm_hour=0;
+    ft.tm_min=0;
+    ft.tm_sec=daysec;
+
+    time_t target=mktime(&ft);
+
+    // target later than we are looking for
+    // target==calc_from is ok (that's why it is called lastnow...)
+    if (todaycheck && target > calc_from)
+    {
+        // not today but the next matching weekday
+        localtime_r(&calc_from,&ft);
+        ft.tm_mday--;
+        return get_next_point(mktime(&ft),daysec,false);
+    }
+
+    return target;
+}
 
index 26e67f4..41cd418 100644 (file)
@@ -27,7 +27,8 @@ class WeekCron
         int every;
         WEEK week;
 
-        time_t get_next_point(time_t calc_from=0);
+        time_t get_next_point(time_t calc_from, int daysec,bool todaycheck);
+        time_t get_lastnow_point(time_t calc_from, int daysec,bool todaycheck);
 
     public:
 
index f66e61b..56bfcc8 100644 (file)
@@ -208,6 +208,31 @@ int WEEK::days_till_set(WEEKDAY start)
     return -1;
 }
 
+/**
+    @brief returns the number of days since the previous weekday which is set
+    @param start weekday to start checking
+    @note returns 0 if the start-day is set
+*/
+int WEEK::days_since_set(WEEKDAY start)
+{
+    if (none_set())
+        return -1;
+
+    for (unsigned int days=0; days < 8; days++)
+    {
+        int check=start-days;
+        if (check < 0)
+            check+=7;
+        if (is_set(static_cast<WEEKDAY>(check)))
+            return days;
+    }
+
+    throw logic_error("can't find next weekday");
+
+    // fake
+    return -1;
+}
+
 std::string WEEK::get_daystring() const
 {
     ostringstream out;
index 8467af6..ddb86db 100644 (file)
@@ -76,6 +76,7 @@ class WEEK
             { return days.none(); }
 
         int days_till_set(WEEKDAY day);
+        int days_since_set(WEEKDAY day);
 
         std::string get_daystring() const;
         std::string get_displaystring() const;
index ca83ba0..cf6903d 100644 (file)
@@ -23,10 +23,23 @@ class TestCronFunc : public TestFixture
 {
     CPPUNIT_TEST_SUITE(TestCronFunc);
 
+    // Points in time
     CPPUNIT_TEST(NotYetToday);
     CPPUNIT_TEST(LaterToday);
+    CPPUNIT_TEST(Now);
     CPPUNIT_TEST(Tomorrow);
     CPPUNIT_TEST(NextWeek);
+    CPPUNIT_TEST(NextWeekFromToday);
+
+    // Intervals
+    CPPUNIT_TEST(IntervalBeginToday);
+    CPPUNIT_TEST(IntervalDoneToday);
+    CPPUNIT_TEST(IntervalBeginNow);
+    CPPUNIT_TEST(IntervalBeginStep);
+    CPPUNIT_TEST(IntervalWithin);
+    CPPUNIT_TEST(IntervalLaststep);
+    CPPUNIT_TEST(IntervalEnd);
+    CPPUNIT_TEST(IntervalBigstep);
 
     CPPUNIT_TEST_SUITE_END();
 
@@ -41,12 +54,22 @@ public:
     void tearDown()
     { }
 
+    /////////////////////////////////////////////////////
+    // Points in time
+    /////////////////////////////////////////////////////
+
     void NotYetToday()
     {
         WeekCron cron("2345",3600);
         CPPUNIT_ASSERT_EQUAL( 1233100800, static_cast<int>(cron.get_next_run(1233099657)));
     }
 
+    void Now()
+    {
+        WeekCron cron("2345",3600);
+        CPPUNIT_ASSERT_EQUAL( 1233187200, static_cast<int>(cron.get_next_run(1233100800)));
+    }
+
     void LaterToday()
     {
         WeekCron cron("2345",3600);
@@ -65,6 +88,64 @@ public:
         CPPUNIT_ASSERT_EQUAL( 1233532800, static_cast<int>(cron.get_next_run(1233099657)));
     }
 
+    void NextWeekFromToday()
+    {
+        WeekCron cron("13",3600);
+        CPPUNIT_ASSERT_EQUAL( 1233532800, static_cast<int>(cron.get_next_run(1233100801)));
+    }
+
+    /////////////////////////////////////////////////////
+    // Intervals
+    /////////////////////////////////////////////////////
+
+    void IntervalBeginToday()
+    {
+        WeekCron cron("2345",3600,7200,10);
+        CPPUNIT_ASSERT_EQUAL( 1233100800, static_cast<int>(cron.get_next_run(1233099657)));
+    }
+
+    void IntervalDoneToday()
+    {
+        WeekCron cron("2345",3600);
+        CPPUNIT_ASSERT_EQUAL( 1233187200, static_cast<int>(cron.get_next_run(1233150000)));
+    }
+
+    void IntervalBeginNow()
+    {
+        WeekCron cron("2345",3600,7200,10);
+        CPPUNIT_ASSERT_EQUAL( 1233100810, static_cast<int>(cron.get_next_run(1233100800)));
+    }
+
+    void IntervalBeginStep()
+    {
+        WeekCron cron("2345",3600,7200,10);
+        CPPUNIT_ASSERT_EQUAL( 1233100820, static_cast<int>(cron.get_next_run(1233100810)));
+    }
+
+    void IntervalWithin()
+    {
+        WeekCron cron("2345",3600,7200,10);
+        CPPUNIT_ASSERT_EQUAL( 1233100830, static_cast<int>(cron.get_next_run(1233100822)));
+    }
+
+    void IntervalLaststep()
+    {
+        WeekCron cron("2345",3600,7200,11);
+        CPPUNIT_ASSERT_EQUAL( 1233187200, static_cast<int>(cron.get_next_run(1233104399)));
+    }
+
+    void IntervalEnd()
+    {
+        WeekCron cron("2345",3600,7200,10);
+        CPPUNIT_ASSERT_EQUAL( 1233187200, static_cast<int>(cron.get_next_run(1233104400)));
+    }
+
+    void IntervalBigstep()
+    {
+        WeekCron cron("2345",3600,7200,10000);
+        CPPUNIT_ASSERT_EQUAL( 1233187200, static_cast<int>(cron.get_next_run(1233100800)));
+    }
+
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(TestCronFunc);