2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: relasttick.c /main/6 1996/11/21 19:46:04 drk $ */
25 * (c) Copyright 1993, 1994 Hewlett-Packard Company
26 * (c) Copyright 1993, 1994 International Business Machines Corp.
27 * (c) Copyright 1993, 1994 Novell, Inc.
28 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
31 #define XOS_USE_NO_LOCKING
32 #define X_INCLUDE_TIME_H
33 #include <X11/Xos_r.h>
40 static Tick DoMinute(const Tick, const RepeatEvent *);
41 static Tick DoDay(const Tick, const RepeatEvent *);
42 static Tick DoWeek(const Tick, RepeatEvent *);
43 static Tick DoMonthDay(const Tick, const RepeatEvent *);
44 static Tick DoMonthPos(const Tick, RepeatEvent *);
45 static Tick DoYearByMonth(const Tick, RepeatEvent *);
46 static Tick DoYearByDay(const Tick, RepeatEvent *);
47 static Tick LastOccurence(const Tick, const WeekDayTime *, const unsigned int);
48 static Tick LastTickFromEndDate(const Tick, const RepeatEvent *);
49 static int LastDayExists(const struct tm *, const unsigned int,
50 const unsigned int *);
51 extern void FillInRepeatEvent(const Tick, RepeatEvent *);
52 extern Tick ClosestTick(const Tick, const Tick, RepeatEvent *,
54 extern Tick PrevTick(const Tick, const Tick, RepeatEvent *, RepeatEventState *);
58 const Tick start_time,
63 if (!re) return (Tick)NULL;
65 if (re->re_duration == RE_INFINITY) return EOT;
67 FillInRepeatEvent(start_time, re);
69 switch (re->re_type) {
71 last_time = DoMinute(start_time, re);
74 last_time = DoDay(start_time, re);
77 last_time = DoWeek(start_time, re);
79 case RT_MONTHLY_POSITION:
80 last_time = DoMonthPos(start_time, re);
83 last_time = DoMonthDay(start_time, re);
86 last_time = DoYearByMonth(start_time, re);
89 last_time = DoYearByDay(start_time, re);
98 const Tick start_time,
99 const RepeatEvent *re)
106 const Tick start_time,
107 const RepeatEvent *re)
109 Tick last_time1 = EOT,
112 if (re->re_end_date) {
113 last_time1 = LastTickFromEndDate(start_time, re);
116 if (re->re_duration != RE_NOTSET) {
118 _Xltimeparams localtime_buf;
120 start_tm = _XLocaltime((const time_t *)&start_time, localtime_buf);
122 /* Go to the last day an event can happen on. */
123 start_tm->tm_mday += (re->re_duration - 1) * re->re_interval;
124 start_tm->tm_isdst = -1;
126 /* Go to the last time an event can happen on the last day. */
127 if (RE_DAILY(re)->dd_ntime) {
129 RE_DAILY(re)->dd_time[RE_DAILY(re)->dd_ntime - 1] / 100;
131 RE_DAILY(re)->dd_time[RE_DAILY(re)->dd_ntime - 1] % 100;
133 last_time2 = mktime(start_tm);
136 return ((last_time1 < last_time2) ? last_time1 : last_time2);
141 const Tick start_time,
145 unsigned int wd_ndaytime = RE_WEEKLY(re)->wd_ndaytime,
149 Tick _start_time = start_time,
152 RepeatEventState *res;
153 _Xltimeparams localtime_buf;
155 if (re->re_end_date) {
156 last_time1 = LastTickFromEndDate(start_time, re);
158 if (re->re_duration == RE_NOTSET)
162 /* Find the real start time */
163 _start_time = ClosestTick(start_time, start_time, re, &res);
165 start_tm = _XLocaltime((const time_t *)&_start_time, localtime_buf);
167 start_hour = start_tm->tm_hour;
168 start_min = start_tm->tm_min;
170 /* Go to the last day an event can happen on. */
171 start_tm->tm_mday += (re->re_duration - 1) * re->re_interval * 7;
172 start_tm->tm_isdst = -1;
175 _start_time = mktime(start_tm);
176 start_tm = _XLocaltime((const time_t *)&_start_time, localtime_buf);
178 /* Normalize to the beginning of the week */
179 start_tm->tm_mday -= start_tm->tm_wday;
180 start_tm->tm_sec = start_tm->tm_min = start_tm->tm_hour = 0;
181 start_tm->tm_isdst = -1;
182 _start_time = mktime(start_tm);
183 start_tm = _XLocaltime((const time_t *)&_start_time, localtime_buf);
185 /* Move forward to the proper week day */
187 RE_WEEKLY(re)->wd_daytime[wd_ndaytime - 1].dt_day;
189 dt_ntime = RE_WEEKLY(re)->wd_daytime[wd_ndaytime - 1].dt_ntime;
191 /* Set the proper time */
193 start_tm->tm_hour = RE_WEEKLY(re)->
194 wd_daytime[wd_ndaytime - 1].dt_time[dt_ntime - 1]
196 start_tm->tm_min = RE_WEEKLY(re)->
197 wd_daytime[wd_ndaytime - 1].dt_time[dt_ntime - 1]
200 start_tm->tm_hour = start_hour;
201 start_tm->tm_min = start_min;
205 start_tm->tm_isdst = -1;
206 last_time2 = mktime(start_tm);
208 return ((last_time1 < last_time2) ? last_time1 : last_time2);
213 const Tick start_time,
214 const RepeatEvent *re)
218 unsigned int md_nitems = RE_MONTHLY(re)->md_nitems,
219 *md_days = RE_MONTHLY(re)->md_days,
224 _Xltimeparams localtime_buf;
226 if (re->re_end_date) {
227 last_time1 = LastTickFromEndDate(start_time, re);
229 if (re->re_duration == RE_NOTSET)
233 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
234 cur_tm = _XLocaltime((const time_t *)&start_time, localtime_buf);
235 start_tm.tm_isdst = -1;
237 /* The 28th - 31st may not exist in a given month thus if only these
238 * days are specified in a rule it is necessary to calculate the
239 * correct month by brute force versus as a mathimatical calculation.
241 if (md_days[0] > 28) {
244 /* Compute last event by brute force */
246 cur_tm->tm_mon += re->re_interval;
247 cur_tm->tm_isdst = -1;
248 cur_time = mktime(cur_tm);
249 cur_tm = _XLocaltime((const time_t *)&cur_time, localtime_buf);
252 DayOfMonth(md_days[0], cur_tm->tm_mon,
254 cur_tm->tm_mon, cur_tm->tm_year))
256 } while (interval < re->re_duration);
258 start_tm.tm_mon = cur_tm->tm_mon;
259 start_tm.tm_year = cur_tm->tm_year;
260 start_tm.tm_mday = LastDayExists(cur_tm, md_nitems, md_days);
262 } else if (md_nitems) {
263 start_tm.tm_mon += (re->re_duration - 1) * re->re_interval;
264 start_tm.tm_mday = 1;
265 /* Have the year and month updated */
266 cur_time = mktime(&start_tm);
267 start_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
268 /* Get the right day (LASTDAY converted to a real day) */
269 start_tm.tm_isdst = -1;
270 start_tm.tm_mday = DayOfMonth(
271 md_days[md_nitems - 1],
272 start_tm.tm_mon, start_tm.tm_year);
274 start_tm.tm_mon += (re->re_duration - 1) * re->re_interval;
276 last_time2 = mktime(&start_tm);
277 return ((last_time1 < last_time2) ? last_time1 : last_time2);
282 const Tick _start_time,
287 Tick last_time1 = EOT,
289 start_time = _start_time;
290 unsigned int nwdt_list = RE_MONTHLY(re)->md_nitems,
294 WeekDayTime *wdt_list = RE_MONTHLY(re)->md_weektime;
295 RepeatEventState *res;
296 _Xltimeparams localtime_buf;
298 if (re->re_end_date) {
299 last_time1 = LastTickFromEndDate(start_time, re);
301 if (re->re_duration == RE_NOTSET)
305 /* Find the real start time */
306 start_time = ClosestTick(start_time, start_time, re, &res);
308 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
310 for (i = 0; i < nwdt_list; i++) {
311 for (j = 0; j < wdt_list[i].wdt_nweek; j++) {
312 if ((wdt_list[i].wdt_week[j] != WK_F5) &&
313 (wdt_list[i].wdt_week[j] != WK_L5)) {
318 if (brute_force == FALSE) break;
325 while (num_intervals < re->re_duration) {
326 cur_tm.tm_mon += re->re_interval;
327 cur_tm.tm_isdst = -1;
328 last_time2 = mktime(&cur_tm);
329 cur_tm = *_XLocaltime((const time_t *)&last_time2,
332 if (OccurenceExists(wdt_list, nwdt_list, last_time2))
335 if (!InTimeRange(num_intervals, re->re_duration))
339 start_tm.tm_mon += (re->re_duration - 1) * re->re_interval;
340 start_tm.tm_isdst = -1;
341 start_tm.tm_mday = 1;
342 last_time2 = mktime(&start_tm);
346 * Given the occurence information, find the last valid day in the
349 last_time2 = LastOccurence(last_time2, wdt_list, nwdt_list);
351 return ((last_time1 < last_time2) ? last_time1 : last_time2);
356 const Tick start_time,
364 RepeatEventState *res;
365 _Xltimeparams localtime_buf;
367 if (re->re_end_date) {
368 last_time1 = LastTickFromEndDate(start_time, re);
370 if (re->re_duration == RE_NOTSET)
374 /* Find the real start time */
375 _start_time = ClosestTick(start_time, start_time, re, &res);
377 start_tm = _XLocaltime((const time_t *)&_start_time, localtime_buf);
378 start_day = start_tm->tm_mday;
380 /* Go to the last day an event can happen on. */
381 start_tm->tm_year += (re->re_duration - 1) * re->re_interval;
382 start_tm->tm_isdst = -1;
384 /* XXX: If the only month used is Feb and the date is the 29th, then
385 * we must use a special case.
388 /* Go to the last time an event can happen on on the last month. */
389 if (RE_YEARLY(re)->yd_nitems) {
392 _start_time = mktime(start_tm);
393 start_tm = _XLocaltime((const time_t *)&_start_time, localtime_buf);
395 for (i = RE_YEARLY(re)->yd_nitems - 1; i >= 0; i++) {
396 if (DayExists(start_day, RE_YEARLY(re)->yd_items[i],
397 start_tm->tm_year)) {
398 start_tm->tm_mon = RE_YEARLY(re)->yd_items[i]-1;
399 start_tm->tm_isdst = -1;
400 return (mktime(start_tm));
403 /* No months have a day that can be used */
407 last_time2 = mktime(start_tm);
408 return ((last_time1 < last_time2) ? last_time1 : last_time2);
413 const Tick start_time,
421 RepeatEventState *res;
422 _Xltimeparams localtime_buf;
424 if (re->re_end_date) {
425 last_time1 = LastTickFromEndDate(start_time, re);
427 if (re->re_duration == RE_NOTSET)
431 /* Find the real start time */
432 _start_time = ClosestTick(start_time, start_time, re, &res);
434 start_tm = _XLocaltime((const time_t *)&_start_time, localtime_buf);
436 /* Go to the last year an event can happen on. */
437 start_tm->tm_year += (re->re_duration - 1) * re->re_interval;
438 start_tm->tm_isdst = -1;
440 /* Go to the last time an event can happen on. */
441 if (RE_YEARLY(re)->yd_nitems) {
442 start_tm->tm_mon = 0;
444 RE_YEARLY(re)->yd_items[RE_YEARLY(re)->yd_nitems - 1];
447 last_time2 = mktime(start_tm);
448 return ((last_time1 < last_time2) ? last_time1 : last_time2);
452 * Given a month/year (from cur_tm), and a list of days of the month
453 * determine the last day in that list that is valid in that month.
457 const struct tm *cur_tm,
458 const unsigned int md_nitems,
459 const unsigned int *md_days)
464 for (i = md_nitems - 1; i >= 0; i--) {
465 day = DayOfMonth(md_days[i], cur_tm->tm_mon, cur_tm->tm_year);
466 if (DayExists(day, cur_tm->tm_mon, cur_tm->tm_year))
474 * Given a month/year (in cur_time) determine the last occurence of week/day/
480 const WeekDayTime *wdt_list,
481 const unsigned int nwdt_list)
484 Tick oldest_time = 0,
487 for (i = 0; i < nwdt_list; i++) {
488 for (j = 0; j < wdt_list[i].wdt_nweek; j++) {
489 for (k = 0; k < wdt_list[i].wdt_nday; k++) {
490 if (current_time = WeekNumberToDay(cur_time,
491 wdt_list[i].wdt_week[j],
492 wdt_list[i].wdt_day[k])) {
493 if (current_time > oldest_time)
494 oldest_time = current_time;
505 * Given a time and a rule find the last tick before the end date.
510 const RepeatEvent *re)
512 RepeatEventState *res;
513 RepeatEvent *_re = (RepeatEvent *)re;
514 Tick end_date = re->re_end_date,
516 Duration duration = re->re_duration;
518 /* Take the end date out of the equation. */
519 _re->re_end_date = 0;
520 _re->re_duration = RE_INFINITY;
522 /* Use the end date to get the closest tick after it, then
523 * step back one tick to get the last tick before the
526 last_time = ClosestTick(end_date, cur_time, _re, &res);
528 * An event that occurs at the same time as the end_date is an
531 if (last_time != end_date)
532 last_time = PrevTick(last_time, cur_time, _re, res);
534 /* Return the re to its original state. */
535 _re->re_end_date = end_date;
536 _re->re_duration = duration;