1 /* $XConsortium: repeat.c /main/7 1996/11/21 19:46:39 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.
11 #define XOS_USE_NO_LOCKING
12 #define X_INCLUDE_TIME_H
13 #include <X11/Xos_r.h>
21 #define EOT 2147483647
25 static time_t bot, eot;
37 static unsigned int weekdaymasks[] = {
47 static int monthsecs[12] = {
48 31*daysec, 28*daysec, 31*daysec,
49 30*daysec, 31*daysec, 30*daysec,
50 31*daysec, 31*daysec, 30*daysec,
51 31*daysec, 30*daysec, 31*daysec
54 extern int monthdays[12] = {
61 static int lastapptofweek(u_int mask);
62 static int ntimes_this_week(u_int weekmask, int firstday);
63 static boolean_t nthweekdayofmonth(time_t t, int *nth);
64 static time_t next_nmonth(time_t t, int n);
65 static int adjust_dst(time_t start, time_t next);
66 static time_t prev_nmonth(time_t t, int n);
67 static time_t nextnyear(time_t t, int n);
68 static int timeok(time_t t);
69 static time_t prevnyear(time_t t, int n);
70 static time_t prevmonth_exactday(time_t t);
71 static time_t nextmonth_exactday(time_t t);
72 static time_t previousmonth(time_t t);
73 static int monthseconds(time_t t);
74 static int get_ndelta(time_t startdate, Period_4 period, int ntimes);
75 static time_t lastnthweekday(time_t t, int nth, int ntimes);
76 static time_t nextnthweekday(time_t t, int nth);
77 static time_t prevnthweekday(time_t t, int nth);
78 static time_t nextnday_exacttime(time_t t, int n);
79 static time_t prevnday_exacttime(time_t t, int n);
80 static time_t nextnwk_exacttime(time_t t, int n);
81 static time_t prevnwk_exacttime(time_t t, int n);
82 static time_t nextnmth_exactday(time_t t, int n);
83 static time_t prevnmth_exactday(time_t t, int n);
84 static time_t nextmonTofri(time_t t);
85 static time_t prevmonTofri(time_t t);
86 static time_t nextmonwedfri(time_t t);
87 static time_t prevmonwedfri(time_t t);
88 static time_t nexttuethur(time_t t);
89 static time_t prevtuethur(time_t t);
90 static time_t nextdaysofweek(time_t t, int weekmask);
91 static time_t prevdaysofweek(time_t t, int weekmask);
94 * cm now supports to up end of 1999. This is due to the limitation
95 * of cm_getdate() which can only handle up to end of 1999.
96 * When cm_getdate() is improved to handle up to the system limit,
97 * definitions of eot and EOT need to be changed as well as some
98 * of the routines in this file and the caller of these routines.
105 _Xltimeparams localtime_buf;
106 _Xgtimeparams gmtime_buf;
113 /* Fix for QAR 31607 */
114 if (getenv("TZ") == NULL){
116 tzptr = malloc(strlen(tzname[0]) + strlen(tzname[1]) + 10);
117 sprintf (tzptr,"TZ=%s%d%s", tzname[0], timezone/3600, tzname[1]);
126 tm = *_XLocaltime(&t, localtime_buf);
127 gm = *_XGmtime(&t, gmtime_buf);
129 bot = mktime(&gm) - mktime(&tm);
136 tm.tm_year =137; /* Dec. 31, 2037 */
142 _DtCms_adjust_appt_startdate(Appt_4 *appt)
145 _Xltimeparams localtime_buf;
147 if (appt->period.period < monThruFri_4 ||
148 appt->period.period > tueThur_4)
151 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
152 switch (appt->period.period) {
154 if (tm->tm_wday < 1 || tm->tm_wday > 5)
155 appt->appt_id.tick = _DtCms_next_tick_v4(
160 if ((tm->tm_wday % 2) == 0)
161 appt->appt_id.tick = _DtCms_next_tick_v4(
166 if (tm->tm_wday != 2 && tm->tm_wday != 4)
167 appt->appt_id.tick = _DtCms_next_tick_v4(
175 * Calculate the actual number of instances of the repeating event.
178 _DtCms_get_ninstance_v4(Appt_4 *appt)
181 int i, pdelta, ndelta, ninstance, timesperweek;
183 _Xltimeparams localtime_buf;
185 if (appt->ntimes == _DtCM_OLD_REPEAT_FOREVER)
186 return(appt->ntimes);
188 switch (appt->period.period) {
191 case everyNthMonth_4:
192 ninstance = (appt->ntimes+(appt->period.nth-1))/appt->period.nth;
196 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
197 pdelta = 6 - tm->tm_wday;
198 ndelta = get_ndelta(appt->appt_id.tick, appt->period,
200 dninstance = (double)(appt->ntimes - 1) * 5 + pdelta - ndelta;
201 ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER) ?
202 _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
206 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
207 pdelta = (7 - tm->tm_wday) / 2;
208 ndelta = get_ndelta(appt->appt_id.tick, appt->period,
210 dninstance = (double)(appt->ntimes - 1) * 3 + pdelta - ndelta;
211 ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER)
212 ? _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
216 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
217 pdelta = (tm->tm_wday == 2) ? 2 : 1;
218 ndelta = get_ndelta(appt->appt_id.tick, appt->period,
220 dninstance = (double)(appt->ntimes - 1) * 2 + pdelta - ndelta;
221 ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER) ?
222 _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
226 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
227 timesperweek = ntimes_this_week((u_int)appt->period.nth, 0);
228 pdelta = ntimes_this_week((u_int)appt->period.nth, tm->tm_wday);
229 ndelta = get_ndelta(appt->appt_id.tick, appt->period,
231 dninstance = (double)(appt->ntimes-1) * timesperweek +
233 ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER) ?
234 _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
238 ninstance = appt->ntimes;
245 * calculate the ntimes value which, depending on the
246 * repeating event type, may not be the same
247 * as the actual number of instances
250 _DtCms_get_new_ntimes_v4(Period_4 period, time_t tick, int ninstance)
254 int delta = 0, firstweek, timesperweek;
255 _Xltimeparams localtime_buf;
257 switch (period.period) {
260 case everyNthMonth_4:
261 ntimes = ninstance * period.nth;
264 tm = _XLocaltime(&tick, localtime_buf);
266 delta = ((ninstance % 5) > (6 - tm->tm_wday)) ? 2 : 1;
267 else if (tm->tm_wday != 1)
269 ntimes = (ninstance/5) + delta;
272 tm = _XLocaltime(&tick, localtime_buf);
274 delta = ((ninstance % 3) > ((7-tm->tm_wday)/2)) ? 2:1;
275 else if (tm->tm_wday != 1)
277 ntimes = (ninstance/3) + delta;
280 tm = _XLocaltime(&tick, localtime_buf);
281 if (ninstance % 2 || tm->tm_wday != 2)
283 ntimes = (ninstance/2) + delta;
286 tm = _XLocaltime(&tick, localtime_buf);
287 timesperweek = ntimes_this_week((u_int)period.nth, 0);
288 firstweek=ntimes_this_week((u_int)period.nth,tm->tm_wday);
289 if (ninstance % timesperweek)
290 delta = ((ninstance % timesperweek) > firstweek) ? 2:1;
291 else if (firstweek != timesperweek)
293 ntimes = (ninstance/timesperweek) + delta;
304 _DtCms_first_tick_v4(time_t t, Period_4 period, int ordinal)
310 for (i = 1; i < ordinal; i++)
311 ftick = _DtCms_prev_tick_v4(ftick, period);
318 * Given a time, calculate the closest instance whose
319 * tick is later than the time.
320 * If the calculated tick does not pass timeok(), ftick is
321 * returned and ordinal set to 1.
324 _DtCms_closest_tick_v4(time_t target, time_t ftick, Period_4 period, int *ordinal)
332 _Xltimeparams localtime_buf;
334 if (target <= ftick) {
339 if (period.period < monthly_4 || period.period == everyNthDay_4 ||
340 period.period == everyNthWeek_4) {
341 tm1 = *_XLocaltime(&ftick, localtime_buf);
342 tm2 = *_XLocaltime(&target, localtime_buf);
344 switch(period.period) {
346 delta = (target - ftick) / daysec;
347 remainder = target - ftick - daysec * delta;
348 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
350 *ordinal = delta + (remainder>0?1:0) + 1;
351 ctick = nextnday_exacttime(ftick, *ordinal - 1);
354 delta = (target - ftick) / wksec;
355 remainder = target - ftick - wksec * delta;
356 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
358 *ordinal = delta + (remainder>0?1:0) + 1;
359 ctick = nextnwk_exacttime(ftick, *ordinal - 1);
362 delta = (target - ftick) / (wksec * 2);
363 remainder = target - ftick - wksec * 2 * 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, 2 * (*ordinal - 1));
370 tm = _XLocaltime(&ftick, localtime_buf);
372 * Calculate the closest tick only if the date
373 * is < 29; otherwise just return the first tick.
374 * Use 32 to take care of dst time difference.
375 * Without dst, we can use 31.
377 if (tm->tm_mday < 29) {
378 delta = (target - ftick) / (daysec * 32);
379 remainder = target - ftick - (daysec * 32) * delta;
380 *ordinal = delta + (remainder>0?1:0) + 1;
381 ctick = nextnmth_exactday(ftick, *ordinal - 1);
388 tm = _XLocaltime(&ftick, localtime_buf);
389 if (tm->tm_mday == 29 && tm->tm_mon == 1) {
390 delta = (target - ftick) / (yrsec * 4 + daysec);
391 remainder = target - ftick - (yrsec * 4) * delta;
392 *ordinal = delta + (remainder>0?1:0) + 1;
393 ctick = nextnyear(ftick, (*ordinal - 1) * 4);
395 delta = (target - ftick) / yrsec;
396 /* adjustment for leap year */
397 remainder = tm->tm_year % 4;
398 if (remainder == 0 || (remainder + delta) > 3)
400 remainder = target - ftick - yrsec * delta;
401 *ordinal = delta + (remainder>0?1:0) + 1;
402 ctick = nextnyear(ftick, *ordinal - 1);
406 /* 36 is 5 weeks ==> maximum interval between 2 instances */
407 delta = (target - ftick) / (daysec * 36);
408 remainder = target - ftick - (daysec * 36) * delta;
409 *ordinal = delta + (remainder>0?1:0) + 1;
410 ctick = lastnthweekday(ftick, period.nth, *ordinal - 1);
413 delta = (target - ftick) / (daysec * period.nth);
414 remainder = target - ftick - (daysec * period.nth) * delta;
415 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
417 *ordinal = delta + (remainder>0?1:0) + 1;
418 ctick = nextnday_exacttime(ftick,
419 period.nth * (*ordinal - 1));
422 delta = (target - ftick) / (wksec * period.nth);
423 remainder = target - ftick - (wksec * period.nth) * delta;
424 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
426 *ordinal = delta + (remainder>0?1:0) + 1;
427 ctick = nextnwk_exacttime(ftick,
428 period.nth * (*ordinal - 1));
430 case everyNthMonth_4:
431 tm = _XLocaltime(&ftick, localtime_buf);
432 if (tm->tm_mday < 29) {
433 delta = (target - ftick) / (daysec * 32 * period.nth);
434 remainder = target-ftick-(daysec*32*period.nth)*delta;
435 *ordinal = delta + (remainder>0?1:0) + 1;
436 ctick = nextnmth_exactday(ftick,
437 period.nth * (*ordinal - 1));
447 delta = (target - ftick) / wksec;
448 tm = _XLocaltime(&ftick, localtime_buf);
450 switch (period.period) {
452 *ordinal = delta * 5 + 6 - tm->tm_wday;
455 *ordinal = delta * 3 + (7 - tm->tm_wday) / 2;
458 *ordinal = delta * 2 + ((tm->tm_wday == 2) ? 2 : 1);
461 *ordinal = delta * ntimes_this_week((u_int)period.nth,0)
462 + ntimes_this_week((u_int)period.nth,
466 /* delta*daysperweek+(lastapptofweek-firstday in first week) */
467 if (period.period == daysOfWeek_4) {
469 lastapptofweek((u_int)period.nth) - tm->tm_wday;
470 ctick = ftick + ndays * daysec;
471 } else if (period.period == tueThur_4) {
472 ndays = delta * 7 + 4 - tm->tm_wday;
473 ctick = ftick + ndays * daysec;
475 ndays = delta * 7 + 5 - tm->tm_wday;
476 ctick = ftick + ndays * daysec;
479 if (ctick > target) { /* need to go back 1 week */
485 if (period.period == monThruFri_4)
487 else if (period.period == monWedFri_4)
489 else if (period.period == tueThur_4)
491 ctick -= (7 * daysec);
494 ctick = adjust_dst(ftick, ctick);
510 * Calculate the tick of the last instance of a repeating event.
511 * If the calculated tick does not pass timeok(), EOT is returned.
514 _DtCms_last_tick_v4(time_t ftick, Period_4 period, int ntimes)
520 _Xltimeparams localtime_buf;
522 if (ntimes >= _DtCM_OLD_REPEAT_FOREVER)
525 if (period.enddate != 0)
526 return(period.enddate);
528 switch(period.period) {
530 ltick = nextnwk_exacttime(ftick, ntimes - 1);
533 /* 2 * (ntimes-1) won't overflow an integer since
534 * we make sure ntimes is < EOT
536 ltick = nextnwk_exacttime(ftick, 2 * (ntimes - 1));
539 ltick = nextnday_exacttime(ftick, ntimes - 1);
542 tm = _XLocaltime(&ftick, localtime_buf);
544 * calculate the last tick only if the date
545 * is < 29; otherwise return EOT to force calculation
547 if (tm->tm_mday < 29)
548 ltick = nextnmth_exactday(ftick, ntimes - 1);
553 /* 2038 is the last year that can be represented.
554 * this check is to prevent (ntimes-1)*4 from integer overflow
559 tm = _XLocaltime(&ftick, localtime_buf);
560 if (tm->tm_mday == 29 && tm->tm_mon == 1)
561 ltick = nextnyear(ftick, (ntimes - 1) * 4);
563 ltick = nextnyear(ftick, ntimes - 1);
567 ltick = lastnthweekday(ftick, period.nth, ntimes - 1);
570 ltick = nextnday_exacttime(ftick, period.nth *
571 (((ntimes+(period.nth-1))/period.nth) - 1));
574 ltick = nextnwk_exacttime(ftick, period.nth *
575 (((ntimes+(period.nth-1))/period.nth) - 1));
577 case everyNthMonth_4:
578 tm = _XLocaltime(&ftick, localtime_buf);
579 if (tm->tm_mday < 29)
580 ltick = nextnmth_exactday(ftick, period.nth *
581 (((ntimes+(period.nth-1))/period.nth) -1));
589 tm = _XLocaltime(&ftick, localtime_buf);
591 /* (ntimes-1)*daysperweek+(lastapptofweek-fstapptofFstweek) */
592 if (period.period == daysOfWeek_4)
594 ((double)(ntimes - 1) * 7 +
595 lastapptofweek((u_int)period.nth) - tm->tm_wday)
597 else if (period.period == tueThur_4)
599 ((double)(ntimes - 1) * 7 + (4 - tm->tm_wday)) *
603 ((double)(ntimes - 1) * 7 + (5 - tm->tm_wday)) *
606 if (dltick >= EOT || dltick < 0)
609 ltick = adjust_dst(ftick, (time_t)dltick);
621 * Calculate the tick of next instance.
622 * If the calculated tick does not pass timeok(), EOT is returned.
625 _DtCms_next_tick_v4(time_t tick, Period_4 period)
629 _Xltimeparams localtime_buf;
631 switch(period.period) {
633 next = nextnwk_exacttime(tick, 1);
636 next = nextnwk_exacttime(tick, 2);
639 next = nextnday_exacttime(tick, 1);
642 next = nextmonth_exactday(tick);
645 tm = _XLocaltime(&tick, localtime_buf);
646 if (tm->tm_mday == 29 && tm->tm_mon == 1)
647 next = nextnyear(tick, 4);
649 next = nextnyear(tick, 1);
652 next = nextnthweekday(tick, period.nth);
655 next = nextnday_exacttime(tick, period.nth);
658 next = nextnwk_exacttime(tick, period.nth);
660 case everyNthMonth_4:
661 next = nextnmth_exactday(tick, period.nth);
664 next = nextmonTofri(tick);
667 next = nextmonwedfri(tick);
670 next = nexttuethur(tick);
673 next = nextdaysofweek(tick, period.nth);
678 if(next != tick && timeok(next)) return(next);
683 * Calculate the tick of previous instance.
684 * If the calculated tick does not pass timeok(), bot-1 is returned.
687 _DtCms_prev_tick_v4(time_t tick, Period_4 period)
691 _Xltimeparams localtime_buf;
693 switch(period.period) {
695 prev = prevnwk_exacttime(tick, 1);
698 prev = prevnwk_exacttime(tick, 2);
701 prev = prevnday_exacttime(tick, 1);
704 prev = prevmonth_exactday(tick);
707 tm = _XLocaltime(&tick, localtime_buf);
708 if (tm->tm_mday == 29 && tm->tm_mon == 1)
709 prev = prevnyear(tick, 4);
711 prev = prevnyear(tick, 1);
714 prev = prevnthweekday(tick, period.nth);
717 prev = prevnday_exacttime(tick, period.nth);
720 prev = prevnwk_exacttime(tick, period.nth);
722 case everyNthMonth_4:
723 prev = prevnmth_exactday(tick, period.nth);
726 prev = prevmonTofri(tick);
729 prev = prevmonwedfri(tick);
732 prev = prevtuethur(tick);
735 prev = prevdaysofweek(tick, period.nth);
740 if(prev != tick && timeok(prev)) return(prev);
746 * TRUE - it is a match regard_DtCmsIsLess the event is cancelled,
747 * FALSE - it is not a match if the event is cancelled.
750 _DtCms_in_repeater(Id_4 *key, Appt_4 *p_appt, boolean_t dont_care_cancel)
757 ntimes = _DtCms_get_ninstance_v4(p_appt);
758 period = p_appt->period;
759 tick = _DtCms_closest_tick_v4(key->tick, p_appt->appt_id.tick, period, &ordinal);
761 while (++ordinal <= ntimes)
763 if (tick > key->tick) /* out-of-bound */
765 if (tick == key->tick)
767 if (dont_care_cancel)
769 if (!_DtCms_marked_4_cancellation (p_appt, ordinal))
772 tick = _DtCms_next_tick_v4 (tick, period);
779 _DtCms_marked_4_cancellation(Appt_4 *a, int i)
786 p = a->exception; /* in descending order for faster access */
798 next_ndays(time_t t, int n)
802 _Xltimeparams localtime_buf;
804 tm = *_XLocaltime(&t, localtime_buf);
812 next = timelocal(&tm);
814 next = next + n * daysec;
815 next = adjust_dst(t, next);
820 next_nmins(time_t t, int m)
824 _Xltimeparams localtime_buf;
826 tm = *_XLocaltime(&t, localtime_buf);
831 next = next + m * minsec;
832 next = adjust_dst(t, next);
837 _DtCmsBeginOfDay(time_t t)
840 _Xltimeparams localtime_buf;
842 tm = *_XLocaltime(&t, localtime_buf);
850 _DtCmsTimeOfDay(time_t t)
853 _Xltimeparams localtime_buf;
855 tm = *_XLocaltime(&t, localtime_buf);
859 return(t - mktime(&tm));
863 * Given a weekmask, find the last appointment in the week
866 lastapptofweek(u_int mask)
873 for (n = -1; mask != 0; n++, mask = mask >> 1);
879 * Given a weekmask and the first day of the week, calculate
880 * the number of times outstanding in the week.
883 ntimes_this_week(u_int weekmask, int firstday)
885 int i, ntimes, weekdaymask = 1 << firstday;
890 for (i=firstday, ntimes=0; i < 7; i++, weekdaymask <<= 1) {
891 if (weekdaymask & weekmask)
898 nthweekdayofmonth(time_t t, int *nth)
900 struct tm tm, tm2, tmfirstday;
902 _Xltimeparams localtime_buf;
904 tmfirstday = tm = *_XLocaltime(&t, localtime_buf);
906 *nth = (12 + tm.tm_mday - tm.tm_wday)/7;
908 tmfirstday.tm_hour = 0;
909 tmfirstday.tm_min = 0;
910 tmfirstday.tm_sec = 0;
911 tmfirstday.tm_mday = 1;
912 firstday = mktime(&tmfirstday);
913 tmfirstday = *_XLocaltime(&firstday, localtime_buf);
915 if (tm.tm_wday < tmfirstday.tm_wday)
922 tm2 = *_XLocaltime(&t, localtime_buf);
924 return((tm.tm_mon == tm2.tm_mon) ? B_FALSE : B_TRUE);
929 * If the result falls beyond the system limit, -1 is returned by mktime().
932 next_nmonth(time_t t, int n)
936 _Xltimeparams localtime_buf;
941 tm = *_XLocaltime(&t, localtime_buf);
949 if ((tm.tm_mon = tm.tm_mon + n) > 11) {
959 adjust_dst(time_t start, time_t next)
963 _Xltimeparams localtime_buf;
965 oldt = *_XLocaltime(&start, localtime_buf);
966 newt = *_XLocaltime(&next, localtime_buf);
968 if (oldt.tm_isdst == newt.tm_isdst) {
970 } else if (oldt.tm_isdst == 1) {
971 return (next + (int)hrsec);
973 return (next - (int)hrsec);
978 prev_nmonth(time_t t, int n)
982 _Xltimeparams localtime_buf;
987 tm = *_XLocaltime(&t, localtime_buf);
995 if ((tm.tm_mon = tm.tm_mon - n) < 0) {
1001 return(mktime(&tm));
1003 return(timelocal(&tm));
1011 (y % 4 == 0 && y % 100 !=0 || y % 400 == 0);
1019 _Xltimeparams localtime_buf;
1021 tm = *_XLocaltime(&t, localtime_buf);
1023 return(((mon==1) && leapyr(tm.tm_year+1900))? 29 : monthdays[mon]);
1026 extern int /* find dow(0-6) that 1st dom falls on */
1030 _Xltimeparams localtime_buf;
1032 tm = *_XLocaltime(&t, localtime_buf);
1036 tm = *_XLocaltime(&t, localtime_buf);
1041 ldom(Tick t /* find dow(0-6) that last dom falls on */ )
1044 _Xltimeparams localtime_buf;
1046 tm = *_XLocaltime(&t, localtime_buf);
1047 tm.tm_mday = monthlength(t);
1050 tm = *_XLocaltime(&t, localtime_buf);
1055 _DtCmsInExceptionList(cms_entry *eptr, time_t tick)
1057 CSA_date_time_entry *dt = NULL;
1060 if (eptr->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value)
1061 dt = eptr->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value->\
1062 item.date_time_list_value;
1064 for (; dt != NULL; dt = dt->next) {
1065 if (_csa_iso8601_to_tick(dt->date_time, &time))
1076 nextnyear(time_t t, int n)
1079 _Xltimeparams localtime_buf;
1081 tm = *_XLocaltime(&t, localtime_buf);
1084 return(mktime(&tm));
1086 return(timelocal(&tm));
1093 int r =((t >= bot) &&(t <= eot));
1098 prevnyear(time_t t, int n)
1101 _Xltimeparams localtime_buf;
1103 tm = *_XLocaltime(&t, localtime_buf);
1106 return(mktime(&tm));
1108 return(timelocal(&tm));
1113 prevmonth_exactday(time_t t)
1115 time_t prev; int day;
1118 _Xltimeparams localtime_buf;
1120 tm = *_XLocaltime(&t, localtime_buf);
1121 sdelta = tm.tm_hour * hrsec + tm.tm_min * minsec + tm.tm_sec;
1123 if((tm.tm_mday < 31 && tm.tm_mon != 0) || /* at least 30 days everywhere, except Feb.*/
1124 (tm.tm_mday==31 && tm.tm_mon==6) || /* two 31s -- Jul./Aug. */
1125 (tm.tm_mday==31 && tm.tm_mon==11) || /* two 31s -- Dec./Jan. */
1126 (tm.tm_mon == 0 &&(tm.tm_mday < 29 ||(tm.tm_mday==29 && leapyr(tm.tm_year+1900))))) {
1127 prev = t-monthseconds(previousmonth(t));
1128 prev = adjust_dst(t, prev);
1130 else { /* brute force */
1131 prev = previousmonth(previousmonth(t)); /* hop over the month */
1132 tm = *_XLocaltime(&prev, localtime_buf);
1136 prev =(mktime(&tm)) + sdelta;
1138 prev =(timelocal(&tm)) + sdelta;
1146 nextmonth_exactday(time_t t)
1148 time_t next; int day;
1151 _Xltimeparams localtime_buf;
1153 tm = *_XLocaltime(&t, localtime_buf);
1154 sdelta = tm.tm_hour * hrsec + tm.tm_min * minsec + tm.tm_sec;
1156 if((tm.tm_mday < 31 && tm.tm_mon != 0) || /* at least 30 days everywhere, except Feb.*/
1157 (tm.tm_mday==31 && tm.tm_mon==6) || /* two 31s -- Jul./Aug. */
1158 (tm.tm_mday==31 && tm.tm_mon==11) || /* two 31s -- Dec./Jan. */
1159 (tm.tm_mon == 0 &&(tm.tm_mday < 29 ||(tm.tm_mday==29 && leapyr(tm.tm_year+1900))))) {
1160 next = t+monthseconds(t);
1161 next = adjust_dst(t, next);
1163 else { /* brute force */
1164 next = next_nmonth(t, 2); /* hop over the month */
1165 tm = *_XLocaltime(&next, localtime_buf);
1169 next = mktime(&tm) + sdelta;
1171 next =(timelocal(&tm)) + sdelta;
1178 previousmonth(time_t t)
1181 _Xltimeparams localtime_buf;
1183 tm = *_XLocaltime(&t, localtime_buf);
1198 return(mktime(&tm));
1200 return(timelocal(&tm));
1205 monthseconds(time_t t)
1209 _Xltimeparams localtime_buf;
1211 tm = *_XLocaltime(&t, localtime_buf);
1213 return(((mon==1) && leapyr(tm.tm_year+1900)) ?
1214 29*daysec : monthsecs[mon]);
1218 * find the number of instances to be subtracted
1221 get_ndelta(time_t startdate, Period_4 period, int ntimes)
1227 _Xltimeparams localtime_buf;
1229 if (period.enddate == 0)
1232 /* find last day of the series */
1233 dlastdate = startdate + (double)wksec * (ntimes - 1); /* last week */
1234 if (dlastdate > EOT)
1237 lastdate = (time_t)dlastdate;
1239 tm = _XLocaltime(&lastdate, localtime_buf);
1240 if (period.period == monThruFri_4 || period.period == monWedFri_4)
1241 lastdate = lastdate + daysec * (5 - tm->tm_wday);
1242 else if (period.period == tueThur_4)
1243 lastdate = lastdate + daysec * (4 - tm->tm_wday);
1244 else if (period.period == daysOfWeek_4)
1245 lastdate = lastdate + daysec *
1246 (lastapptofweek((u_int)period.nth) - tm->tm_wday);
1248 if (period.enddate > lastdate)
1251 tm = _XLocaltime(&period.enddate, localtime_buf);
1252 switch (period.period) {
1254 ndelta = 5 - tm->tm_wday;
1257 if (tm->tm_wday < 3)
1259 else if (tm->tm_wday < 5)
1263 if (tm->tm_wday < 2)
1265 else if (tm->tm_wday < 4)
1269 ndelta = ntimes_this_week((u_int)period.nth, tm->tm_wday) - 1;
1276 lastnthweekday(time_t t, int nth, int ntimes)
1282 _Xltimeparams localtime_buf;
1285 * if nth is not specified, assume it's the
1286 * 4th week for the ambiguous case.
1289 nthweekdayofmonth(t, &nth);
1294 tm1 = *_XLocaltime(&t, localtime_buf);
1295 sdelta = tm1.tm_hour * hrsec + tm1.tm_min * minsec + tm1.tm_sec;
1298 if ((tick = next_nmonth(t, ntimes)) == EOT || tick < 0)
1301 tm2 = *_XLocaltime(&tick, localtime_buf);
1303 delta = tm1.tm_wday - tm2.tm_wday;
1307 ntick = tick + (((nth - 1) * 7 + delta) * daysec) + sdelta;
1309 if ((tick = next_nmonth(t, ntimes + 1)) == EOT || tick < 0)
1312 tm2 = *_XLocaltime(&tick, localtime_buf);
1314 delta = tm2.tm_wday - tm1.tm_wday;
1315 if (tm1.tm_wday >= tm2.tm_wday)
1318 ntick = tick - (delta * daysec) + sdelta;
1320 ntick = adjust_dst(tick, ntick);
1326 nextnthweekday(time_t t, int nth)
1332 _Xltimeparams localtime_buf;
1335 * if nth is not specified, assume it's the
1336 * 4th week for the ambiguous case.
1339 nthweekdayofmonth(t, &nth);
1344 tm1 = *_XLocaltime(&t, localtime_buf);
1345 sdelta = tm1.tm_hour * hrsec + tm1.tm_min * minsec + tm1.tm_sec;
1348 tick = next_nmonth(t, 1);
1349 tm2 = *_XLocaltime(&tick, localtime_buf);
1351 delta = tm1.tm_wday - tm2.tm_wday;
1355 ntick = tick + (((nth - 1) * 7 + delta) * daysec) + sdelta;
1357 tick = next_nmonth(t, 2);
1358 tm2 = *_XLocaltime(&tick, localtime_buf);
1360 delta = tm2.tm_wday - tm1.tm_wday;
1361 if (tm1.tm_wday >= tm2.tm_wday)
1364 ntick = tick - (delta * daysec) + sdelta;
1366 ntick = adjust_dst(tick, ntick);
1372 prevnthweekday(time_t t, int nth)
1378 _Xltimeparams localtime_buf;
1381 * if nth is not specified, assume it's the
1382 * 4th week for the ambiguous case.
1385 nthweekdayofmonth(t, &nth);
1390 tm1 = *_XLocaltime(&t, localtime_buf);
1391 sdelta = tm1.tm_hour * hrsec + tm1.tm_min * minsec + tm1.tm_sec;
1394 tick = prev_nmonth(t, 1);
1395 tm2 = *_XLocaltime(&tick, localtime_buf);
1397 delta = tm1.tm_wday - tm2.tm_wday;
1401 ptick = tick + (((nth - 1) * 7 + delta) * daysec) + sdelta;
1403 tick = prev_nmonth(next_nmonth(t, 1), 1);
1404 tm2 = *_XLocaltime(&tick, localtime_buf);
1406 delta = tm2.tm_wday - tm1.tm_wday;
1407 if (tm1.tm_wday >= tm2.tm_wday)
1410 ptick = tick - (delta * daysec) + sdelta;
1412 ptick = adjust_dst(tick, ptick);
1417 /* use double in this routine to avoid integer overflow
1418 * in case n is very large.
1421 nextnday_exacttime(time_t t, int n)
1425 next = t + (double)n * daysec;
1426 if (next >= EOT || next < 0)
1429 next = adjust_dst(t, (time_t)next);
1430 return((time_t)next);
1435 * This is defined in the private library and is used also by the front
1436 * end -- should it be here?
1439 prevnday_exacttime(time_t t, int n)
1443 prev = t - (n * daysec);
1444 prev = adjust_dst(t, prev);
1448 /* use double in this routine to avoid integer overflow
1449 * in case n is very large.
1452 nextnwk_exacttime(time_t t, int n)
1456 next = t + (double)n * 7 * daysec;
1457 if (next >= EOT || next < 0)
1460 next = adjust_dst(t, (time_t)next);
1461 return((time_t)next);
1466 prevnwk_exacttime(time_t t, int n)
1470 prev = t - n * 7 * daysec;
1471 prev = adjust_dst(t, prev);
1476 nextnmth_exactday(time_t t, int n)
1479 boolean_t done = B_FALSE;
1481 _Xltimeparams localtime_buf;
1483 tm1 = *_XLocaltime(&t, localtime_buf);
1485 if ((next = next_nmonth(t, n)) == EOT || next < 0)
1488 tm2 = *_XLocaltime(&next, localtime_buf);
1490 /* 1. at least 30 days except feb
1491 * 2. 2/29 on leap year
1492 * 3. 31st on the appropriate month
1494 if ((tm1.tm_mday < 31 && tm2.tm_mon != 1) ||
1495 (tm2.tm_mon == 1 && (tm1.tm_mday < 29 ||
1496 (tm1.tm_mday == 29 && leapyr(tm2.tm_year + 1900)))) ||
1497 (tm1.tm_mday == 31 && ((tm2.tm_mon > 6 && tm2.tm_mon % 2) ||
1498 ((tm2.tm_mon <= 6 && (tm2.tm_mon % 2 == 0)))))) {
1499 tm2.tm_sec = tm1.tm_sec;
1500 tm2.tm_min = tm1.tm_min;
1501 tm2.tm_hour = tm1.tm_hour;
1502 tm2.tm_mday = tm1.tm_mday;
1510 next = mktime(&tm2);
1512 next = (timelocal(&tm2));
1518 prevnmth_exactday(time_t t, int n)
1521 boolean_t done = B_FALSE;
1523 _Xltimeparams localtime_buf;
1525 tm1 = *_XLocaltime(&t, localtime_buf);
1527 prev = prev_nmonth(t, n);
1528 tm2 = *_XLocaltime(&prev, localtime_buf);
1530 if ((tm1.tm_mday < 30 && tm2.tm_mon != 1) ||
1531 (tm2.tm_mon == 1 && (tm1.tm_mday < 29 ||
1532 (tm1.tm_mday == 29 && leapyr(tm2.tm_year + 1900)))) ||
1533 (tm1.tm_mday == 31 && ((tm2.tm_mon > 6 && tm2.tm_mon % 2) ||
1534 ((tm2.tm_mon <= 6 && (tm2.tm_mon % 2 == 0)))))) {
1535 tm2.tm_sec = tm1.tm_sec;
1536 tm2.tm_min = tm1.tm_min;
1537 tm2.tm_hour = tm1.tm_hour;
1538 tm2.tm_mday = tm1.tm_mday;
1546 prev = mktime(&tm2);
1548 prev = (timelocal(&tm2));
1554 nextmonTofri(time_t t)
1558 _Xltimeparams localtime_buf;
1560 tm = _XLocaltime(&t, localtime_buf);
1562 if (tm->tm_wday < 5)
1563 next = t + (int)daysec;
1565 next = t + (int)daysec * (8 - tm->tm_wday);
1567 next = adjust_dst(t, next);
1572 prevmonTofri(time_t t)
1576 _Xltimeparams localtime_buf;
1578 tm = _XLocaltime(&t, localtime_buf);
1580 if (tm->tm_wday > 1)
1581 prev = t - (int)daysec;
1583 prev = t - (int)daysec * (2 + tm->tm_wday);
1585 prev = adjust_dst(t, prev);
1590 nextmonwedfri(time_t t)
1594 _Xltimeparams localtime_buf;
1596 tm = _XLocaltime(&t, localtime_buf);
1598 if (tm->tm_wday == 5)
1599 next = t + (int)daysec * 3;
1600 else if (tm->tm_wday % 2 || tm->tm_wday == 6)
1601 next = t + (int)daysec * 2;
1603 next = t + (int)daysec;
1605 next = adjust_dst(t, next);
1610 prevmonwedfri(time_t t)
1614 _Xltimeparams localtime_buf;
1616 tm = _XLocaltime(&t, localtime_buf);
1618 if (tm->tm_wday == 1)
1619 prev = t - (int)daysec * 3;
1620 else if (tm->tm_wday % 2 || tm->tm_wday == 0)
1621 prev = t - (int)daysec * 2;
1623 prev = t - (int)daysec;
1625 prev = adjust_dst(t, prev);
1630 nexttuethur(time_t t)
1634 _Xltimeparams localtime_buf;
1636 tm = _XLocaltime(&t, localtime_buf);
1638 if (tm->tm_wday < 4) {
1639 if (tm->tm_wday % 2)
1640 next = t + (int)daysec;
1642 next = t + (int)daysec * 2;
1644 next = t + (int)daysec * (9 - tm->tm_wday);
1646 next = adjust_dst(t, next);
1651 prevtuethur(time_t t)
1655 _Xltimeparams localtime_buf;
1657 tm = _XLocaltime(&t, localtime_buf);
1659 if (tm->tm_wday > 2) {
1660 if (tm->tm_wday % 2)
1661 prev = t - (int)daysec;
1663 prev = t - (int)daysec * 2;
1665 prev = t - (int)daysec * (3 + tm->tm_wday);
1667 prev = adjust_dst(t, prev);
1672 * the 7-bit mask should be put in the last 7 bits of the int
1675 nextdaysofweek(time_t t, int weekmask)
1677 unsigned int doublemask;
1679 int i, ndays, daymask;
1681 _Xltimeparams localtime_buf;
1683 doublemask = weekmask | (weekmask << 7);
1684 tm = _XLocaltime(&t, localtime_buf);
1685 daymask = weekdaymasks[tm->tm_wday] << 1;
1687 for (i = 0, ndays = 1; i < 7; i++) {
1688 if (daymask & doublemask)
1696 next = t + (int)daysec * ndays;
1697 next = adjust_dst(t, next);
1702 prevdaysofweek(time_t t, int weekmask)
1704 unsigned int doublemask, daymask;
1708 _Xltimeparams localtime_buf;
1710 doublemask = weekmask | (weekmask << 7);
1711 tm = _XLocaltime(&t, localtime_buf);
1712 daymask = weekdaymasks[tm->tm_wday] << 6;
1714 for (i = 0, ndays = 1; i < 7; i++) {
1715 if (daymask & doublemask)
1723 prev = t - (int)daysec * ndays;
1724 prev = adjust_dst(t, prev);