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: 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
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;
138 /* Fix for QAR 31607 */
139 if (getenv("TZ") == NULL){
141 tzptr = malloc(strlen(tzname[0]) + strlen(tzname[1]) + 10);
142 sprintf (tzptr,"TZ=%s%d%s", tzname[0], timezone/3600, tzname[1]);
151 tm = *_XLocaltime(&t, localtime_buf);
152 gm = *_XGmtime(&t, gmtime_buf);
154 bot = mktime(&gm) - mktime(&tm);
161 tm.tm_year =137; /* Dec. 31, 2037 */
167 _DtCms_adjust_appt_startdate(Appt_4 *appt)
170 _Xltimeparams localtime_buf;
172 if (appt->period.period < monThruFri_4 ||
173 appt->period.period > tueThur_4)
176 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
177 switch (appt->period.period) {
179 if (tm->tm_wday < 1 || tm->tm_wday > 5)
180 appt->appt_id.tick = _DtCms_next_tick_v4(
185 if ((tm->tm_wday % 2) == 0)
186 appt->appt_id.tick = _DtCms_next_tick_v4(
191 if (tm->tm_wday != 2 && tm->tm_wday != 4)
192 appt->appt_id.tick = _DtCms_next_tick_v4(
200 * Calculate the actual number of instances of the repeating event.
203 _DtCms_get_ninstance_v4(Appt_4 *appt)
206 int i, pdelta, ndelta, ninstance, timesperweek;
208 _Xltimeparams localtime_buf;
210 if (appt->ntimes == _DtCM_OLD_REPEAT_FOREVER)
211 return(appt->ntimes);
213 switch (appt->period.period) {
216 case everyNthMonth_4:
217 ninstance = (appt->ntimes+(appt->period.nth-1))/appt->period.nth;
221 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
222 pdelta = 6 - tm->tm_wday;
223 ndelta = get_ndelta(appt->appt_id.tick, appt->period,
225 dninstance = (double)(appt->ntimes - 1) * 5 + pdelta - ndelta;
226 ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER) ?
227 _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
231 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
232 pdelta = (7 - tm->tm_wday) / 2;
233 ndelta = get_ndelta(appt->appt_id.tick, appt->period,
235 dninstance = (double)(appt->ntimes - 1) * 3 + pdelta - ndelta;
236 ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER)
237 ? _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
241 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
242 pdelta = (tm->tm_wday == 2) ? 2 : 1;
243 ndelta = get_ndelta(appt->appt_id.tick, appt->period,
245 dninstance = (double)(appt->ntimes - 1) * 2 + pdelta - ndelta;
246 ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER) ?
247 _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
251 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
252 timesperweek = ntimes_this_week((u_int)appt->period.nth, 0);
253 pdelta = ntimes_this_week((u_int)appt->period.nth, tm->tm_wday);
254 ndelta = get_ndelta(appt->appt_id.tick, appt->period,
256 dninstance = (double)(appt->ntimes-1) * timesperweek +
258 ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER) ?
259 _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
263 ninstance = appt->ntimes;
270 * calculate the ntimes value which, depending on the
271 * repeating event type, may not be the same
272 * as the actual number of instances
275 _DtCms_get_new_ntimes_v4(Period_4 period, time_t tick, int ninstance)
279 int delta = 0, firstweek, timesperweek;
280 _Xltimeparams localtime_buf;
282 switch (period.period) {
285 case everyNthMonth_4:
286 ntimes = ninstance * period.nth;
289 tm = _XLocaltime(&tick, localtime_buf);
291 delta = ((ninstance % 5) > (6 - tm->tm_wday)) ? 2 : 1;
292 else if (tm->tm_wday != 1)
294 ntimes = (ninstance/5) + delta;
297 tm = _XLocaltime(&tick, localtime_buf);
299 delta = ((ninstance % 3) > ((7-tm->tm_wday)/2)) ? 2:1;
300 else if (tm->tm_wday != 1)
302 ntimes = (ninstance/3) + delta;
305 tm = _XLocaltime(&tick, localtime_buf);
306 if (ninstance % 2 || tm->tm_wday != 2)
308 ntimes = (ninstance/2) + delta;
311 tm = _XLocaltime(&tick, localtime_buf);
312 timesperweek = ntimes_this_week((u_int)period.nth, 0);
313 firstweek=ntimes_this_week((u_int)period.nth,tm->tm_wday);
314 if (ninstance % timesperweek)
315 delta = ((ninstance % timesperweek) > firstweek) ? 2:1;
316 else if (firstweek != timesperweek)
318 ntimes = (ninstance/timesperweek) + delta;
329 _DtCms_first_tick_v4(time_t t, Period_4 period, int ordinal)
335 for (i = 1; i < ordinal; i++)
336 ftick = _DtCms_prev_tick_v4(ftick, period);
343 * Given a time, calculate the closest instance whose
344 * tick is later than the time.
345 * If the calculated tick does not pass timeok(), ftick is
346 * returned and ordinal set to 1.
349 _DtCms_closest_tick_v4(time_t target, time_t ftick, Period_4 period, int *ordinal)
357 _Xltimeparams localtime_buf;
359 if (target <= ftick) {
364 if (period.period < monthly_4 || period.period == everyNthDay_4 ||
365 period.period == everyNthWeek_4) {
366 tm1 = *_XLocaltime(&ftick, localtime_buf);
367 tm2 = *_XLocaltime(&target, localtime_buf);
369 switch(period.period) {
371 delta = (target - ftick) / daysec;
372 remainder = target - ftick - daysec * delta;
373 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
375 *ordinal = delta + (remainder>0?1:0) + 1;
376 ctick = nextnday_exacttime(ftick, *ordinal - 1);
379 delta = (target - ftick) / wksec;
380 remainder = target - ftick - wksec * delta;
381 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
383 *ordinal = delta + (remainder>0?1:0) + 1;
384 ctick = nextnwk_exacttime(ftick, *ordinal - 1);
387 delta = (target - ftick) / (wksec * 2);
388 remainder = target - ftick - wksec * 2 * delta;
389 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
391 *ordinal = delta + (remainder>0?1:0) + 1;
392 ctick = nextnwk_exacttime(ftick, 2 * (*ordinal - 1));
395 tm = _XLocaltime(&ftick, localtime_buf);
397 * Calculate the closest tick only if the date
398 * is < 29; otherwise just return the first tick.
399 * Use 32 to take care of dst time difference.
400 * Without dst, we can use 31.
402 if (tm->tm_mday < 29) {
403 delta = (target - ftick) / (daysec * 32);
404 remainder = target - ftick - (daysec * 32) * delta;
405 *ordinal = delta + (remainder>0?1:0) + 1;
406 ctick = nextnmth_exactday(ftick, *ordinal - 1);
413 tm = _XLocaltime(&ftick, localtime_buf);
414 if (tm->tm_mday == 29 && tm->tm_mon == 1) {
415 delta = (target - ftick) / (yrsec * 4 + daysec);
416 remainder = target - ftick - (yrsec * 4) * delta;
417 *ordinal = delta + (remainder>0?1:0) + 1;
418 ctick = nextnyear(ftick, (*ordinal - 1) * 4);
420 delta = (target - ftick) / yrsec;
421 /* adjustment for leap year */
422 remainder = tm->tm_year % 4;
423 if (remainder == 0 || (remainder + delta) > 3)
425 remainder = target - ftick - yrsec * delta;
426 *ordinal = delta + (remainder>0?1:0) + 1;
427 ctick = nextnyear(ftick, *ordinal - 1);
431 /* 36 is 5 weeks ==> maximum interval between 2 instances */
432 delta = (target - ftick) / (daysec * 36);
433 remainder = target - ftick - (daysec * 36) * delta;
434 *ordinal = delta + (remainder>0?1:0) + 1;
435 ctick = lastnthweekday(ftick, period.nth, *ordinal - 1);
438 delta = (target - ftick) / (daysec * period.nth);
439 remainder = target - ftick - (daysec * period.nth) * delta;
440 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
442 *ordinal = delta + (remainder>0?1:0) + 1;
443 ctick = nextnday_exacttime(ftick,
444 period.nth * (*ordinal - 1));
447 delta = (target - ftick) / (wksec * period.nth);
448 remainder = target - ftick - (wksec * period.nth) * delta;
449 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
451 *ordinal = delta + (remainder>0?1:0) + 1;
452 ctick = nextnwk_exacttime(ftick,
453 period.nth * (*ordinal - 1));
455 case everyNthMonth_4:
456 tm = _XLocaltime(&ftick, localtime_buf);
457 if (tm->tm_mday < 29) {
458 delta = (target - ftick) / (daysec * 32 * period.nth);
459 remainder = target-ftick-(daysec*32*period.nth)*delta;
460 *ordinal = delta + (remainder>0?1:0) + 1;
461 ctick = nextnmth_exactday(ftick,
462 period.nth * (*ordinal - 1));
472 delta = (target - ftick) / wksec;
473 tm = _XLocaltime(&ftick, localtime_buf);
475 switch (period.period) {
477 *ordinal = delta * 5 + 6 - tm->tm_wday;
480 *ordinal = delta * 3 + (7 - tm->tm_wday) / 2;
483 *ordinal = delta * 2 + ((tm->tm_wday == 2) ? 2 : 1);
486 *ordinal = delta * ntimes_this_week((u_int)period.nth,0)
487 + ntimes_this_week((u_int)period.nth,
491 /* delta*daysperweek+(lastapptofweek-firstday in first week) */
492 if (period.period == daysOfWeek_4) {
494 lastapptofweek((u_int)period.nth) - tm->tm_wday;
495 ctick = ftick + ndays * daysec;
496 } else if (period.period == tueThur_4) {
497 ndays = delta * 7 + 4 - tm->tm_wday;
498 ctick = ftick + ndays * daysec;
500 ndays = delta * 7 + 5 - tm->tm_wday;
501 ctick = ftick + ndays * daysec;
504 if (ctick > target) { /* need to go back 1 week */
510 if (period.period == monThruFri_4)
512 else if (period.period == monWedFri_4)
514 else if (period.period == tueThur_4)
516 ctick -= (7 * daysec);
519 ctick = adjust_dst(ftick, ctick);
535 * Calculate the tick of the last instance of a repeating event.
536 * If the calculated tick does not pass timeok(), EOT is returned.
539 _DtCms_last_tick_v4(time_t ftick, Period_4 period, int ntimes)
545 _Xltimeparams localtime_buf;
547 if (ntimes >= _DtCM_OLD_REPEAT_FOREVER)
550 if (period.enddate != 0)
551 return(period.enddate);
553 switch(period.period) {
555 ltick = nextnwk_exacttime(ftick, ntimes - 1);
558 /* 2 * (ntimes-1) won't overflow an integer since
559 * we make sure ntimes is < EOT
561 ltick = nextnwk_exacttime(ftick, 2 * (ntimes - 1));
564 ltick = nextnday_exacttime(ftick, ntimes - 1);
567 tm = _XLocaltime(&ftick, localtime_buf);
569 * calculate the last tick only if the date
570 * is < 29; otherwise return EOT to force calculation
572 if (tm->tm_mday < 29)
573 ltick = nextnmth_exactday(ftick, ntimes - 1);
578 /* 2038 is the last year that can be represented.
579 * this check is to prevent (ntimes-1)*4 from integer overflow
584 tm = _XLocaltime(&ftick, localtime_buf);
585 if (tm->tm_mday == 29 && tm->tm_mon == 1)
586 ltick = nextnyear(ftick, (ntimes - 1) * 4);
588 ltick = nextnyear(ftick, ntimes - 1);
592 ltick = lastnthweekday(ftick, period.nth, ntimes - 1);
595 ltick = nextnday_exacttime(ftick, period.nth *
596 (((ntimes+(period.nth-1))/period.nth) - 1));
599 ltick = nextnwk_exacttime(ftick, period.nth *
600 (((ntimes+(period.nth-1))/period.nth) - 1));
602 case everyNthMonth_4:
603 tm = _XLocaltime(&ftick, localtime_buf);
604 if (tm->tm_mday < 29)
605 ltick = nextnmth_exactday(ftick, period.nth *
606 (((ntimes+(period.nth-1))/period.nth) -1));
614 tm = _XLocaltime(&ftick, localtime_buf);
616 /* (ntimes-1)*daysperweek+(lastapptofweek-fstapptofFstweek) */
617 if (period.period == daysOfWeek_4)
619 ((double)(ntimes - 1) * 7 +
620 lastapptofweek((u_int)period.nth) - tm->tm_wday)
622 else if (period.period == tueThur_4)
624 ((double)(ntimes - 1) * 7 + (4 - tm->tm_wday)) *
628 ((double)(ntimes - 1) * 7 + (5 - tm->tm_wday)) *
631 if (dltick >= EOT || dltick < 0)
634 ltick = adjust_dst(ftick, (time_t)dltick);
646 * Calculate the tick of next instance.
647 * If the calculated tick does not pass timeok(), EOT is returned.
650 _DtCms_next_tick_v4(time_t tick, Period_4 period)
654 _Xltimeparams localtime_buf;
656 switch(period.period) {
658 next = nextnwk_exacttime(tick, 1);
661 next = nextnwk_exacttime(tick, 2);
664 next = nextnday_exacttime(tick, 1);
667 next = nextmonth_exactday(tick);
670 tm = _XLocaltime(&tick, localtime_buf);
671 if (tm->tm_mday == 29 && tm->tm_mon == 1)
672 next = nextnyear(tick, 4);
674 next = nextnyear(tick, 1);
677 next = nextnthweekday(tick, period.nth);
680 next = nextnday_exacttime(tick, period.nth);
683 next = nextnwk_exacttime(tick, period.nth);
685 case everyNthMonth_4:
686 next = nextnmth_exactday(tick, period.nth);
689 next = nextmonTofri(tick);
692 next = nextmonwedfri(tick);
695 next = nexttuethur(tick);
698 next = nextdaysofweek(tick, period.nth);
703 if(next != tick && timeok(next)) return(next);
708 * Calculate the tick of previous instance.
709 * If the calculated tick does not pass timeok(), bot-1 is returned.
712 _DtCms_prev_tick_v4(time_t tick, Period_4 period)
716 _Xltimeparams localtime_buf;
718 switch(period.period) {
720 prev = prevnwk_exacttime(tick, 1);
723 prev = prevnwk_exacttime(tick, 2);
726 prev = prevnday_exacttime(tick, 1);
729 prev = prevmonth_exactday(tick);
732 tm = _XLocaltime(&tick, localtime_buf);
733 if (tm->tm_mday == 29 && tm->tm_mon == 1)
734 prev = prevnyear(tick, 4);
736 prev = prevnyear(tick, 1);
739 prev = prevnthweekday(tick, period.nth);
742 prev = prevnday_exacttime(tick, period.nth);
745 prev = prevnwk_exacttime(tick, period.nth);
747 case everyNthMonth_4:
748 prev = prevnmth_exactday(tick, period.nth);
751 prev = prevmonTofri(tick);
754 prev = prevmonwedfri(tick);
757 prev = prevtuethur(tick);
760 prev = prevdaysofweek(tick, period.nth);
765 if(prev != tick && timeok(prev)) return(prev);
771 * TRUE - it is a match regard_DtCmsIsLess the event is cancelled,
772 * FALSE - it is not a match if the event is cancelled.
775 _DtCms_in_repeater(Id_4 *key, Appt_4 *p_appt, boolean_t dont_care_cancel)
782 ntimes = _DtCms_get_ninstance_v4(p_appt);
783 period = p_appt->period;
784 tick = _DtCms_closest_tick_v4(key->tick, p_appt->appt_id.tick, period, &ordinal);
786 while (++ordinal <= ntimes)
788 if (tick > key->tick) /* out-of-bound */
790 if (tick == key->tick)
792 if (dont_care_cancel)
794 if (!_DtCms_marked_4_cancellation (p_appt, ordinal))
797 tick = _DtCms_next_tick_v4 (tick, period);
804 _DtCms_marked_4_cancellation(Appt_4 *a, int i)
811 p = a->exception; /* in descending order for faster access */
823 next_ndays(time_t t, int n)
827 _Xltimeparams localtime_buf;
829 tm = *_XLocaltime(&t, localtime_buf);
837 next = timelocal(&tm);
839 next = next + n * daysec;
840 next = adjust_dst(t, next);
845 next_nmins(time_t t, int m)
849 _Xltimeparams localtime_buf;
851 tm = *_XLocaltime(&t, localtime_buf);
856 next = next + m * minsec;
857 next = adjust_dst(t, next);
862 _DtCmsBeginOfDay(time_t t)
865 _Xltimeparams localtime_buf;
867 tm = *_XLocaltime(&t, localtime_buf);
875 _DtCmsTimeOfDay(time_t t)
878 _Xltimeparams localtime_buf;
880 tm = *_XLocaltime(&t, localtime_buf);
884 return(t - mktime(&tm));
888 * Given a weekmask, find the last appointment in the week
891 lastapptofweek(u_int mask)
898 for (n = -1; mask != 0; n++, mask = mask >> 1);
904 * Given a weekmask and the first day of the week, calculate
905 * the number of times outstanding in the week.
908 ntimes_this_week(u_int weekmask, int firstday)
910 int i, ntimes, weekdaymask = 1 << firstday;
915 for (i=firstday, ntimes=0; i < 7; i++, weekdaymask <<= 1) {
916 if (weekdaymask & weekmask)
923 nthweekdayofmonth(time_t t, int *nth)
925 struct tm tm, tm2, tmfirstday;
927 _Xltimeparams localtime_buf;
929 tmfirstday = tm = *_XLocaltime(&t, localtime_buf);
931 *nth = (12 + tm.tm_mday - tm.tm_wday)/7;
933 tmfirstday.tm_hour = 0;
934 tmfirstday.tm_min = 0;
935 tmfirstday.tm_sec = 0;
936 tmfirstday.tm_mday = 1;
937 firstday = mktime(&tmfirstday);
938 tmfirstday = *_XLocaltime(&firstday, localtime_buf);
940 if (tm.tm_wday < tmfirstday.tm_wday)
947 tm2 = *_XLocaltime(&t, localtime_buf);
949 return((tm.tm_mon == tm2.tm_mon) ? B_FALSE : B_TRUE);
954 * If the result falls beyond the system limit, -1 is returned by mktime().
957 next_nmonth(time_t t, int n)
961 _Xltimeparams localtime_buf;
966 tm = *_XLocaltime(&t, localtime_buf);
974 if ((tm.tm_mon = tm.tm_mon + n) > 11) {
984 adjust_dst(time_t start, time_t next)
988 _Xltimeparams localtime_buf;
990 oldt = *_XLocaltime(&start, localtime_buf);
991 newt = *_XLocaltime(&next, localtime_buf);
993 if (oldt.tm_isdst == newt.tm_isdst) {
995 } else if (oldt.tm_isdst == 1) {
996 return (next + (int)hrsec);
998 return (next - (int)hrsec);
1003 prev_nmonth(time_t t, int n)
1007 _Xltimeparams localtime_buf;
1012 tm = *_XLocaltime(&t, localtime_buf);
1020 if ((tm.tm_mon = tm.tm_mon - n) < 0) {
1026 return(mktime(&tm));
1028 return(timelocal(&tm));
1036 (y % 4 == 0 && y % 100 !=0 || y % 400 == 0);
1044 _Xltimeparams localtime_buf;
1046 tm = *_XLocaltime(&t, localtime_buf);
1048 return(((mon==1) && leapyr(tm.tm_year+1900))? 29 : monthdays[mon]);
1051 extern int /* find dow(0-6) that 1st dom falls on */
1055 _Xltimeparams localtime_buf;
1057 tm = *_XLocaltime(&t, localtime_buf);
1061 tm = *_XLocaltime(&t, localtime_buf);
1066 ldom(Tick t /* find dow(0-6) that last dom falls on */ )
1069 _Xltimeparams localtime_buf;
1071 tm = *_XLocaltime(&t, localtime_buf);
1072 tm.tm_mday = monthlength(t);
1075 tm = *_XLocaltime(&t, localtime_buf);
1080 _DtCmsInExceptionList(cms_entry *eptr, time_t tick)
1082 CSA_date_time_entry *dt = NULL;
1085 if (eptr->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value)
1086 dt = eptr->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value->\
1087 item.date_time_list_value;
1089 for (; dt != NULL; dt = dt->next) {
1090 if (_csa_iso8601_to_tick(dt->date_time, &time))
1101 nextnyear(time_t t, int n)
1104 _Xltimeparams localtime_buf;
1106 tm = *_XLocaltime(&t, localtime_buf);
1109 return(mktime(&tm));
1111 return(timelocal(&tm));
1118 int r =((t >= bot) &&(t <= eot));
1123 prevnyear(time_t t, int n)
1126 _Xltimeparams localtime_buf;
1128 tm = *_XLocaltime(&t, localtime_buf);
1131 return(mktime(&tm));
1133 return(timelocal(&tm));
1138 prevmonth_exactday(time_t t)
1140 time_t prev; int day;
1143 _Xltimeparams localtime_buf;
1145 tm = *_XLocaltime(&t, localtime_buf);
1146 sdelta = tm.tm_hour * hrsec + tm.tm_min * minsec + tm.tm_sec;
1148 if((tm.tm_mday < 31 && tm.tm_mon != 0) || /* at least 30 days everywhere, except Feb.*/
1149 (tm.tm_mday==31 && tm.tm_mon==6) || /* two 31s -- Jul./Aug. */
1150 (tm.tm_mday==31 && tm.tm_mon==11) || /* two 31s -- Dec./Jan. */
1151 (tm.tm_mon == 0 &&(tm.tm_mday < 29 ||(tm.tm_mday==29 && leapyr(tm.tm_year+1900))))) {
1152 prev = t-monthseconds(previousmonth(t));
1153 prev = adjust_dst(t, prev);
1155 else { /* brute force */
1156 prev = previousmonth(previousmonth(t)); /* hop over the month */
1157 tm = *_XLocaltime(&prev, localtime_buf);
1161 prev =(mktime(&tm)) + sdelta;
1163 prev =(timelocal(&tm)) + sdelta;
1171 nextmonth_exactday(time_t t)
1173 time_t next; int day;
1176 _Xltimeparams localtime_buf;
1178 tm = *_XLocaltime(&t, localtime_buf);
1179 sdelta = tm.tm_hour * hrsec + tm.tm_min * minsec + tm.tm_sec;
1181 if((tm.tm_mday < 31 && tm.tm_mon != 0) || /* at least 30 days everywhere, except Feb.*/
1182 (tm.tm_mday==31 && tm.tm_mon==6) || /* two 31s -- Jul./Aug. */
1183 (tm.tm_mday==31 && tm.tm_mon==11) || /* two 31s -- Dec./Jan. */
1184 (tm.tm_mon == 0 &&(tm.tm_mday < 29 ||(tm.tm_mday==29 && leapyr(tm.tm_year+1900))))) {
1185 next = t+monthseconds(t);
1186 next = adjust_dst(t, next);
1188 else { /* brute force */
1189 next = next_nmonth(t, 2); /* hop over the month */
1190 tm = *_XLocaltime(&next, localtime_buf);
1194 next = mktime(&tm) + sdelta;
1196 next =(timelocal(&tm)) + sdelta;
1203 previousmonth(time_t t)
1206 _Xltimeparams localtime_buf;
1208 tm = *_XLocaltime(&t, localtime_buf);
1223 return(mktime(&tm));
1225 return(timelocal(&tm));
1230 monthseconds(time_t t)
1234 _Xltimeparams localtime_buf;
1236 tm = *_XLocaltime(&t, localtime_buf);
1238 return(((mon==1) && leapyr(tm.tm_year+1900)) ?
1239 29*daysec : monthsecs[mon]);
1243 * find the number of instances to be subtracted
1246 get_ndelta(time_t startdate, Period_4 period, int ntimes)
1252 _Xltimeparams localtime_buf;
1254 if (period.enddate == 0)
1257 /* find last day of the series */
1258 dlastdate = startdate + (double)wksec * (ntimes - 1); /* last week */
1259 if (dlastdate > EOT)
1262 lastdate = (time_t)dlastdate;
1264 tm = _XLocaltime(&lastdate, localtime_buf);
1265 if (period.period == monThruFri_4 || period.period == monWedFri_4)
1266 lastdate = lastdate + daysec * (5 - tm->tm_wday);
1267 else if (period.period == tueThur_4)
1268 lastdate = lastdate + daysec * (4 - tm->tm_wday);
1269 else if (period.period == daysOfWeek_4)
1270 lastdate = lastdate + daysec *
1271 (lastapptofweek((u_int)period.nth) - tm->tm_wday);
1273 if (period.enddate > lastdate)
1276 tm = _XLocaltime(&period.enddate, localtime_buf);
1277 switch (period.period) {
1279 ndelta = 5 - tm->tm_wday;
1282 if (tm->tm_wday < 3)
1284 else if (tm->tm_wday < 5)
1288 if (tm->tm_wday < 2)
1290 else if (tm->tm_wday < 4)
1294 ndelta = ntimes_this_week((u_int)period.nth, tm->tm_wday) - 1;
1301 lastnthweekday(time_t t, int nth, int ntimes)
1307 _Xltimeparams localtime_buf;
1310 * if nth is not specified, assume it's the
1311 * 4th week for the ambiguous case.
1314 nthweekdayofmonth(t, &nth);
1319 tm1 = *_XLocaltime(&t, localtime_buf);
1320 sdelta = tm1.tm_hour * hrsec + tm1.tm_min * minsec + tm1.tm_sec;
1323 if ((tick = next_nmonth(t, ntimes)) == EOT || tick < 0)
1326 tm2 = *_XLocaltime(&tick, localtime_buf);
1328 delta = tm1.tm_wday - tm2.tm_wday;
1332 ntick = tick + (((nth - 1) * 7 + delta) * daysec) + sdelta;
1334 if ((tick = next_nmonth(t, ntimes + 1)) == EOT || tick < 0)
1337 tm2 = *_XLocaltime(&tick, localtime_buf);
1339 delta = tm2.tm_wday - tm1.tm_wday;
1340 if (tm1.tm_wday >= tm2.tm_wday)
1343 ntick = tick - (delta * daysec) + sdelta;
1345 ntick = adjust_dst(tick, ntick);
1351 nextnthweekday(time_t t, int nth)
1357 _Xltimeparams localtime_buf;
1360 * if nth is not specified, assume it's the
1361 * 4th week for the ambiguous case.
1364 nthweekdayofmonth(t, &nth);
1369 tm1 = *_XLocaltime(&t, localtime_buf);
1370 sdelta = tm1.tm_hour * hrsec + tm1.tm_min * minsec + tm1.tm_sec;
1373 tick = next_nmonth(t, 1);
1374 tm2 = *_XLocaltime(&tick, localtime_buf);
1376 delta = tm1.tm_wday - tm2.tm_wday;
1380 ntick = tick + (((nth - 1) * 7 + delta) * daysec) + sdelta;
1382 tick = next_nmonth(t, 2);
1383 tm2 = *_XLocaltime(&tick, localtime_buf);
1385 delta = tm2.tm_wday - tm1.tm_wday;
1386 if (tm1.tm_wday >= tm2.tm_wday)
1389 ntick = tick - (delta * daysec) + sdelta;
1391 ntick = adjust_dst(tick, ntick);
1397 prevnthweekday(time_t t, int nth)
1403 _Xltimeparams localtime_buf;
1406 * if nth is not specified, assume it's the
1407 * 4th week for the ambiguous case.
1410 nthweekdayofmonth(t, &nth);
1415 tm1 = *_XLocaltime(&t, localtime_buf);
1416 sdelta = tm1.tm_hour * hrsec + tm1.tm_min * minsec + tm1.tm_sec;
1419 tick = prev_nmonth(t, 1);
1420 tm2 = *_XLocaltime(&tick, localtime_buf);
1422 delta = tm1.tm_wday - tm2.tm_wday;
1426 ptick = tick + (((nth - 1) * 7 + delta) * daysec) + sdelta;
1428 tick = prev_nmonth(next_nmonth(t, 1), 1);
1429 tm2 = *_XLocaltime(&tick, localtime_buf);
1431 delta = tm2.tm_wday - tm1.tm_wday;
1432 if (tm1.tm_wday >= tm2.tm_wday)
1435 ptick = tick - (delta * daysec) + sdelta;
1437 ptick = adjust_dst(tick, ptick);
1442 /* use double in this routine to avoid integer overflow
1443 * in case n is very large.
1446 nextnday_exacttime(time_t t, int n)
1450 next = t + (double)n * daysec;
1451 if (next >= EOT || next < 0)
1454 next = adjust_dst(t, (time_t)next);
1455 return((time_t)next);
1460 * This is defined in the private library and is used also by the front
1461 * end -- should it be here?
1464 prevnday_exacttime(time_t t, int n)
1468 prev = t - (n * daysec);
1469 prev = adjust_dst(t, prev);
1473 /* use double in this routine to avoid integer overflow
1474 * in case n is very large.
1477 nextnwk_exacttime(time_t t, int n)
1481 next = t + (double)n * 7 * daysec;
1482 if (next >= EOT || next < 0)
1485 next = adjust_dst(t, (time_t)next);
1486 return((time_t)next);
1491 prevnwk_exacttime(time_t t, int n)
1495 prev = t - n * 7 * daysec;
1496 prev = adjust_dst(t, prev);
1501 nextnmth_exactday(time_t t, int n)
1504 boolean_t done = B_FALSE;
1506 _Xltimeparams localtime_buf;
1508 tm1 = *_XLocaltime(&t, localtime_buf);
1510 if ((next = next_nmonth(t, n)) == EOT || next < 0)
1513 tm2 = *_XLocaltime(&next, localtime_buf);
1515 /* 1. at least 30 days except feb
1516 * 2. 2/29 on leap year
1517 * 3. 31st on the appropriate month
1519 if ((tm1.tm_mday < 31 && tm2.tm_mon != 1) ||
1520 (tm2.tm_mon == 1 && (tm1.tm_mday < 29 ||
1521 (tm1.tm_mday == 29 && leapyr(tm2.tm_year + 1900)))) ||
1522 (tm1.tm_mday == 31 && ((tm2.tm_mon > 6 && tm2.tm_mon % 2) ||
1523 ((tm2.tm_mon <= 6 && (tm2.tm_mon % 2 == 0)))))) {
1524 tm2.tm_sec = tm1.tm_sec;
1525 tm2.tm_min = tm1.tm_min;
1526 tm2.tm_hour = tm1.tm_hour;
1527 tm2.tm_mday = tm1.tm_mday;
1535 next = mktime(&tm2);
1537 next = (timelocal(&tm2));
1543 prevnmth_exactday(time_t t, int n)
1546 boolean_t done = B_FALSE;
1548 _Xltimeparams localtime_buf;
1550 tm1 = *_XLocaltime(&t, localtime_buf);
1552 prev = prev_nmonth(t, n);
1553 tm2 = *_XLocaltime(&prev, localtime_buf);
1555 if ((tm1.tm_mday < 30 && tm2.tm_mon != 1) ||
1556 (tm2.tm_mon == 1 && (tm1.tm_mday < 29 ||
1557 (tm1.tm_mday == 29 && leapyr(tm2.tm_year + 1900)))) ||
1558 (tm1.tm_mday == 31 && ((tm2.tm_mon > 6 && tm2.tm_mon % 2) ||
1559 ((tm2.tm_mon <= 6 && (tm2.tm_mon % 2 == 0)))))) {
1560 tm2.tm_sec = tm1.tm_sec;
1561 tm2.tm_min = tm1.tm_min;
1562 tm2.tm_hour = tm1.tm_hour;
1563 tm2.tm_mday = tm1.tm_mday;
1571 prev = mktime(&tm2);
1573 prev = (timelocal(&tm2));
1579 nextmonTofri(time_t t)
1583 _Xltimeparams localtime_buf;
1585 tm = _XLocaltime(&t, localtime_buf);
1587 if (tm->tm_wday < 5)
1588 next = t + (int)daysec;
1590 next = t + (int)daysec * (8 - tm->tm_wday);
1592 next = adjust_dst(t, next);
1597 prevmonTofri(time_t t)
1601 _Xltimeparams localtime_buf;
1603 tm = _XLocaltime(&t, localtime_buf);
1605 if (tm->tm_wday > 1)
1606 prev = t - (int)daysec;
1608 prev = t - (int)daysec * (2 + tm->tm_wday);
1610 prev = adjust_dst(t, prev);
1615 nextmonwedfri(time_t t)
1619 _Xltimeparams localtime_buf;
1621 tm = _XLocaltime(&t, localtime_buf);
1623 if (tm->tm_wday == 5)
1624 next = t + (int)daysec * 3;
1625 else if (tm->tm_wday % 2 || tm->tm_wday == 6)
1626 next = t + (int)daysec * 2;
1628 next = t + (int)daysec;
1630 next = adjust_dst(t, next);
1635 prevmonwedfri(time_t t)
1639 _Xltimeparams localtime_buf;
1641 tm = _XLocaltime(&t, localtime_buf);
1643 if (tm->tm_wday == 1)
1644 prev = t - (int)daysec * 3;
1645 else if (tm->tm_wday % 2 || tm->tm_wday == 0)
1646 prev = t - (int)daysec * 2;
1648 prev = t - (int)daysec;
1650 prev = adjust_dst(t, prev);
1655 nexttuethur(time_t t)
1659 _Xltimeparams localtime_buf;
1661 tm = _XLocaltime(&t, localtime_buf);
1663 if (tm->tm_wday < 4) {
1664 if (tm->tm_wday % 2)
1665 next = t + (int)daysec;
1667 next = t + (int)daysec * 2;
1669 next = t + (int)daysec * (9 - tm->tm_wday);
1671 next = adjust_dst(t, next);
1676 prevtuethur(time_t t)
1680 _Xltimeparams localtime_buf;
1682 tm = _XLocaltime(&t, localtime_buf);
1684 if (tm->tm_wday > 2) {
1685 if (tm->tm_wday % 2)
1686 prev = t - (int)daysec;
1688 prev = t - (int)daysec * 2;
1690 prev = t - (int)daysec * (3 + tm->tm_wday);
1692 prev = adjust_dst(t, prev);
1697 * the 7-bit mask should be put in the last 7 bits of the int
1700 nextdaysofweek(time_t t, int weekmask)
1702 unsigned int doublemask;
1704 int i, ndays, daymask;
1706 _Xltimeparams localtime_buf;
1708 doublemask = weekmask | (weekmask << 7);
1709 tm = _XLocaltime(&t, localtime_buf);
1710 daymask = weekdaymasks[tm->tm_wday] << 1;
1712 for (i = 0, ndays = 1; i < 7; i++) {
1713 if (daymask & doublemask)
1721 next = t + (int)daysec * ndays;
1722 next = adjust_dst(t, next);
1727 prevdaysofweek(time_t t, int weekmask)
1729 unsigned int doublemask, daymask;
1733 _Xltimeparams localtime_buf;
1735 doublemask = weekmask | (weekmask << 7);
1736 tm = _XLocaltime(&t, localtime_buf);
1737 daymask = weekdaymasks[tm->tm_wday] << 6;
1739 for (i = 0, ndays = 1; i < 7; i++) {
1740 if (daymask & doublemask)
1748 prev = t - (int)daysec * ndays;
1749 prev = adjust_dst(t, prev);