Rename get_dir_size() to get_dir_count()
[libi2ncommon] / src / cron.cpp
CommitLineData
0e23f538
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
1720acee 4
0e23f538
TJ
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*/
1720acee
GE
20/** @file
21 * @brief repeating time-points and intervals
22 *
23 * @copyright Copyright © 2009 by Intra2net AG
1720acee
GE
24 *
25 */
26#include <time.h>
55661be5 27#include <limits.h>
1720acee 28#include <stdexcept>
300d1c09 29#include <iostream>
1720acee
GE
30
31#include <cron.hpp>
32
0c7e72d7
TJ
33namespace I2n {
34namespace Time {
fd6d9c59 35
55661be5 36const time_t WeekCron::StNimmerleinsDay = static_cast<time_t>(INT_MAX);
3d73a872 37
882ecfd7 38/**
ab205aa3
GE
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/**
249bd63f
TJ
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 */
fd6d9c59 54WeekCron::WeekCron(const std::string& daystring, const int begin)
249bd63f
TJ
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 */
fd6d9c59 69WeekCron::WeekCron(const std::string& daystring, const int begin, const int end, const int every)
249bd63f
TJ
70 : Begin(begin)
71 , End(end)
72 , Every(every)
73 , Week(daystring)
74{
75}
76
ab205aa3
GE
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}
249bd63f
TJ
104
105/**
106 * Checks if the input values are sane
107 * @return True if sane, false otherweise
108 */
5774a519 109bool WeekCron::is_sane() const
1720acee 110{
5774a519 111 if (Begin < 0 || Begin > 86399)
1720acee
GE
112 return false;
113
5774a519 114 if (Every != -1)
1720acee 115 {
5774a519
TJ
116 if (End < 0 || End > 86400 ||
117 Every < 1 || Every > 86400 ||
118 Begin > End)
1720acee
GE
119 return false;
120 }
121
122 return true;
123}
124
882ecfd7 125/**
3d73a872
TJ
126 * Returns the next point in time the item is scheduled for.
127 * Handles the full possibilities of WeekCron.
249bd63f
TJ
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
3d73a872 131 * returns constant #StNimmerleinsDay if it is scheduled never
249bd63f 132 */
dfbe7ca9 133time_t WeekCron::get_next_run(time_t calc_from) const
1720acee
GE
134{
135 if (!calc_from)
136 calc_from=time(NULL);
137
138 if (!is_sane())
139 throw std::runtime_error("illegal cron value");
140
8de7c371 141 if (calc_from <= 86400*14)
fd6d9c59 142 throw std::runtime_error("WeekCron doesn't work for timestamps near 0");
1720acee 143
5774a519 144 if (Week.none_set())
3d73a872 145 return StNimmerleinsDay;
1720acee 146
5774a519 147 if (Every == -1)
1720acee
GE
148 {
149 // point in time
5774a519 150 return get_next_point(calc_from,Begin,true);
1720acee
GE
151 }
152 else
153 {
154 // interval
fd6d9c59
TJ
155 time_t next_begin = get_next_point(calc_from,Begin,true);
156 if (next_begin > get_next_point(calc_from,End-1,true))
882ecfd7
GE
157 {
158 // next begin > next end means we are at the begin or within the interval
159
d70ccb7a 160 time_t interval_begin=get_previousnow_point(calc_from,Begin,true);
882ecfd7
GE
161
162 time_t within_interval=calc_from - interval_begin;
5774a519
TJ
163 time_t since_lastrun=within_interval % Every;
164 time_t next_exec=calc_from+(Every-since_lastrun);
882ecfd7 165
8de7c371 166 // next step at or after end?
78b3ba9d 167 if (next_exec > get_next_point(calc_from,End-1,true))
5774a519 168 return get_next_point(calc_from,Begin,true);
882ecfd7
GE
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
fd6d9c59 175 return next_begin;
882ecfd7 176 }
1720acee
GE
177 }
178}
179
249bd63f 180/**
3d73a872 181 * Returns the next point in time the item is scheduled for. Does not care about intervals.
3438e43a 182 * Returns next point if scheduled for @a calc_from.
249bd63f
TJ
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
3438e43a 186 our @a calc_from calcucation start point.
249bd63f
TJ
187 If yes, we will advance to the next day.
188 * @return Next point in time
189 */
dfbe7ca9 190time_t WeekCron::get_next_point(const time_t calc_from, const int daysec, const bool todaycheck) const
1720acee
GE
191{
192 struct tm ft;
dfbe7ca9
TJ
193 if (localtime_r(&calc_from,&ft) == NULL)
194 return calc_from;
1720acee
GE
195
196 // take care of the weekday
dfbe7ca9 197 ft.tm_mday+=Week.days_till_set(static_cast<Week::WeekDay>(ft.tm_wday)); //lint !e737 !e713
1720acee 198
300d1c09
GE
199 fill_tm_with_wallclock(&ft,daysec);
200
f60e4880
GE
201 // tm_isdst means to use the dst in use at the given time
202 ft.tm_isdst=-1;
1720acee 203
300d1c09
GE
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
dfbe7ca9
TJ
208 if (target == (time_t)-1)
209 return calc_from;
1720acee 210
882ecfd7
GE
211 // todays schedule could already been through or now
212 if (todaycheck && target <= calc_from)
1720acee 213 {
882ecfd7 214 // not today but the next matching weekday
1720acee 215 ft.tm_mday++;
f60e4880
GE
216 ft.tm_isdst=-1;
217 target=get_next_point(mktime(&ft),daysec,false);
1720acee
GE
218 }
219
220 return target;
221}
222
249bd63f 223/**
d70ccb7a 224 * Returns the previous or current point in time the item was scheduled for.
3d73a872 225 * Does not care about intervals.
3438e43a 226 * Returns @a calc_from if scheduled for @a calc_from.
249bd63f
TJ
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
d70ccb7a 229 * @param todaycheck If true we check if the calculated time point is after
3438e43a 230 our @a calc_from calcucation start point.
d70ccb7a
TJ
231 If yes, we will go back to the previos day
232 * @return Previous point in time
249bd63f 233 */
dfbe7ca9 234time_t WeekCron::get_previousnow_point(const time_t calc_from, const int daysec, const bool todaycheck) const
882ecfd7
GE
235{
236 struct tm ft;
dfbe7ca9
TJ
237 if (localtime_r(&calc_from,&ft) == NULL)
238 return calc_from;
882ecfd7
GE
239
240 // take care of the weekday
dfbe7ca9 241 ft.tm_mday-=Week.days_since_set(static_cast<Week::WeekDay>(ft.tm_wday)); //lint !e737 !e713
882ecfd7 242
300d1c09
GE
243 fill_tm_with_wallclock(&ft,daysec);
244
245 // tm_isdst means to use the dst in use at the given time
f60e4880 246 ft.tm_isdst=-1;
882ecfd7 247
300d1c09
GE
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
dfbe7ca9
TJ
252 if (target == (time_t)-1)
253 return calc_from;
882ecfd7
GE
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 {
f60e4880 259 // not today but the previous matching weekday
882ecfd7 260 ft.tm_mday--;
f60e4880
GE
261 ft.tm_isdst=-1;
262 target=get_previousnow_point(mktime(&ft),daysec,false);
882ecfd7
GE
263 }
264
265 return target;
266}
fd6d9c59 267
300d1c09 268/**
3438e43a 269 * Converts @a daysec into hour/minute/second and fills it into the provided struct tm
300d1c09
GE
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
0c7e72d7
TJ
286}
287}