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 libraries 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: repeat.c /main/7 1996/11/21 19:46:39 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 #include <EUSCompat.h>
33 #define XOS_USE_NO_LOCKING
34 #define X_INCLUDE_TIME_H
35 #if defined(__linux__)
38 #include <X11/Xos_r.h>
46 #define EOT 2147483647
50 static time_t bot, eot;
62 static unsigned int weekdaymasks[] = {
72 static int monthsecs[12] = {
73 31*daysec, 28*daysec, 31*daysec,
74 30*daysec, 31*daysec, 30*daysec,
75 31*daysec, 31*daysec, 30*daysec,
76 31*daysec, 30*daysec, 31*daysec
86 static int lastapptofweek(u_int mask);
87 static int ntimes_this_week(u_int weekmask, int firstday);
88 static boolean_t nthweekdayofmonth(time_t t, int *nth);
89 static time_t next_nmonth(time_t t, int n);
90 static int adjust_dst(time_t start, time_t next);
91 static time_t prev_nmonth(time_t t, int n);
92 static time_t nextnyear(time_t t, int n);
93 static int timeok(time_t t);
94 static time_t prevnyear(time_t t, int n);
95 static time_t prevmonth_exactday(time_t t);
96 static time_t nextmonth_exactday(time_t t);
97 static time_t previousmonth(time_t t);
98 static int monthseconds(time_t t);
99 static int get_ndelta(time_t startdate, Period_4 period, int ntimes);
100 static time_t lastnthweekday(time_t t, int nth, int ntimes);
101 static time_t nextnthweekday(time_t t, int nth);
102 static time_t prevnthweekday(time_t t, int nth);
103 static time_t nextnday_exacttime(time_t t, int n);
104 static time_t prevnday_exacttime(time_t t, int n);
105 static time_t nextnwk_exacttime(time_t t, int n);
106 static time_t prevnwk_exacttime(time_t t, int n);
107 static time_t nextnmth_exactday(time_t t, int n);
108 static time_t prevnmth_exactday(time_t t, int n);
109 static time_t nextmonTofri(time_t t);
110 static time_t prevmonTofri(time_t t);
111 static time_t nextmonwedfri(time_t t);
112 static time_t prevmonwedfri(time_t t);
113 static time_t nexttuethur(time_t t);
114 static time_t prevtuethur(time_t t);
115 static time_t nextdaysofweek(time_t t, int weekmask);
116 static time_t prevdaysofweek(time_t t, int weekmask);
119 * cm now supports to up end of 1999. This is due to the limitation
120 * of cm_getdate() which can only handle up to end of 1999.
121 * When cm_getdate() is improved to handle up to the system limit,
122 * definitions of eot and EOT need to be changed as well as some
123 * of the routines in this file and the caller of these routines.
130 _Xltimeparams localtime_buf;
131 _Xgtimeparams gmtime_buf;
134 tm = *_XLocaltime(&t, localtime_buf);
135 gm = *_XGmtime(&t, gmtime_buf);
137 bot = mktime(&gm) - mktime(&tm);
144 tm.tm_year =137; /* Dec. 31, 2037 */
150 _DtCms_adjust_appt_startdate(Appt_4 *appt)
153 _Xltimeparams localtime_buf;
155 if (appt->period.period < monThruFri_4 ||
156 appt->period.period > tueThur_4)
159 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
160 switch (appt->period.period) {
162 if (tm->tm_wday < 1 || tm->tm_wday > 5)
163 appt->appt_id.tick = _DtCms_next_tick_v4(
168 if ((tm->tm_wday % 2) == 0)
169 appt->appt_id.tick = _DtCms_next_tick_v4(
174 if (tm->tm_wday != 2 && tm->tm_wday != 4)
175 appt->appt_id.tick = _DtCms_next_tick_v4(
183 * Calculate the actual number of instances of the repeating event.
186 _DtCms_get_ninstance_v4(Appt_4 *appt)
189 int i, pdelta, ndelta, ninstance, timesperweek;
191 _Xltimeparams localtime_buf;
193 if (appt->ntimes == _DtCM_OLD_REPEAT_FOREVER)
194 return(appt->ntimes);
196 switch (appt->period.period) {
199 case everyNthMonth_4:
200 ninstance = (appt->ntimes+(appt->period.nth-1))/appt->period.nth;
204 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
205 pdelta = 6 - tm->tm_wday;
206 ndelta = get_ndelta(appt->appt_id.tick, appt->period,
208 dninstance = (double)(appt->ntimes - 1) * 5 + pdelta - ndelta;
209 ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER) ?
210 _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
214 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
215 pdelta = (7 - tm->tm_wday) / 2;
216 ndelta = get_ndelta(appt->appt_id.tick, appt->period,
218 dninstance = (double)(appt->ntimes - 1) * 3 + pdelta - ndelta;
219 ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER)
220 ? _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
224 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
225 pdelta = (tm->tm_wday == 2) ? 2 : 1;
226 ndelta = get_ndelta(appt->appt_id.tick, appt->period,
228 dninstance = (double)(appt->ntimes - 1) * 2 + pdelta - ndelta;
229 ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER) ?
230 _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
234 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
235 timesperweek = ntimes_this_week((u_int)appt->period.nth, 0);
236 pdelta = ntimes_this_week((u_int)appt->period.nth, tm->tm_wday);
237 ndelta = get_ndelta(appt->appt_id.tick, appt->period,
239 dninstance = (double)(appt->ntimes-1) * timesperweek +
241 ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER) ?
242 _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
246 ninstance = appt->ntimes;
253 * calculate the ntimes value which, depending on the
254 * repeating event type, may not be the same
255 * as the actual number of instances
258 _DtCms_get_new_ntimes_v4(Period_4 period, time_t tick, int ninstance)
262 int delta = 0, firstweek, timesperweek;
263 _Xltimeparams localtime_buf;
265 switch (period.period) {
268 case everyNthMonth_4:
269 ntimes = ninstance * period.nth;
272 tm = _XLocaltime(&tick, localtime_buf);
274 delta = ((ninstance % 5) > (6 - tm->tm_wday)) ? 2 : 1;
275 else if (tm->tm_wday != 1)
277 ntimes = (ninstance/5) + delta;
280 tm = _XLocaltime(&tick, localtime_buf);
282 delta = ((ninstance % 3) > ((7-tm->tm_wday)/2)) ? 2:1;
283 else if (tm->tm_wday != 1)
285 ntimes = (ninstance/3) + delta;
288 tm = _XLocaltime(&tick, localtime_buf);
289 if (ninstance % 2 || tm->tm_wday != 2)
291 ntimes = (ninstance/2) + delta;
294 tm = _XLocaltime(&tick, localtime_buf);
295 timesperweek = ntimes_this_week((u_int)period.nth, 0);
296 firstweek=ntimes_this_week((u_int)period.nth,tm->tm_wday);
297 if (ninstance % timesperweek)
298 delta = ((ninstance % timesperweek) > firstweek) ? 2:1;
299 else if (firstweek != timesperweek)
301 ntimes = (ninstance/timesperweek) + delta;
312 _DtCms_first_tick_v4(time_t t, Period_4 period, int ordinal)
318 for (i = 1; i < ordinal; i++)
319 ftick = _DtCms_prev_tick_v4(ftick, period);
326 * Given a time, calculate the closest instance whose
327 * tick is later than the time.
328 * If the calculated tick does not pass timeok(), ftick is
329 * returned and ordinal set to 1.
332 _DtCms_closest_tick_v4(time_t target, time_t ftick, Period_4 period, int *ordinal)
340 _Xltimeparams localtime_buf;
342 if (target <= ftick) {
347 if (period.period < monthly_4 || period.period == everyNthDay_4 ||
348 period.period == everyNthWeek_4) {
349 tm1 = *_XLocaltime(&ftick, localtime_buf);
350 tm2 = *_XLocaltime(&target, localtime_buf);
352 switch(period.period) {
354 delta = (target - ftick) / daysec;
355 remainder = target - ftick - daysec * delta;
356 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
358 *ordinal = delta + (remainder>0?1:0) + 1;
359 ctick = nextnday_exacttime(ftick, *ordinal - 1);
362 delta = (target - ftick) / wksec;
363 remainder = target - ftick - wksec * delta;
364 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
366 *ordinal = delta + (remainder>0?1:0) + 1;
367 ctick = nextnwk_exacttime(ftick, *ordinal - 1);
370 delta = (target - ftick) / (wksec * 2);
371 remainder = target - ftick - wksec * 2 * delta;
372 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
374 *ordinal = delta + (remainder>0?1:0) + 1;
375 ctick = nextnwk_exacttime(ftick, 2 * (*ordinal - 1));
378 tm = _XLocaltime(&ftick, localtime_buf);
380 * Calculate the closest tick only if the date
381 * is < 29; otherwise just return the first tick.
382 * Use 32 to take care of dst time difference.
383 * Without dst, we can use 31.
385 if (tm->tm_mday < 29) {
386 delta = (target - ftick) / (daysec * 32);
387 remainder = target - ftick - (daysec * 32) * delta;
388 *ordinal = delta + (remainder>0?1:0) + 1;
389 ctick = nextnmth_exactday(ftick, *ordinal - 1);
396 tm = _XLocaltime(&ftick, localtime_buf);
397 if (tm->tm_mday == 29 && tm->tm_mon == 1) {
398 delta = (target - ftick) / (yrsec * 4 + daysec);
399 remainder = target - ftick - (yrsec * 4) * delta;
400 *ordinal = delta + (remainder>0?1:0) + 1;
401 ctick = nextnyear(ftick, (*ordinal - 1) * 4);
403 delta = (target - ftick) / yrsec;
404 /* adjustment for leap year */
405 remainder = tm->tm_year % 4;
406 if (remainder == 0 || (remainder + delta) > 3)
408 remainder = target - ftick - yrsec * delta;
409 *ordinal = delta + (remainder>0?1:0) + 1;
410 ctick = nextnyear(ftick, *ordinal - 1);
414 /* 36 is 5 weeks ==> maximum interval between 2 instances */
415 delta = (target - ftick) / (daysec * 36);
416 remainder = target - ftick - (daysec * 36) * delta;
417 *ordinal = delta + (remainder>0?1:0) + 1;
418 ctick = lastnthweekday(ftick, period.nth, *ordinal - 1);
421 delta = (target - ftick) / (daysec * period.nth);
422 remainder = target - ftick - (daysec * period.nth) * delta;
423 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
425 *ordinal = delta + (remainder>0?1:0) + 1;
426 ctick = nextnday_exacttime(ftick,
427 period.nth * (*ordinal - 1));
430 delta = (target - ftick) / (wksec * period.nth);
431 remainder = target - ftick - (wksec * period.nth) * delta;
432 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
434 *ordinal = delta + (remainder>0?1:0) + 1;
435 ctick = nextnwk_exacttime(ftick,
436 period.nth * (*ordinal - 1));
438 case everyNthMonth_4:
439 tm = _XLocaltime(&ftick, localtime_buf);
440 if (tm->tm_mday < 29) {
441 delta = (target - ftick) / (daysec * 32 * period.nth);
442 remainder = target-ftick-(daysec*32*period.nth)*delta;
443 *ordinal = delta + (remainder>0?1:0) + 1;
444 ctick = nextnmth_exactday(ftick,
445 period.nth * (*ordinal - 1));
455 delta = (target - ftick) / wksec;
456 tm = _XLocaltime(&ftick, localtime_buf);
458 switch (period.period) {
460 *ordinal = delta * 5 + 6 - tm->tm_wday;
463 *ordinal = delta * 3 + (7 - tm->tm_wday) / 2;
466 *ordinal = delta * 2 + ((tm->tm_wday == 2) ? 2 : 1);
469 *ordinal = delta * ntimes_this_week((u_int)period.nth,0)
470 + ntimes_this_week((u_int)period.nth,
474 /* delta*daysperweek+(lastapptofweek-firstday in first week) */
475 if (period.period == daysOfWeek_4) {
477 lastapptofweek((u_int)period.nth) - tm->tm_wday;
478 ctick = ftick + ndays * daysec;
479 } else if (period.period == tueThur_4) {
480 ndays = delta * 7 + 4 - tm->tm_wday;
481 ctick = ftick + ndays * daysec;
483 ndays = delta * 7 + 5 - tm->tm_wday;
484 ctick = ftick + ndays * daysec;
487 if (ctick > target) { /* need to go back 1 week */
493 if (period.period == monThruFri_4)
495 else if (period.period == monWedFri_4)
497 else if (period.period == tueThur_4)
499 ctick -= (7 * daysec);
502 ctick = adjust_dst(ftick, ctick);
518 * Calculate the tick of the last instance of a repeating event.
519 * If the calculated tick does not pass timeok(), EOT is returned.
522 _DtCms_last_tick_v4(time_t ftick, Period_4 period, int ntimes)
528 _Xltimeparams localtime_buf;
530 if (ntimes >= _DtCM_OLD_REPEAT_FOREVER)
533 if (period.enddate != 0)
534 return(period.enddate);
536 switch(period.period) {
538 ltick = nextnwk_exacttime(ftick, ntimes - 1);
541 /* 2 * (ntimes-1) won't overflow an integer since
542 * we make sure ntimes is < EOT
544 ltick = nextnwk_exacttime(ftick, 2 * (ntimes - 1));
547 ltick = nextnday_exacttime(ftick, ntimes - 1);
550 tm = _XLocaltime(&ftick, localtime_buf);
552 * calculate the last tick only if the date
553 * is < 29; otherwise return EOT to force calculation
555 if (tm->tm_mday < 29)
556 ltick = nextnmth_exactday(ftick, ntimes - 1);
561 /* 2038 is the last year that can be represented.
562 * this check is to prevent (ntimes-1)*4 from integer overflow
567 tm = _XLocaltime(&ftick, localtime_buf);
568 if (tm->tm_mday == 29 && tm->tm_mon == 1)
569 ltick = nextnyear(ftick, (ntimes - 1) * 4);
571 ltick = nextnyear(ftick, ntimes - 1);
575 ltick = lastnthweekday(ftick, period.nth, ntimes - 1);
578 ltick = nextnday_exacttime(ftick, period.nth *
579 (((ntimes+(period.nth-1))/period.nth) - 1));
582 ltick = nextnwk_exacttime(ftick, period.nth *
583 (((ntimes+(period.nth-1))/period.nth) - 1));
585 case everyNthMonth_4:
586 tm = _XLocaltime(&ftick, localtime_buf);
587 if (tm->tm_mday < 29)
588 ltick = nextnmth_exactday(ftick, period.nth *
589 (((ntimes+(period.nth-1))/period.nth) -1));
597 tm = _XLocaltime(&ftick, localtime_buf);
599 /* (ntimes-1)*daysperweek+(lastapptofweek-fstapptofFstweek) */
600 if (period.period == daysOfWeek_4)
602 ((double)(ntimes - 1) * 7 +
603 lastapptofweek((u_int)period.nth) - tm->tm_wday)
605 else if (period.period == tueThur_4)
607 ((double)(ntimes - 1) * 7 + (4 - tm->tm_wday)) *
611 ((double)(ntimes - 1) * 7 + (5 - tm->tm_wday)) *
614 if (dltick >= EOT || dltick < 0)
617 ltick = adjust_dst(ftick, (time_t)dltick);
629 * Calculate the tick of next instance.
630 * If the calculated tick does not pass timeok(), EOT is returned.
633 _DtCms_next_tick_v4(time_t tick, Period_4 period)
637 _Xltimeparams localtime_buf;
639 switch(period.period) {
641 next = nextnwk_exacttime(tick, 1);
644 next = nextnwk_exacttime(tick, 2);
647 next = nextnday_exacttime(tick, 1);
650 next = nextmonth_exactday(tick);
653 tm = _XLocaltime(&tick, localtime_buf);
654 if (tm->tm_mday == 29 && tm->tm_mon == 1)
655 next = nextnyear(tick, 4);
657 next = nextnyear(tick, 1);
660 next = nextnthweekday(tick, period.nth);
663 next = nextnday_exacttime(tick, period.nth);
666 next = nextnwk_exacttime(tick, period.nth);
668 case everyNthMonth_4:
669 next = nextnmth_exactday(tick, period.nth);
672 next = nextmonTofri(tick);
675 next = nextmonwedfri(tick);
678 next = nexttuethur(tick);
681 next = nextdaysofweek(tick, period.nth);
686 if(next != tick && timeok(next)) return(next);
691 * Calculate the tick of previous instance.
692 * If the calculated tick does not pass timeok(), bot-1 is returned.
695 _DtCms_prev_tick_v4(time_t tick, Period_4 period)
699 _Xltimeparams localtime_buf;
701 switch(period.period) {
703 prev = prevnwk_exacttime(tick, 1);
706 prev = prevnwk_exacttime(tick, 2);
709 prev = prevnday_exacttime(tick, 1);
712 prev = prevmonth_exactday(tick);
715 tm = _XLocaltime(&tick, localtime_buf);
716 if (tm->tm_mday == 29 && tm->tm_mon == 1)
717 prev = prevnyear(tick, 4);
719 prev = prevnyear(tick, 1);
722 prev = prevnthweekday(tick, period.nth);
725 prev = prevnday_exacttime(tick, period.nth);
728 prev = prevnwk_exacttime(tick, period.nth);
730 case everyNthMonth_4:
731 prev = prevnmth_exactday(tick, period.nth);
734 prev = prevmonTofri(tick);
737 prev = prevmonwedfri(tick);
740 prev = prevtuethur(tick);
743 prev = prevdaysofweek(tick, period.nth);
748 if(prev != tick && timeok(prev)) return(prev);
754 * TRUE - it is a match regard_DtCmsIsLess the event is cancelled,
755 * FALSE - it is not a match if the event is cancelled.
758 _DtCms_in_repeater(Id_4 *key, Appt_4 *p_appt, boolean_t dont_care_cancel)
765 ntimes = _DtCms_get_ninstance_v4(p_appt);
766 period = p_appt->period;
767 tick = _DtCms_closest_tick_v4(key->tick, p_appt->appt_id.tick, period, &ordinal);
769 while (++ordinal <= ntimes)
771 if (tick > key->tick) /* out-of-bound */
773 if (tick == key->tick)
775 if (dont_care_cancel)
777 if (!_DtCms_marked_4_cancellation (p_appt, ordinal))
780 tick = _DtCms_next_tick_v4 (tick, period);
787 _DtCms_marked_4_cancellation(Appt_4 *a, int i)
794 p = a->exception; /* in descending order for faster access */
806 next_ndays(time_t t, int n)
810 _Xltimeparams localtime_buf;
812 tm = *_XLocaltime(&t, localtime_buf);
820 next = timelocal(&tm);
822 next = next + n * daysec;
823 next = adjust_dst(t, next);
828 next_nmins(time_t t, int m)
832 _Xltimeparams localtime_buf;
834 tm = *_XLocaltime(&t, localtime_buf);
839 next = next + m * minsec;
840 next = adjust_dst(t, next);
845 _DtCmsBeginOfDay(time_t t)
848 _Xltimeparams localtime_buf;
850 tm = *_XLocaltime(&t, localtime_buf);
858 _DtCmsTimeOfDay(time_t t)
861 _Xltimeparams localtime_buf;
863 tm = *_XLocaltime(&t, localtime_buf);
867 return(t - mktime(&tm));
871 * Given a weekmask, find the last appointment in the week
874 lastapptofweek(u_int mask)
881 for (n = -1; mask != 0; n++, mask = mask >> 1);
887 * Given a weekmask and the first day of the week, calculate
888 * the number of times outstanding in the week.
891 ntimes_this_week(u_int weekmask, int firstday)
893 int i, ntimes, weekdaymask = 1 << firstday;
898 for (i=firstday, ntimes=0; i < 7; i++, weekdaymask <<= 1) {
899 if (weekdaymask & weekmask)
906 nthweekdayofmonth(time_t t, int *nth)
908 struct tm tm, tm2, tmfirstday;
910 _Xltimeparams localtime_buf;
912 tmfirstday = tm = *_XLocaltime(&t, localtime_buf);
914 *nth = (12 + tm.tm_mday - tm.tm_wday)/7;
916 tmfirstday.tm_hour = 0;
917 tmfirstday.tm_min = 0;
918 tmfirstday.tm_sec = 0;
919 tmfirstday.tm_mday = 1;
920 firstday = mktime(&tmfirstday);
921 tmfirstday = *_XLocaltime(&firstday, localtime_buf);
923 if (tm.tm_wday < tmfirstday.tm_wday)
930 tm2 = *_XLocaltime(&t, localtime_buf);
932 return((tm.tm_mon == tm2.tm_mon) ? B_FALSE : B_TRUE);
937 * If the result falls beyond the system limit, -1 is returned by mktime().
940 next_nmonth(time_t t, int n)
944 _Xltimeparams localtime_buf;
949 tm = *_XLocaltime(&t, localtime_buf);
957 if ((tm.tm_mon = tm.tm_mon + n) > 11) {
967 adjust_dst(time_t start, time_t next)
971 _Xltimeparams localtime_buf;
973 oldt = *_XLocaltime(&start, localtime_buf);
974 newt = *_XLocaltime(&next, localtime_buf);
976 if (oldt.tm_isdst == newt.tm_isdst) {
978 } else if (oldt.tm_isdst == 1) {
979 return (next + (int)hrsec);
981 return (next - (int)hrsec);
986 prev_nmonth(time_t t, int n)
990 _Xltimeparams localtime_buf;
995 tm = *_XLocaltime(&t, localtime_buf);
1003 if ((tm.tm_mon = tm.tm_mon - n) < 0) {
1009 return(mktime(&tm));
1011 return(timelocal(&tm));
1019 (y % 4 == 0 && y % 100 !=0 || y % 400 == 0);
1027 _Xltimeparams localtime_buf;
1029 tm = *_XLocaltime(&t, localtime_buf);
1031 return(((mon==1) && leapyr(tm.tm_year+1900))? 29 : monthdays[mon]);
1034 extern int /* find dow(0-6) that 1st dom falls on */
1038 _Xltimeparams localtime_buf;
1040 tm = *_XLocaltime(&t, localtime_buf);
1044 tm = *_XLocaltime(&t, localtime_buf);
1049 ldom(Tick t /* find dow(0-6) that last dom falls on */ )
1052 _Xltimeparams localtime_buf;
1054 tm = *_XLocaltime(&t, localtime_buf);
1055 tm.tm_mday = monthlength(t);
1058 tm = *_XLocaltime(&t, localtime_buf);
1063 _DtCmsInExceptionList(cms_entry *eptr, time_t tick)
1065 CSA_date_time_entry *dt = NULL;
1068 if (eptr->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value)
1069 dt = eptr->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value->\
1070 item.date_time_list_value;
1072 for (; dt != NULL; dt = dt->next) {
1073 if (_csa_iso8601_to_tick(dt->date_time, &time))
1084 nextnyear(time_t t, int n)
1087 _Xltimeparams localtime_buf;
1089 tm = *_XLocaltime(&t, localtime_buf);
1092 return(mktime(&tm));
1094 return(timelocal(&tm));
1101 int r =((t >= bot) &&(t <= eot));
1106 prevnyear(time_t t, int n)
1109 _Xltimeparams localtime_buf;
1111 tm = *_XLocaltime(&t, localtime_buf);
1114 return(mktime(&tm));
1116 return(timelocal(&tm));
1121 prevmonth_exactday(time_t t)
1123 time_t prev; int day;
1126 _Xltimeparams localtime_buf;
1128 tm = *_XLocaltime(&t, localtime_buf);
1129 sdelta = tm.tm_hour * hrsec + tm.tm_min * minsec + tm.tm_sec;
1131 if((tm.tm_mday < 31 && tm.tm_mon != 0) || /* at least 30 days everywhere, except Feb.*/
1132 (tm.tm_mday==31 && tm.tm_mon==6) || /* two 31s -- Jul./Aug. */
1133 (tm.tm_mday==31 && tm.tm_mon==11) || /* two 31s -- Dec./Jan. */
1134 (tm.tm_mon == 0 &&(tm.tm_mday < 29 ||(tm.tm_mday==29 && leapyr(tm.tm_year+1900))))) {
1135 prev = t-monthseconds(previousmonth(t));
1136 prev = adjust_dst(t, prev);
1138 else { /* brute force */
1139 prev = previousmonth(previousmonth(t)); /* hop over the month */
1140 tm = *_XLocaltime(&prev, localtime_buf);
1144 prev =(mktime(&tm)) + sdelta;
1146 prev =(timelocal(&tm)) + sdelta;
1154 nextmonth_exactday(time_t t)
1156 time_t next; int day;
1159 _Xltimeparams localtime_buf;
1161 tm = *_XLocaltime(&t, localtime_buf);
1162 sdelta = tm.tm_hour * hrsec + tm.tm_min * minsec + tm.tm_sec;
1164 if((tm.tm_mday < 31 && tm.tm_mon != 0) || /* at least 30 days everywhere, except Feb.*/
1165 (tm.tm_mday==31 && tm.tm_mon==6) || /* two 31s -- Jul./Aug. */
1166 (tm.tm_mday==31 && tm.tm_mon==11) || /* two 31s -- Dec./Jan. */
1167 (tm.tm_mon == 0 &&(tm.tm_mday < 29 ||(tm.tm_mday==29 && leapyr(tm.tm_year+1900))))) {
1168 next = t+monthseconds(t);
1169 next = adjust_dst(t, next);
1171 else { /* brute force */
1172 next = next_nmonth(t, 2); /* hop over the month */
1173 tm = *_XLocaltime(&next, localtime_buf);
1177 next = mktime(&tm) + sdelta;
1179 next =(timelocal(&tm)) + sdelta;
1186 previousmonth(time_t t)
1189 _Xltimeparams localtime_buf;
1191 tm = *_XLocaltime(&t, localtime_buf);
1206 return(mktime(&tm));
1208 return(timelocal(&tm));
1213 monthseconds(time_t t)
1217 _Xltimeparams localtime_buf;
1219 tm = *_XLocaltime(&t, localtime_buf);
1221 return(((mon==1) && leapyr(tm.tm_year+1900)) ?
1222 29*daysec : monthsecs[mon]);
1226 * find the number of instances to be subtracted
1229 get_ndelta(time_t startdate, Period_4 period, int ntimes)
1235 _Xltimeparams localtime_buf;
1237 if (period.enddate == 0)
1240 /* find last day of the series */
1241 dlastdate = startdate + (double)wksec * (ntimes - 1); /* last week */
1242 if (dlastdate > EOT)
1245 lastdate = (time_t)dlastdate;
1247 tm = _XLocaltime(&lastdate, localtime_buf);
1248 if (period.period == monThruFri_4 || period.period == monWedFri_4)
1249 lastdate = lastdate + daysec * (5 - tm->tm_wday);
1250 else if (period.period == tueThur_4)
1251 lastdate = lastdate + daysec * (4 - tm->tm_wday);
1252 else if (period.period == daysOfWeek_4)
1253 lastdate = lastdate + daysec *
1254 (lastapptofweek((u_int)period.nth) - tm->tm_wday);
1256 if (period.enddate > lastdate)
1259 tm = _XLocaltime(&period.enddate, localtime_buf);
1260 switch (period.period) {
1262 ndelta = 5 - tm->tm_wday;
1265 if (tm->tm_wday < 3)
1267 else if (tm->tm_wday < 5)
1271 if (tm->tm_wday < 2)
1273 else if (tm->tm_wday < 4)
1277 ndelta = ntimes_this_week((u_int)period.nth, tm->tm_wday) - 1;
1284 lastnthweekday(time_t t, int nth, int ntimes)
1290 _Xltimeparams localtime_buf;
1293 * if nth is not specified, assume it's the
1294 * 4th week for the ambiguous case.
1297 nthweekdayofmonth(t, &nth);
1302 tm1 = *_XLocaltime(&t, localtime_buf);
1303 sdelta = tm1.tm_hour * hrsec + tm1.tm_min * minsec + tm1.tm_sec;
1306 if ((tick = next_nmonth(t, ntimes)) == EOT || tick < 0)
1309 tm2 = *_XLocaltime(&tick, localtime_buf);
1311 delta = tm1.tm_wday - tm2.tm_wday;
1315 ntick = tick + (((nth - 1) * 7 + delta) * daysec) + sdelta;
1317 if ((tick = next_nmonth(t, ntimes + 1)) == EOT || tick < 0)
1320 tm2 = *_XLocaltime(&tick, localtime_buf);
1322 delta = tm2.tm_wday - tm1.tm_wday;
1323 if (tm1.tm_wday >= tm2.tm_wday)
1326 ntick = tick - (delta * daysec) + sdelta;
1328 ntick = adjust_dst(tick, ntick);
1334 nextnthweekday(time_t t, int nth)
1340 _Xltimeparams localtime_buf;
1343 * if nth is not specified, assume it's the
1344 * 4th week for the ambiguous case.
1347 nthweekdayofmonth(t, &nth);
1352 tm1 = *_XLocaltime(&t, localtime_buf);
1353 sdelta = tm1.tm_hour * hrsec + tm1.tm_min * minsec + tm1.tm_sec;
1356 tick = next_nmonth(t, 1);
1357 tm2 = *_XLocaltime(&tick, localtime_buf);
1359 delta = tm1.tm_wday - tm2.tm_wday;
1363 ntick = tick + (((nth - 1) * 7 + delta) * daysec) + sdelta;
1365 tick = next_nmonth(t, 2);
1366 tm2 = *_XLocaltime(&tick, localtime_buf);
1368 delta = tm2.tm_wday - tm1.tm_wday;
1369 if (tm1.tm_wday >= tm2.tm_wday)
1372 ntick = tick - (delta * daysec) + sdelta;
1374 ntick = adjust_dst(tick, ntick);
1380 prevnthweekday(time_t t, int nth)
1386 _Xltimeparams localtime_buf;
1389 * if nth is not specified, assume it's the
1390 * 4th week for the ambiguous case.
1393 nthweekdayofmonth(t, &nth);
1398 tm1 = *_XLocaltime(&t, localtime_buf);
1399 sdelta = tm1.tm_hour * hrsec + tm1.tm_min * minsec + tm1.tm_sec;
1402 tick = prev_nmonth(t, 1);
1403 tm2 = *_XLocaltime(&tick, localtime_buf);
1405 delta = tm1.tm_wday - tm2.tm_wday;
1409 ptick = tick + (((nth - 1) * 7 + delta) * daysec) + sdelta;
1411 tick = prev_nmonth(next_nmonth(t, 1), 1);
1412 tm2 = *_XLocaltime(&tick, localtime_buf);
1414 delta = tm2.tm_wday - tm1.tm_wday;
1415 if (tm1.tm_wday >= tm2.tm_wday)
1418 ptick = tick - (delta * daysec) + sdelta;
1420 ptick = adjust_dst(tick, ptick);
1425 /* use double in this routine to avoid integer overflow
1426 * in case n is very large.
1429 nextnday_exacttime(time_t t, int n)
1433 next = t + (double)n * daysec;
1434 if (next >= EOT || next < 0)
1437 next = adjust_dst(t, (time_t)next);
1438 return((time_t)next);
1443 * This is defined in the private library and is used also by the front
1444 * end -- should it be here?
1447 prevnday_exacttime(time_t t, int n)
1451 prev = t - (n * daysec);
1452 prev = adjust_dst(t, prev);
1456 /* use double in this routine to avoid integer overflow
1457 * in case n is very large.
1460 nextnwk_exacttime(time_t t, int n)
1464 next = t + (double)n * 7 * daysec;
1465 if (next >= EOT || next < 0)
1468 next = adjust_dst(t, (time_t)next);
1469 return((time_t)next);
1474 prevnwk_exacttime(time_t t, int n)
1478 prev = t - n * 7 * daysec;
1479 prev = adjust_dst(t, prev);
1484 nextnmth_exactday(time_t t, int n)
1487 boolean_t done = B_FALSE;
1489 _Xltimeparams localtime_buf;
1491 tm1 = *_XLocaltime(&t, localtime_buf);
1493 if ((next = next_nmonth(t, n)) == EOT || next < 0)
1496 tm2 = *_XLocaltime(&next, localtime_buf);
1498 /* 1. at least 30 days except feb
1499 * 2. 2/29 on leap year
1500 * 3. 31st on the appropriate month
1502 if ((tm1.tm_mday < 31 && tm2.tm_mon != 1) ||
1503 (tm2.tm_mon == 1 && (tm1.tm_mday < 29 ||
1504 (tm1.tm_mday == 29 && leapyr(tm2.tm_year + 1900)))) ||
1505 (tm1.tm_mday == 31 && ((tm2.tm_mon > 6 && tm2.tm_mon % 2) ||
1506 ((tm2.tm_mon <= 6 && (tm2.tm_mon % 2 == 0)))))) {
1507 tm2.tm_sec = tm1.tm_sec;
1508 tm2.tm_min = tm1.tm_min;
1509 tm2.tm_hour = tm1.tm_hour;
1510 tm2.tm_mday = tm1.tm_mday;
1518 next = mktime(&tm2);
1520 next = (timelocal(&tm2));
1526 prevnmth_exactday(time_t t, int n)
1529 boolean_t done = B_FALSE;
1531 _Xltimeparams localtime_buf;
1533 tm1 = *_XLocaltime(&t, localtime_buf);
1535 prev = prev_nmonth(t, n);
1536 tm2 = *_XLocaltime(&prev, localtime_buf);
1538 if ((tm1.tm_mday < 30 && tm2.tm_mon != 1) ||
1539 (tm2.tm_mon == 1 && (tm1.tm_mday < 29 ||
1540 (tm1.tm_mday == 29 && leapyr(tm2.tm_year + 1900)))) ||
1541 (tm1.tm_mday == 31 && ((tm2.tm_mon > 6 && tm2.tm_mon % 2) ||
1542 ((tm2.tm_mon <= 6 && (tm2.tm_mon % 2 == 0)))))) {
1543 tm2.tm_sec = tm1.tm_sec;
1544 tm2.tm_min = tm1.tm_min;
1545 tm2.tm_hour = tm1.tm_hour;
1546 tm2.tm_mday = tm1.tm_mday;
1554 prev = mktime(&tm2);
1556 prev = (timelocal(&tm2));
1562 nextmonTofri(time_t t)
1566 _Xltimeparams localtime_buf;
1568 tm = _XLocaltime(&t, localtime_buf);
1570 if (tm->tm_wday < 5)
1571 next = t + (int)daysec;
1573 next = t + (int)daysec * (8 - tm->tm_wday);
1575 next = adjust_dst(t, next);
1580 prevmonTofri(time_t t)
1584 _Xltimeparams localtime_buf;
1586 tm = _XLocaltime(&t, localtime_buf);
1588 if (tm->tm_wday > 1)
1589 prev = t - (int)daysec;
1591 prev = t - (int)daysec * (2 + tm->tm_wday);
1593 prev = adjust_dst(t, prev);
1598 nextmonwedfri(time_t t)
1602 _Xltimeparams localtime_buf;
1604 tm = _XLocaltime(&t, localtime_buf);
1606 if (tm->tm_wday == 5)
1607 next = t + (int)daysec * 3;
1608 else if (tm->tm_wday % 2 || tm->tm_wday == 6)
1609 next = t + (int)daysec * 2;
1611 next = t + (int)daysec;
1613 next = adjust_dst(t, next);
1618 prevmonwedfri(time_t t)
1622 _Xltimeparams localtime_buf;
1624 tm = _XLocaltime(&t, localtime_buf);
1626 if (tm->tm_wday == 1)
1627 prev = t - (int)daysec * 3;
1628 else if (tm->tm_wday % 2 || tm->tm_wday == 0)
1629 prev = t - (int)daysec * 2;
1631 prev = t - (int)daysec;
1633 prev = adjust_dst(t, prev);
1638 nexttuethur(time_t t)
1642 _Xltimeparams localtime_buf;
1644 tm = _XLocaltime(&t, localtime_buf);
1646 if (tm->tm_wday < 4) {
1647 if (tm->tm_wday % 2)
1648 next = t + (int)daysec;
1650 next = t + (int)daysec * 2;
1652 next = t + (int)daysec * (9 - tm->tm_wday);
1654 next = adjust_dst(t, next);
1659 prevtuethur(time_t t)
1663 _Xltimeparams localtime_buf;
1665 tm = _XLocaltime(&t, localtime_buf);
1667 if (tm->tm_wday > 2) {
1668 if (tm->tm_wday % 2)
1669 prev = t - (int)daysec;
1671 prev = t - (int)daysec * 2;
1673 prev = t - (int)daysec * (3 + tm->tm_wday);
1675 prev = adjust_dst(t, prev);
1680 * the 7-bit mask should be put in the last 7 bits of the int
1683 nextdaysofweek(time_t t, int weekmask)
1685 unsigned int doublemask;
1687 int i, ndays, daymask;
1689 _Xltimeparams localtime_buf;
1691 doublemask = weekmask | (weekmask << 7);
1692 tm = _XLocaltime(&t, localtime_buf);
1693 daymask = weekdaymasks[tm->tm_wday] << 1;
1695 for (i = 0, ndays = 1; i < 7; i++) {
1696 if (daymask & doublemask)
1704 next = t + (int)daysec * ndays;
1705 next = adjust_dst(t, next);
1710 prevdaysofweek(time_t t, int weekmask)
1712 unsigned int doublemask, daymask;
1716 _Xltimeparams localtime_buf;
1718 doublemask = weekmask | (weekmask << 7);
1719 tm = _XLocaltime(&t, localtime_buf);
1720 daymask = weekdaymasks[tm->tm_wday] << 6;
1722 for (i = 0, ndays = 1; i < 7; i++) {
1723 if (daymask & doublemask)
1731 prev = t - (int)daysec * ndays;
1732 prev = adjust_dst(t, prev);