2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
10 # | Copyright Mathias Kettner 2016 mk@mathias-kettner.de |
11 # +------------------------------------------------------------------+
13 # This file is part of Check_MK.
14 # The official homepage is at http://mathias-kettner.de/check_mk.
16 # check_mk is free software; you can redistribute it and/or modify it
17 # under the terms of the GNU General Public License as published by
18 # the Free Software Foundation in version 2. check_mk is distributed
19 # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
20 # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
21 # PARTICULAR PURPOSE. See the GNU General Public License for more de-
22 # tails. You should have received a copy of the GNU General Public
23 # License along with GNU Make; see the file COPYING. If not, write
24 # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 # Boston, MA 02110-1301 USA.
27 # Computes for a scheduling entry the last/next time that this entry
28 # should have run or will be run. Such a scheduling entry is specified
29 # by a period specification as produced by the SchedulePeriod() valuespec
30 # and a timeofday specification which is a two element tuple of hours and minutes
36 from dateutil
.relativedelta
import relativedelta
37 from dateutil
.rrule
import rrule
, DAILY
, WEEKLY
, MONTHLY
40 class Schedule(object):
42 Abstract base class for schedules. A default implementation
43 for the last and next event at a given datetime are provided.
44 Subclasses have to define the class attribute _delta and the
45 instance attribute _rule.
47 __metaclass__
= abc
.ABCMeta
58 return self
.rule
.replace(dtstart
=t
).after(t
)
61 from_
= t
+ relativedelta(**self
.delta
)
62 return self
.rule
.replace(dtstart
=from_
, until
=t
).before(t
)
65 class DaySchedule(Schedule
):
70 def __init__(self
, timeofday
):
71 self
._rule
= rrule(DAILY
, byhour
=timeofday
.hour
, byminute
=timeofday
.minute
, bysecond
=0)
82 class WeekSchedule(Schedule
):
87 def __init__(self
, weekday
, timeofday
):
88 if not 0 <= weekday
<= 6:
89 raise ValueError('weekday must be between 0 and 6')
91 WEEKLY
, byweekday
=weekday
, byhour
=timeofday
.hour
, byminute
=timeofday
.minute
, bysecond
=0)
102 class StartMonthSchedule(Schedule
):
104 A monthly schedule initialized relatively to the first day of the month.
107 def __init__(self
, day
, timeofday
):
108 if not 1 <= day
<= 31:
109 raise ValueError('day must be between 1 and 31')
111 MONTHLY
, bymonthday
=day
, byhour
=timeofday
.hour
, byminute
=timeofday
.minute
, bysecond
=0)
119 return {"months": -2}
122 class EndMonthSchedule(Schedule
):
124 A monthly schedule initialized relatively to the last day of the month.
127 def __init__(self
, days_from_end
, timeofday
):
128 if not 1 <= days_from_end
<= 31:
129 raise ValueError('days_from_end must be between 1 and 31')
132 MONTHLY
, bymonthday
=day
, byhour
=timeofday
.hour
, byminute
=timeofday
.minute
, bysecond
=0)
140 return {"months": -2}
143 def _get_schedule(period
, timeofday
):
145 Returns a schedule instance for a given period and timeofday.
147 t
= datetime
.time(*timeofday
)
150 schedule
= DaySchedule(t
)
151 elif period
[0] == "week":
153 schedule
= WeekSchedule(weekday
, t
)
154 elif period
[0] == "month_begin":
156 schedule
= StartMonthSchedule(day
, t
)
157 elif period
[0] == "month_end":
158 days_from_end
= period
[1]
159 schedule
= EndMonthSchedule(days_from_end
, t
)
161 raise ValueError('Unknown period')
166 def last_scheduled_time(period
, timeofday
, dt
=None):
168 dt
= datetime
.datetime
.today()
169 schedule
= _get_schedule(period
, timeofday
)
170 return time
.mktime(schedule
.last(dt
).timetuple())
173 def next_scheduled_time(period
, timeofday
, dt
=None):
175 dt
= datetime
.datetime
.today()
176 schedule
= _get_schedule(period
, timeofday
)
177 return time
.mktime(schedule
.next(dt
).timetuple())