1 /* $XConsortium: relasttick.c /main/6 1996/11/21 19:46:04 drk $ */
3 * (c) Copyright 1993, 1994 Hewlett-Packard Company
4 * (c) Copyright 1993, 1994 International Business Machines Corp.
5 * (c) Copyright 1993, 1994 Novell, Inc.
6 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
9 #define XOS_USE_NO_LOCKING
10 #define X_INCLUDE_TIME_H
11 #include <X11/Xos_r.h>
18 static Tick DoMinute(const Tick, const RepeatEvent *);
19 static Tick DoDay(const Tick, const RepeatEvent *);
20 static Tick DoWeek(const Tick, RepeatEvent *);
21 static Tick DoMonthDay(const Tick, const RepeatEvent *);
22 static Tick DoMonthPos(const Tick, RepeatEvent *);
23 static Tick DoYearByMonth(const Tick, RepeatEvent *);
24 static Tick DoYearByDay(const Tick, RepeatEvent *);
25 static Tick LastOccurence(const Tick, const WeekDayTime *, const unsigned int);
26 static Tick LastTickFromEndDate(const Tick, const RepeatEvent *);
27 static int LastDayExists(const struct tm *, const unsigned int,
28 const unsigned int *);
29 extern void FillInRepeatEvent(const Tick, RepeatEvent *);
30 extern Tick ClosestTick(const Tick, const Tick, RepeatEvent *,
32 extern Tick PrevTick(const Tick, const Tick, RepeatEvent *, RepeatEventState *);
36 const Tick start_time,
41 if (!re) return (Tick)NULL;
43 if (re->re_duration == RE_INFINITY) return EOT;
45 FillInRepeatEvent(start_time, re);
47 switch (re->re_type) {
49 last_time = DoMinute(start_time, re);
52 last_time = DoDay(start_time, re);
55 last_time = DoWeek(start_time, re);
57 case RT_MONTHLY_POSITION:
58 last_time = DoMonthPos(start_time, re);
61 last_time = DoMonthDay(start_time, re);
64 last_time = DoYearByMonth(start_time, re);
67 last_time = DoYearByDay(start_time, re);
76 const Tick start_time,
77 const RepeatEvent *re)
84 const Tick start_time,
85 const RepeatEvent *re)
87 Tick last_time1 = EOT,
90 if (re->re_end_date) {
91 last_time1 = LastTickFromEndDate(start_time, re);
94 if (re->re_duration != RE_NOTSET) {
96 _Xltimeparams localtime_buf;
98 start_tm = _XLocaltime((const time_t *)&start_time, localtime_buf);
100 /* Go to the last day an event can happen on. */
101 start_tm->tm_mday += (re->re_duration - 1) * re->re_interval;
102 start_tm->tm_isdst = -1;
104 /* Go to the last time an event can happen on the last day. */
105 if (RE_DAILY(re)->dd_ntime) {
107 RE_DAILY(re)->dd_time[RE_DAILY(re)->dd_ntime - 1] / 100;
109 RE_DAILY(re)->dd_time[RE_DAILY(re)->dd_ntime - 1] % 100;
111 last_time2 = mktime(start_tm);
114 return ((last_time1 < last_time2) ? last_time1 : last_time2);
119 const Tick start_time,
123 unsigned int wd_ndaytime = RE_WEEKLY(re)->wd_ndaytime,
127 Tick _start_time = start_time,
130 RepeatEventState *res;
131 _Xltimeparams localtime_buf;
133 if (re->re_end_date) {
134 last_time1 = LastTickFromEndDate(start_time, re);
136 if (re->re_duration == RE_NOTSET)
140 /* Find the real start time */
141 _start_time = ClosestTick(start_time, start_time, re, &res);
143 start_tm = _XLocaltime((const time_t *)&_start_time, localtime_buf);
145 start_hour = start_tm->tm_hour;
146 start_min = start_tm->tm_min;
148 /* Go to the last day an event can happen on. */
149 start_tm->tm_mday += (re->re_duration - 1) * re->re_interval * 7;
150 start_tm->tm_isdst = -1;
153 _start_time = mktime(start_tm);
154 start_tm = _XLocaltime((const time_t *)&_start_time, localtime_buf);
156 /* Normalize to the beginning of the week */
157 start_tm->tm_mday -= start_tm->tm_wday;
158 start_tm->tm_sec = start_tm->tm_min = start_tm->tm_hour = 0;
159 start_tm->tm_isdst = -1;
160 _start_time = mktime(start_tm);
161 start_tm = _XLocaltime((const time_t *)&_start_time, localtime_buf);
163 /* Move forward to the proper week day */
165 RE_WEEKLY(re)->wd_daytime[wd_ndaytime - 1].dt_day;
167 dt_ntime = RE_WEEKLY(re)->wd_daytime[wd_ndaytime - 1].dt_ntime;
169 /* Set the proper time */
171 start_tm->tm_hour = RE_WEEKLY(re)->
172 wd_daytime[wd_ndaytime - 1].dt_time[dt_ntime - 1]
174 start_tm->tm_min = RE_WEEKLY(re)->
175 wd_daytime[wd_ndaytime - 1].dt_time[dt_ntime - 1]
178 start_tm->tm_hour = start_hour;
179 start_tm->tm_min = start_min;
183 start_tm->tm_isdst = -1;
184 last_time2 = mktime(start_tm);
186 return ((last_time1 < last_time2) ? last_time1 : last_time2);
191 const Tick start_time,
192 const RepeatEvent *re)
196 unsigned int md_nitems = RE_MONTHLY(re)->md_nitems,
197 *md_days = RE_MONTHLY(re)->md_days,
202 _Xltimeparams localtime_buf;
204 if (re->re_end_date) {
205 last_time1 = LastTickFromEndDate(start_time, re);
207 if (re->re_duration == RE_NOTSET)
211 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
212 cur_tm = _XLocaltime((const time_t *)&start_time, localtime_buf);
213 start_tm.tm_isdst = -1;
215 /* The 28th - 31st may not exist in a given month thus if only these
216 * days are specified in a rule it is necessary to calculate the
217 * correct month by brute force versus as a mathimatical calculation.
219 if (md_days[0] > 28) {
222 /* Compute last event by brute force */
224 cur_tm->tm_mon += re->re_interval;
225 cur_tm->tm_isdst = -1;
226 cur_time = mktime(cur_tm);
227 cur_tm = _XLocaltime((const time_t *)&cur_time, localtime_buf);
230 DayOfMonth(md_days[0], cur_tm->tm_mon,
232 cur_tm->tm_mon, cur_tm->tm_year))
234 } while (interval < re->re_duration);
236 start_tm.tm_mon = cur_tm->tm_mon;
237 start_tm.tm_year = cur_tm->tm_year;
238 start_tm.tm_mday = LastDayExists(cur_tm, md_nitems, md_days);
240 } else if (md_nitems) {
241 start_tm.tm_mon += (re->re_duration - 1) * re->re_interval;
242 start_tm.tm_mday = 1;
243 /* Have the year and month updated */
244 cur_time = mktime(&start_tm);
245 start_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
246 /* Get the right day (LASTDAY converted to a real day) */
247 start_tm.tm_isdst = -1;
248 start_tm.tm_mday = DayOfMonth(
249 md_days[md_nitems - 1],
250 start_tm.tm_mon, start_tm.tm_year);
252 start_tm.tm_mon += (re->re_duration - 1) * re->re_interval;
254 last_time2 = mktime(&start_tm);
255 return ((last_time1 < last_time2) ? last_time1 : last_time2);
260 const Tick _start_time,
265 Tick last_time1 = EOT,
267 start_time = _start_time;
268 unsigned int nwdt_list = RE_MONTHLY(re)->md_nitems,
272 WeekDayTime *wdt_list = RE_MONTHLY(re)->md_weektime;
273 RepeatEventState *res;
274 _Xltimeparams localtime_buf;
276 if (re->re_end_date) {
277 last_time1 = LastTickFromEndDate(start_time, re);
279 if (re->re_duration == RE_NOTSET)
283 /* Find the real start time */
284 start_time = ClosestTick(start_time, start_time, re, &res);
286 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
288 for (i = 0; i < nwdt_list; i++) {
289 for (j = 0; j < wdt_list[i].wdt_nweek; j++) {
290 if ((wdt_list[i].wdt_week[j] != WK_F5) &&
291 (wdt_list[i].wdt_week[j] != WK_L5)) {
296 if (brute_force == FALSE) break;
303 while (num_intervals < re->re_duration) {
304 cur_tm.tm_mon += re->re_interval;
305 cur_tm.tm_isdst = -1;
306 last_time2 = mktime(&cur_tm);
307 cur_tm = *_XLocaltime((const time_t *)&last_time2,
310 if (OccurenceExists(wdt_list, nwdt_list, last_time2))
313 if (!InTimeRange(num_intervals, re->re_duration))
317 start_tm.tm_mon += (re->re_duration - 1) * re->re_interval;
318 start_tm.tm_isdst = -1;
319 start_tm.tm_mday = 1;
320 last_time2 = mktime(&start_tm);
324 * Given the occurence information, find the last valid day in the
327 last_time2 = LastOccurence(last_time2, wdt_list, nwdt_list);
329 return ((last_time1 < last_time2) ? last_time1 : last_time2);
334 const Tick start_time,
342 RepeatEventState *res;
343 _Xltimeparams localtime_buf;
345 if (re->re_end_date) {
346 last_time1 = LastTickFromEndDate(start_time, re);
348 if (re->re_duration == RE_NOTSET)
352 /* Find the real start time */
353 _start_time = ClosestTick(start_time, start_time, re, &res);
355 start_tm = _XLocaltime((const time_t *)&_start_time, localtime_buf);
356 start_day = start_tm->tm_mday;
358 /* Go to the last day an event can happen on. */
359 start_tm->tm_year += (re->re_duration - 1) * re->re_interval;
360 start_tm->tm_isdst = -1;
362 /* XXX: If the only month used is Feb and the date is the 29th, then
363 * we must use a special case.
366 /* Go to the last time an event can happen on on the last month. */
367 if (RE_YEARLY(re)->yd_nitems) {
370 _start_time = mktime(start_tm);
371 start_tm = _XLocaltime((const time_t *)&_start_time, localtime_buf);
373 for (i = RE_YEARLY(re)->yd_nitems - 1; i >= 0; i++) {
374 if (DayExists(start_day, RE_YEARLY(re)->yd_items[i],
375 start_tm->tm_year)) {
376 start_tm->tm_mon = RE_YEARLY(re)->yd_items[i]-1;
377 start_tm->tm_isdst = -1;
378 return (mktime(start_tm));
381 /* No months have a day that can be used */
385 last_time2 = mktime(start_tm);
386 return ((last_time1 < last_time2) ? last_time1 : last_time2);
391 const Tick start_time,
399 RepeatEventState *res;
400 _Xltimeparams localtime_buf;
402 if (re->re_end_date) {
403 last_time1 = LastTickFromEndDate(start_time, re);
405 if (re->re_duration == RE_NOTSET)
409 /* Find the real start time */
410 _start_time = ClosestTick(start_time, start_time, re, &res);
412 start_tm = _XLocaltime((const time_t *)&_start_time, localtime_buf);
414 /* Go to the last year an event can happen on. */
415 start_tm->tm_year += (re->re_duration - 1) * re->re_interval;
416 start_tm->tm_isdst = -1;
418 /* Go to the last time an event can happen on. */
419 if (RE_YEARLY(re)->yd_nitems) {
420 start_tm->tm_mon = 0;
422 RE_YEARLY(re)->yd_items[RE_YEARLY(re)->yd_nitems - 1];
425 last_time2 = mktime(start_tm);
426 return ((last_time1 < last_time2) ? last_time1 : last_time2);
430 * Given a month/year (from cur_tm), and a list of days of the month
431 * determine the last day in that list that is valid in that month.
435 const struct tm *cur_tm,
436 const unsigned int md_nitems,
437 const unsigned int *md_days)
442 for (i = md_nitems - 1; i >= 0; i--) {
443 day = DayOfMonth(md_days[i], cur_tm->tm_mon, cur_tm->tm_year);
444 if (DayExists(day, cur_tm->tm_mon, cur_tm->tm_year))
452 * Given a month/year (in cur_time) determine the last occurence of week/day/
458 const WeekDayTime *wdt_list,
459 const unsigned int nwdt_list)
462 Tick oldest_time = 0,
465 for (i = 0; i < nwdt_list; i++) {
466 for (j = 0; j < wdt_list[i].wdt_nweek; j++) {
467 for (k = 0; k < wdt_list[i].wdt_nday; k++) {
468 if (current_time = WeekNumberToDay(cur_time,
469 wdt_list[i].wdt_week[j],
470 wdt_list[i].wdt_day[k])) {
471 if (current_time > oldest_time)
472 oldest_time = current_time;
483 * Given a time and a rule find the last tick before the end date.
488 const RepeatEvent *re)
490 RepeatEventState *res;
491 RepeatEvent *_re = (RepeatEvent *)re;
492 Tick end_date = re->re_end_date,
494 Duration duration = re->re_duration;
496 /* Take the end date out of the equation. */
497 _re->re_end_date = 0;
498 _re->re_duration = RE_INFINITY;
500 /* Use the end date to get the closest tick after it, then
501 * step back one tick to get the last tick before the
504 last_time = ClosestTick(end_date, cur_time, _re, &res);
506 * An event that occurs at the same time as the end_date is an
509 if (last_time != end_date)
510 last_time = PrevTick(last_time, cur_time, _re, res);
512 /* Return the re to its original state. */
513 _re->re_end_date = end_date;
514 _re->re_duration = duration;