Replace inet_aton() with inet_pton() to parse IPs correctly (#8825)
[libi2ncommon] / src / cron.cpp
... / ...
CommitLineData
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
20/** @file
21 * @brief repeating time-points and intervals
22 *
23 * @copyright Copyright © 2009 by Intra2net AG
24 *
25 */
26#include <time.h>
27#include <limits.h>
28#include <stdexcept>
29#include <iostream>
30
31#include <cron.hpp>
32
33namespace I2n {
34namespace Time {
35
36const time_t WeekCron::StNimmerleinsDay = static_cast<time_t>(INT_MAX);
37
38/**
39 * Constructor, leaves object in invalid state
40 */
41WeekCron::WeekCron()
42 : Begin(-1)
43 , End(0)
44 , Every(-1)
45 , Week()
46{
47}
48
49/**
50 * Constructor
51 * @param daystring String representing the active weekdays as numbers. 0 is Sunday.
52 * @param begin Start point of time in seconds since the start of the day
53 */
54WeekCron::WeekCron(const std::string& daystring, const int begin)
55 : Begin(begin)
56 , End(0)
57 , Every(-1)
58 , Week(daystring)
59{
60}
61
62/**
63 * Constructor
64 * @param daystring String representing the active weekdays as numbers. 0 is Sunday.
65 * @param begin Start point of time in seconds since the start of the day
66 * @param end End point of time in seconds since the start of the day. Only used when every != -1
67 * @param every Repeat event every xxx seconds in the half-open interval of begin and end. -1 is disabled
68 */
69WeekCron::WeekCron(const std::string& daystring, const int begin, const int end, const int every)
70 : Begin(begin)
71 , End(end)
72 , Every(every)
73 , Week(daystring)
74{
75}
76
77/**
78 * Constructor
79 * @param week I2n::Time::Week object representing the active days
80 * @param begin Start point of time in seconds since the start of the day
81 */
82WeekCron::WeekCron(const I2n::Time::Week& week, const int begin)
83 : Begin(begin)
84 , End(0)
85 , Every(-1)
86 , Week(week)
87{
88}
89
90/**
91 * Constructor
92 * @param week I2n::Time::Week object representing the active days
93 * @param begin Start point of time in seconds since the start of the day
94 * @param end End point of time in seconds since the start of the day. Only used when every != -1
95 * @param every Repeat event every xxx seconds in the half-open interval of begin and end. -1 is disabled
96 */
97WeekCron::WeekCron(const I2n::Time::Week& week, const int begin, const int end, const int every)
98 : Begin(begin)
99 , End(end)
100 , Every(every)
101 , Week(week)
102{
103}
104
105/**
106 * Checks if the input values are sane
107 * @return True if sane, false otherweise
108 */
109bool WeekCron::is_sane() const
110{
111 if (Begin < 0 || Begin > 86399)
112 return false;
113
114 if (Every != -1)
115 {
116 if (End < 0 || End > 86400 ||
117 Every < 1 || Every > 86400 ||
118 Begin > End)
119 return false;
120 }
121
122 return true;
123}
124
125/**
126 * Returns the next point in time the item is scheduled for.
127 * Handles the full possibilities of WeekCron.
128 * @note if it is scheduled for calc_from we return the next schedule, not now!
129 * @param calc_from unix-time to start calculating from (0 means now)
130 * @return Next point in time the item is scheduled for
131 * returns constant #StNimmerleinsDay if it is scheduled never
132 */
133time_t WeekCron::get_next_run(time_t calc_from) const
134{
135 if (!calc_from)
136 calc_from=time(NULL);
137
138 if (!is_sane())
139 throw std::runtime_error("illegal cron value");
140
141 if (calc_from <= 86400*14)
142 throw std::runtime_error("WeekCron doesn't work for timestamps near 0");
143
144 if (Week.none_set())
145 return StNimmerleinsDay;
146
147 if (Every == -1)
148 {
149 // point in time
150 return get_next_point(calc_from,Begin,true);
151 }
152 else
153 {
154 // interval
155 time_t next_begin = get_next_point(calc_from,Begin,true);
156 if (next_begin > get_next_point(calc_from,End-1,true))
157 {
158 // next begin > next end means we are at the begin or within the interval
159
160 time_t interval_begin=get_previousnow_point(calc_from,Begin,true);
161
162 time_t within_interval=calc_from - interval_begin;
163 time_t since_lastrun=within_interval % Every;
164 time_t next_exec=calc_from+(Every-since_lastrun);
165
166 // next step at or after end?
167 if (next_exec > get_next_point(calc_from,End-1,true))
168 return get_next_point(calc_from,Begin,true);
169 else
170 return next_exec;
171 }
172 else
173 {
174 // next begin < next end means we are out of the interval: next begin is next run
175 return next_begin;
176 }
177 }
178}
179
180/**
181 * Returns the next point in time the item is scheduled for. Does not care about intervals.
182 * Returns next point if scheduled for @a calc_from.
183 * @param calc_from Point of time to start calculations from
184 * @param daysec Start point of time in seconds since the start of the day
185 * @param todaycheck If true we check if the calculated time point is before
186 our @a calc_from calcucation start point.
187 If yes, we will advance to the next day.
188 * @return Next point in time
189 */
190time_t WeekCron::get_next_point(const time_t calc_from, const int daysec, const bool todaycheck) const
191{
192 struct tm ft;
193 if (localtime_r(&calc_from,&ft) == NULL)
194 return calc_from;
195
196 // take care of the weekday
197 ft.tm_mday+=Week.days_till_set(static_cast<Week::WeekDay>(ft.tm_wday)); //lint !e737 !e713
198
199 fill_tm_with_wallclock(&ft,daysec);
200
201 // tm_isdst means to use the dst in use at the given time
202 ft.tm_isdst=-1;
203
204 time_t target=mktime(&ft);
205
206 // check for completely illegal time, should not happen without bug in this func,
207 // return calc_from as safeguard
208 if (target == (time_t)-1)
209 return calc_from;
210
211 // todays schedule could already been through or now
212 if (todaycheck && target <= calc_from)
213 {
214 // not today but the next matching weekday
215 ft.tm_mday++;
216 ft.tm_isdst=-1;
217 target=get_next_point(mktime(&ft),daysec,false);
218 }
219
220 return target;
221}
222
223/**
224 * Returns the previous or current point in time the item was scheduled for.
225 * Does not care about intervals.
226 * Returns @a calc_from if scheduled for @a calc_from.
227 * @param calc_from Point of time to start calculations from
228 * @param daysec Start point of time in seconds since the start of the day
229 * @param todaycheck If true we check if the calculated time point is after
230 our @a calc_from calcucation start point.
231 If yes, we will go back to the previos day
232 * @return Previous point in time
233 */
234time_t WeekCron::get_previousnow_point(const time_t calc_from, const int daysec, const bool todaycheck) const
235{
236 struct tm ft;
237 if (localtime_r(&calc_from,&ft) == NULL)
238 return calc_from;
239
240 // take care of the weekday
241 ft.tm_mday-=Week.days_since_set(static_cast<Week::WeekDay>(ft.tm_wday)); //lint !e737 !e713
242
243 fill_tm_with_wallclock(&ft,daysec);
244
245 // tm_isdst means to use the dst in use at the given time
246 ft.tm_isdst=-1;
247
248 time_t target=mktime(&ft);
249
250 // check for completely illegal time, should not happen without bug in this func,
251 // return calc_from as safeguard
252 if (target == (time_t)-1)
253 return calc_from;
254
255 // target later than we are looking for
256 // target==calc_from is ok (that's why it is called lastnow...)
257 if (todaycheck && target > calc_from)
258 {
259 // not today but the previous matching weekday
260 ft.tm_mday--;
261 ft.tm_isdst=-1;
262 target=get_previousnow_point(mktime(&ft),daysec,false);
263 }
264
265 return target;
266}
267
268/**
269 * Converts @a daysec into hour/minute/second and fills it into the provided struct tm
270 * @param ft struct tm to fill wallclock time into
271 * @param daysec Start point of time in seconds since the start of the day
272 */
273void WeekCron::fill_tm_with_wallclock(struct tm *ft, const int daysec) const
274{
275 int remain=daysec;
276
277 ft->tm_hour=remain/3600;
278 remain-=ft->tm_hour*3600;
279
280 ft->tm_min=remain/60;
281 remain-=ft->tm_min*60;
282
283 ft->tm_sec=remain;
284}
285
286}
287}