From: Gerd v. Egidy Date: Wed, 28 Jan 2009 01:32:17 +0000 (+0100) Subject: scheduling class can do intervals now, some fixes X-Git-Tag: v2.6~136^2~24 X-Git-Url: http://developer.intra2net.com/git/?a=commitdiff_plain;h=882ecfd71740e07032503391ba532d96593da3a1;p=libi2ncommon scheduling class can do intervals now, some fixes --- diff --git a/src/cron.cpp b/src/cron.cpp index f3103bf..c85c680 100644 --- a/src/cron.cpp +++ b/src/cron.cpp @@ -13,6 +13,9 @@ #include +/** + @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(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; +} diff --git a/src/cron.hpp b/src/cron.hpp index 26e67f4..41cd418 100644 --- a/src/cron.hpp +++ b/src/cron.hpp @@ -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: diff --git a/src/timefunc.cpp b/src/timefunc.cpp index f66e61b..56bfcc8 100644 --- a/src/timefunc.cpp +++ b/src/timefunc.cpp @@ -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(check))) + return days; + } + + throw logic_error("can't find next weekday"); + + // fake + return -1; +} + std::string WEEK::get_daystring() const { ostringstream out; diff --git a/src/timefunc.hxx b/src/timefunc.hxx index 8467af6..ddb86db 100644 --- a/src/timefunc.hxx +++ b/src/timefunc.hxx @@ -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; diff --git a/test/test_cron.cpp b/test/test_cron.cpp index ca83ba0..cf6903d 100644 --- a/test/test_cron.cpp +++ b/test/test_cron.cpp @@ -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(cron.get_next_run(1233099657))); } + void Now() + { + WeekCron cron("2345",3600); + CPPUNIT_ASSERT_EQUAL( 1233187200, static_cast(cron.get_next_run(1233100800))); + } + void LaterToday() { WeekCron cron("2345",3600); @@ -65,6 +88,64 @@ public: CPPUNIT_ASSERT_EQUAL( 1233532800, static_cast(cron.get_next_run(1233099657))); } + void NextWeekFromToday() + { + WeekCron cron("13",3600); + CPPUNIT_ASSERT_EQUAL( 1233532800, static_cast(cron.get_next_run(1233100801))); + } + + ///////////////////////////////////////////////////// + // Intervals + ///////////////////////////////////////////////////// + + void IntervalBeginToday() + { + WeekCron cron("2345",3600,7200,10); + CPPUNIT_ASSERT_EQUAL( 1233100800, static_cast(cron.get_next_run(1233099657))); + } + + void IntervalDoneToday() + { + WeekCron cron("2345",3600); + CPPUNIT_ASSERT_EQUAL( 1233187200, static_cast(cron.get_next_run(1233150000))); + } + + void IntervalBeginNow() + { + WeekCron cron("2345",3600,7200,10); + CPPUNIT_ASSERT_EQUAL( 1233100810, static_cast(cron.get_next_run(1233100800))); + } + + void IntervalBeginStep() + { + WeekCron cron("2345",3600,7200,10); + CPPUNIT_ASSERT_EQUAL( 1233100820, static_cast(cron.get_next_run(1233100810))); + } + + void IntervalWithin() + { + WeekCron cron("2345",3600,7200,10); + CPPUNIT_ASSERT_EQUAL( 1233100830, static_cast(cron.get_next_run(1233100822))); + } + + void IntervalLaststep() + { + WeekCron cron("2345",3600,7200,11); + CPPUNIT_ASSERT_EQUAL( 1233187200, static_cast(cron.get_next_run(1233104399))); + } + + void IntervalEnd() + { + WeekCron cron("2345",3600,7200,10); + CPPUNIT_ASSERT_EQUAL( 1233187200, static_cast(cron.get_next_run(1233104400))); + } + + void IntervalBigstep() + { + WeekCron cron("2345",3600,7200,10000); + CPPUNIT_ASSERT_EQUAL( 1233187200, static_cast(cron.get_next_run(1233100800))); + } + }; CPPUNIT_TEST_SUITE_REGISTRATION(TestCronFunc);