#include <cron.hpp>
+/**
+ @brief checks if the values are usable
+*/
bool WeekCron::is_sane()
{
if (begin < 0 || begin > 86399)
if (every != -1)
{
if (end < 0 || end > 86399 ||
- every < 0 || every > 86399 ||
+ every < 1 || every > 86399 ||
begin > end)
return false;
}
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)
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);
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;
+}
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:
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;
{ 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;
{
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();
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);
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);