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
35 #include <X11/Xos_r.h>
43 #define EOT 2147483647
47 static time_t bot, eot;
59 static unsigned int weekdaymasks[] = {
69 static int monthsecs[12] = {
70 31*daysec, 28*daysec, 31*daysec,
71 30*daysec, 31*daysec, 30*daysec,
72 31*daysec, 31*daysec, 30*daysec,
73 31*daysec, 30*daysec, 31*daysec
76 extern int monthdays[12] = {
83 static int lastapptofweek(u_int mask);
84 static int ntimes_this_week(u_int weekmask, int firstday);
85 static boolean_t nthweekdayofmonth(time_t t, int *nth);
86 static time_t next_nmonth(time_t t, int n);
87 static int adjust_dst(time_t start, time_t next);
88 static time_t prev_nmonth(time_t t, int n);
89 static time_t nextnyear(time_t t, int n);
90 static int timeok(time_t t);
91 static time_t prevnyear(time_t t, int n);
92 static time_t prevmonth_exactday(time_t t);
93 static time_t nextmonth_exactday(time_t t);
94 static time_t previousmonth(time_t t);
95 static int monthseconds(time_t t);
96 static int get_ndelta(time_t startdate, Period_4 period, int ntimes);
97 static time_t lastnthweekday(time_t t, int nth, int ntimes);
98 static time_t nextnthweekday(time_t t, int nth);
99 static time_t prevnthweekday(time_t t, int nth);
100 static time_t nextnday_exacttime(time_t t, int n);
101 static time_t prevnday_exacttime(time_t t, int n);
102 static time_t nextnwk_exacttime(time_t t, int n);
103 static time_t prevnwk_exacttime(time_t t, int n);
104 static time_t nextnmth_exactday(time_t t, int n);
105 static time_t prevnmth_exactday(time_t t, int n);
106 static time_t nextmonTofri(time_t t);
107 static time_t prevmonTofri(time_t t);
108 static time_t nextmonwedfri(time_t t);
109 static time_t prevmonwedfri(time_t t);
110 static time_t nexttuethur(time_t t);
111 static time_t prevtuethur(time_t t);
112 static time_t nextdaysofweek(time_t t, int weekmask);
113 static time_t prevdaysofweek(time_t t, int weekmask);
116 * cm now supports to up end of 1999. This is due to the limitation
117 * of cm_getdate() which can only handle up to end of 1999.
118 * When cm_getdate() is improved to handle up to the system limit,
119 * definitions of eot and EOT need to be changed as well as some
120 * of the routines in this file and the caller of these routines.
127 _Xltimeparams localtime_buf;
128 _Xgtimeparams gmtime_buf;
135 /* Fix for QAR 31607 */
136 if (getenv("TZ") == NULL){
138 tzptr = malloc(strlen(tzname[0]) + strlen(tzname[1]) + 10);
139 sprintf (tzptr,"TZ=%s%d%s", tzname[0], timezone/3600, tzname[1]);
148 tm = *_XLocaltime(&t, localtime_buf);
149 gm = *_XGmtime(&t, gmtime_buf);
151 bot = mktime(&gm) - mktime(&tm);
158 tm.tm_year =137; /* Dec. 31, 2037 */
164 _DtCms_adjust_appt_startdate(Appt_4 *appt)
167 _Xltimeparams localtime_buf;
169 if (appt->period.period < monThruFri_4 ||
170 appt->period.period > tueThur_4)
173 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
174 switch (appt->period.period) {
176 if (tm->tm_wday < 1 || tm->tm_wday > 5)
177 appt->appt_id.tick = _DtCms_next_tick_v4(
182 if ((tm->tm_wday % 2) == 0)
183 appt->appt_id.tick = _DtCms_next_tick_v4(
188 if (tm->tm_wday != 2 && tm->tm_wday != 4)
189 appt->appt_id.tick = _DtCms_next_tick_v4(
197 * Calculate the actual number of instances of the repeating event.
200 _DtCms_get_ninstance_v4(Appt_4 *appt)
203 int i, pdelta, ndelta, ninstance, timesperweek;
205 _Xltimeparams localtime_buf;
207 if (appt->ntimes == _DtCM_OLD_REPEAT_FOREVER)
208 return(appt->ntimes);
210 switch (appt->period.period) {
213 case everyNthMonth_4:
214 ninstance = (appt->ntimes+(appt->period.nth-1))/appt->period.nth;
218 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
219 pdelta = 6 - tm->tm_wday;
220 ndelta = get_ndelta(appt->appt_id.tick, appt->period,
222 dninstance = (double)(appt->ntimes - 1) * 5 + pdelta - ndelta;
223 ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER) ?
224 _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
228 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
229 pdelta = (7 - tm->tm_wday) / 2;
230 ndelta = get_ndelta(appt->appt_id.tick, appt->period,
232 dninstance = (double)(appt->ntimes - 1) * 3 + pdelta - ndelta;
233 ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER)
234 ? _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
238 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
239 pdelta = (tm->tm_wday == 2) ? 2 : 1;
240 ndelta = get_ndelta(appt->appt_id.tick, appt->period,
242 dninstance = (double)(appt->ntimes - 1) * 2 + pdelta - ndelta;
243 ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER) ?
244 _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
248 tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
249 timesperweek = ntimes_this_week((u_int)appt->period.nth, 0);
250 pdelta = ntimes_this_week((u_int)appt->period.nth, tm->tm_wday);
251 ndelta = get_ndelta(appt->appt_id.tick, appt->period,
253 dninstance = (double)(appt->ntimes-1) * timesperweek +
255 ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER) ?
256 _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
260 ninstance = appt->ntimes;
267 * calculate the ntimes value which, depending on the
268 * repeating event type, may not be the same
269 * as the actual number of instances
272 _DtCms_get_new_ntimes_v4(Period_4 period, time_t tick, int ninstance)
276 int delta = 0, firstweek, timesperweek;
277 _Xltimeparams localtime_buf;
279 switch (period.period) {
282 case everyNthMonth_4:
283 ntimes = ninstance * period.nth;
286 tm = _XLocaltime(&tick, localtime_buf);
288 delta = ((ninstance % 5) > (6 - tm->tm_wday)) ? 2 : 1;
289 else if (tm->tm_wday != 1)
291 ntimes = (ninstance/5) + delta;
294 tm = _XLocaltime(&tick, localtime_buf);
296 delta = ((ninstance % 3) > ((7-tm->tm_wday)/2)) ? 2:1;
297 else if (tm->tm_wday != 1)
299 ntimes = (ninstance/3) + delta;
302 tm = _XLocaltime(&tick, localtime_buf);
303 if (ninstance % 2 || tm->tm_wday != 2)
305 ntimes = (ninstance/2) + delta;
308 tm = _XLocaltime(&tick, localtime_buf);
309 timesperweek = ntimes_this_week((u_int)period.nth, 0);
310 firstweek=ntimes_this_week((u_int)period.nth,tm->tm_wday);
311 if (ninstance % timesperweek)
312 delta = ((ninstance % timesperweek) > firstweek) ? 2:1;
313 else if (firstweek != timesperweek)
315 ntimes = (ninstance/timesperweek) + delta;
326 _DtCms_first_tick_v4(time_t t, Period_4 period, int ordinal)
332 for (i = 1; i < ordinal; i++)
333 ftick = _DtCms_prev_tick_v4(ftick, period);
340 * Given a time, calculate the closest instance whose
341 * tick is later than the time.
342 * If the calculated tick does not pass timeok(), ftick is
343 * returned and ordinal set to 1.
346 _DtCms_closest_tick_v4(time_t target, time_t ftick, Period_4 period, int *ordinal)
354 _Xltimeparams localtime_buf;
356 if (target <= ftick) {
361 if (period.period < monthly_4 || period.period == everyNthDay_4 ||
362 period.period == everyNthWeek_4) {
363 tm1 = *_XLocaltime(&ftick, localtime_buf);
364 tm2 = *_XLocaltime(&target, localtime_buf);
366 switch(period.period) {
368 delta = (target - ftick) / daysec;
369 remainder = target - ftick - daysec * delta;
370 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
372 *ordinal = delta + (remainder>0?1:0) + 1;
373 ctick = nextnday_exacttime(ftick, *ordinal - 1);
376 delta = (target - ftick) / wksec;
377 remainder = target - ftick - wksec * delta;
378 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
380 *ordinal = delta + (remainder>0?1:0) + 1;
381 ctick = nextnwk_exacttime(ftick, *ordinal - 1);
384 delta = (target - ftick) / (wksec * 2);
385 remainder = target - ftick - wksec * 2 * delta;
386 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
388 *ordinal = delta + (remainder>0?1:0) + 1;
389 ctick = nextnwk_exacttime(ftick, 2 * (*ordinal - 1));
392 tm = _XLocaltime(&ftick, localtime_buf);
394 * Calculate the closest tick only if the date
395 * is < 29; otherwise just return the first tick.
396 * Use 32 to take care of dst time difference.
397 * Without dst, we can use 31.
399 if (tm->tm_mday < 29) {
400 delta = (target - ftick) / (daysec * 32);
401 remainder = target - ftick - (daysec * 32) * delta;
402 *ordinal = delta + (remainder>0?1:0) + 1;
403 ctick = nextnmth_exactday(ftick, *ordinal - 1);
410 tm = _XLocaltime(&ftick, localtime_buf);
411 if (tm->tm_mday == 29 && tm->tm_mon == 1) {
412 delta = (target - ftick) / (yrsec * 4 + daysec);
413 remainder = target - ftick - (yrsec * 4) * delta;
414 *ordinal = delta + (remainder>0?1:0) + 1;
415 ctick = nextnyear(ftick, (*ordinal - 1) * 4);
417 delta = (target - ftick) / yrsec;
418 /* adjustment for leap year */
419 remainder = tm->tm_year % 4;
420 if (remainder == 0 || (remainder + delta) > 3)
422 remainder = target - ftick - yrsec * delta;
423 *ordinal = delta + (remainder>0?1:0) + 1;
424 ctick = nextnyear(ftick, *ordinal - 1);
428 /* 36 is 5 weeks ==> maximum interval between 2 instances */
429 delta = (target - ftick) / (daysec * 36);
430 remainder = target - ftick - (daysec * 36) * delta;
431 *ordinal = delta + (remainder>0?1:0) + 1;
432 ctick = lastnthweekday(ftick, period.nth, *ordinal - 1);
435 delta = (target - ftick) / (daysec * period.nth);
436 remainder = target - ftick - (daysec * period.nth) * delta;
437 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
439 *ordinal = delta + (remainder>0?1:0) + 1;
440 ctick = nextnday_exacttime(ftick,
441 period.nth * (*ordinal - 1));
444 delta = (target - ftick) / (wksec * period.nth);
445 remainder = target - ftick - (wksec * period.nth) * delta;
446 if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
448 *ordinal = delta + (remainder>0?1:0) + 1;
449 ctick = nextnwk_exacttime(ftick,
450 period.nth * (*ordinal - 1));
452 case everyNthMonth_4:
453 tm = _XLocaltime(&ftick, localtime_buf);
454 if (tm->tm_mday < 29) {
455 delta = (target - ftick) / (daysec * 32 * period.nth);
456 remainder = target-ftick-(daysec*32*period.nth)*delta;
457 *ordinal = delta + (remainder>0?1:0) + 1;
458 ctick = nextnmth_exactday(ftick,
459 period.nth * (*ordinal - 1));
469 delta = (target - ftick) / wksec;
470 tm = _XLocaltime(&ftick, localtime_buf);
472 switch (period.period) {
474 *ordinal = delta * 5 + 6 - tm->tm_wday;
477 *ordinal = delta * 3 + (7 - tm->tm_wday) / 2;
480 *ordinal = delta * 2 + ((tm->tm_wday == 2) ? 2 : 1);
483 *ordinal = delta * ntimes_this_week((u_int)period.nth,0)
484 + ntimes_this_week((u_int)period.nth,
488 /* delta*daysperweek+(lastapptofweek-firstday in first week) */
489 if (period.period == daysOfWeek_4) {
491 lastapptofweek((u_int)period.nth) - tm->tm_wday;
492 ctick = ftick + ndays * daysec;
493 } else if (period.period == tueThur_4) {
494 ndays = delta * 7 + 4 - tm->tm_wday;
495 ctick = ftick + ndays * daysec;
497 ndays = delta * 7 + 5 - tm->tm_wday;
498 ctick = ftick + ndays * daysec;
501 if (ctick > target) { /* need to go back 1 week */
507 if (period.period == monThruFri_4)
509 else if (period.period == monWedFri_4)
511 else if (period.period == tueThur_4)
513 ctick -= (7 * daysec);
516 ctick = adjust_dst(ftick, ctick);
532 * Calculate the tick of the last instance of a repeating event.
533 * If the calculated tick does not pass timeok(), EOT is returned.
536 _DtCms_last_tick_v4(time_t ftick, Period_4 period, int ntimes)
542 _Xltimeparams localtime_buf;
544 if (ntimes >= _DtCM_OLD_REPEAT_FOREVER)
547 if (period.enddate != 0)
548 return(period.enddate);
550 switch(period.period) {
552 ltick = nextnwk_exacttime(ftick, ntimes - 1);
555 /* 2 * (ntimes-1) won't overflow an integer since
556 * we make sure ntimes is < EOT
558 ltick = nextnwk_exacttime(ftick, 2 * (ntimes - 1));
561 ltick = nextnday_exacttime(ftick, ntimes - 1);
564 tm = _XLocaltime(&ftick, localtime_buf);
566 * calculate the last tick only if the date
567 * is < 29; otherwise return EOT to force calculation
569 if (tm->tm_mday < 29)
570 ltick = nextnmth_exactday(ftick, ntimes - 1);
575 /* 2038 is the last year that can be represented.
576 * this check is to prevent (ntimes-1)*4 from integer overflow
581 tm = _XLocaltime(&ftick, localtime_buf);
582 if (tm->tm_mday == 29 && tm->tm_mon == 1)
583 ltick = nextnyear(ftick, (ntimes - 1) * 4);
585 ltick = nextnyear(ftick, ntimes - 1);
589 ltick = lastnthweekday(ftick, period.nth, ntimes - 1);
592 ltick = nextnday_exacttime(ftick, period.nth *
593 (((ntimes+(period.nth-1))/period.nth) - 1));
596 ltick = nextnwk_exacttime(ftick, period.nth *
597 (((ntimes+(period.nth-1))/period.nth) - 1));
599 case everyNthMonth_4:
600 tm = _XLocaltime(&ftick, localtime_buf);
601 if (tm->tm_mday < 29)
602 ltick = nextnmth_exactday(ftick, period.nth *
603 (((ntimes+(period.nth-1))/period.nth) -1));
611 tm = _XLocaltime(&ftick, localtime_buf);
613 /* (ntimes-1)*daysperweek+(lastapptofweek-fstapptofFstweek) */
614 if (period.period == daysOfWeek_4)
616 ((double)(ntimes - 1) * 7 +
617 lastapptofweek((u_int)period.nth) - tm->tm_wday)
619 else if (period.period == tueThur_4)
621 ((double)(ntimes - 1) * 7 + (4 - tm->tm_wday)) *
625 ((double)(ntimes - 1) * 7 + (5 - tm->tm_wday)) *
628 if (dltick >= EOT || dltick < 0)
631 ltick = adjust_dst(ftick, (time_t)dltick);
643 * Calculate the tick of next instance.
644 * If the calculated tick does not pass timeok(), EOT is returned.
647 _DtCms_next_tick_v4(time_t tick, Period_4 period)
651 _Xltimeparams localtime_buf;
653 switch(period.period) {
655 next = nextnwk_exacttime(tick, 1);
658 next = nextnwk_exacttime(tick, 2);
661 next = nextnday_exacttime(tick, 1);
664 next = nextmonth_exactday(tick);
667 tm = _XLocaltime(&tick, localtime_buf);
668 if (tm->tm_mday == 29 && tm->tm_mon == 1)
669 next = nextnyear(tick, 4);
671 next = nextnyear(tick, 1);
674 next = nextnthweekday(tick, period.nth);
677 next = nextnday_exacttime(tick, period.nth);
680 next = nextnwk_exacttime(tick, period.nth);
682 case everyNthMonth_4:
683 next = nextnmth_exactday(tick, period.nth);
686 next = nextmonTofri(tick);
689 next = nextmonwedfri(tick);
692 next = nexttuethur(tick);
695 next = nextdaysofweek(tick, period.nth);
700 if(next != tick && timeok(next)) return(next);
705 * Calculate the tick of previous instance.
706 * If the calculated tick does not pass timeok(), bot-1 is returned.
709 _DtCms_prev_tick_v4(time_t tick, Period_4 period)
713 _Xltimeparams localtime_buf;
715 switch(period.period) {
717 prev = prevnwk_exacttime(tick, 1);
720 prev = prevnwk_exacttime(tick, 2);
723 prev = prevnday_exacttime(tick, 1);
726 prev = prevmonth_exactday(tick);
729 tm = _XLocaltime(&tick, localtime_buf);
730 if (tm->tm_mday == 29 && tm->tm_mon == 1)
731 prev = prevnyear(tick, 4);
733 prev = prevnyear(tick, 1);
736 prev = prevnthweekday(tick, period.nth);
739 prev = prevnday_exacttime(tick, period.nth);
742 prev = prevnwk_exacttime(tick, period.nth);
744 case everyNthMonth_4:
745 prev = prevnmth_exactday(tick, period.nth);
748 prev = prevmonTofri(tick);
751 prev = prevmonwedfri(tick);
754 prev = prevtuethur(tick);
757 prev = prevdaysofweek(tick, period.nth);
762 if(prev != tick && timeok(prev)) return(prev);
768 * TRUE - it is a match regard_DtCmsIsLess the event is cancelled,
769 * FALSE - it is not a match if the event is cancelled.
772 _DtCms_in_repeater(Id_4 *key, Appt_4 *p_appt, boolean_t dont_care_cancel)
779 ntimes = _DtCms_get_ninstance_v4(p_appt);
780 period = p_appt->period;
781 tick = _DtCms_closest_tick_v4(key->tick, p_appt->appt_id.tick, period, &ordinal);
783 while (++ordinal <= ntimes)
785 if (tick > key->tick) /* out-of-bound */
787 if (tick == key->tick)
789 if (dont_care_cancel)
791 if (!_DtCms_marked_4_cancellation (p_appt, ordinal))
794 tick = _DtCms_next_tick_v4 (tick, period);
801 _DtCms_marked_4_cancellation(Appt_4 *a, int i)
808 p = a->exception; /* in descending order for faster access */
820 next_ndays(time_t t, int n)
824 _Xltimeparams localtime_buf;
826 tm = *_XLocaltime(&t, localtime_buf);
834 next = timelocal(&tm);
836 next = next + n * daysec;
837 next = adjust_dst(t, next);
842 next_nmins(time_t t, int m)
846 _Xltimeparams localtime_buf;
848 tm = *_XLocaltime(&t, localtime_buf);
853 next = next + m * minsec;
854 next = adjust_dst(t, next);
859 _DtCmsBeginOfDay(time_t t)
862 _Xltimeparams localtime_buf;
864 tm = *_XLocaltime(&t, localtime_buf);
872 _DtCmsTimeOfDay(time_t t)
875 _Xltimeparams localtime_buf;
877 tm = *_XLocaltime(&t, localtime_buf);
881 return(t - mktime(&tm));
885 * Given a weekmask, find the last appointment in the week
888 lastapptofweek(u_int mask)
895 for (n = -1; mask != 0; n++, mask = mask >> 1);
901 * Given a weekmask and the first day of the week, calculate
902 * the number of times outstanding in the week.
905 ntimes_this_week(u_int weekmask, int firstday)
907 int i, ntimes, weekdaymask = 1 << firstday;
912 for (i=firstday, ntimes=0; i < 7; i++, weekdaymask <<= 1) {
913 if (weekdaymask & weekmask)
920 nthweekdayofmonth(time_t t, int *nth)
922 struct tm tm, tm2, tmfirstday;
924 _Xltimeparams localtime_buf;
926 tmfirstday = tm = *_XLocaltime(&t, localtime_buf);
928 *nth = (12 + tm.tm_mday - tm.tm_wday)/7;
930 tmfirstday.tm_hour = 0;
931 tmfirstday.tm_min = 0;
932 tmfirstday.tm_sec = 0;
933 tmfirstday.tm_mday = 1;
934 firstday = mktime(&tmfirstday);
935 tmfirstday = *_XLocaltime(&firstday, localtime_buf);
937 if (tm.tm_wday < tmfirstday.tm_wday)
944 tm2 = *_XLocaltime(&t, localtime_buf);
946 return((tm.tm_mon == tm2.tm_mon) ? B_FALSE : B_TRUE);
951 * If the result falls beyond the system limit, -1 is returned by mktime().
954 next_nmonth(time_t t, int n)
958 _Xltimeparams localtime_buf;
963 tm = *_XLocaltime(&t, localtime_buf);
971 if ((tm.tm_mon = tm.tm_mon + n) > 11) {
981 adjust_dst(time_t start, time_t next)
985 _Xltimeparams localtime_buf;
987 oldt = *_XLocaltime(&start, localtime_buf);
988 newt = *_XLocaltime(&next, localtime_buf);
990 if (oldt.tm_isdst == newt.tm_isdst) {
992 } else if (oldt.tm_isdst == 1) {
993 return (next + (int)hrsec);
995 return (next - (int)hrsec);
1000 prev_nmonth(time_t t, int n)
1004 _Xltimeparams localtime_buf;
1009 tm = *_XLocaltime(&t, localtime_buf);
1017 if ((tm.tm_mon = tm.tm_mon - n) < 0) {
1023 return(mktime(&tm));
1025 return(timelocal(&tm));
1033 (y % 4 == 0 && y % 100 !=0 || y % 400 == 0);
1041 _Xltimeparams localtime_buf;
1043 tm = *_XLocaltime(&t, localtime_buf);
1045 return(((mon==1) && leapyr(tm.tm_year+1900))? 29 : monthdays[mon]);
1048 extern int /* find dow(0-6) that 1st dom falls on */
1052 _Xltimeparams localtime_buf;
1054 tm = *_XLocaltime(&t, localtime_buf);
1058 tm = *_XLocaltime(&t, localtime_buf);
1063 ldom(Tick t /* find dow(0-6) that last dom falls on */ )
1066 _Xltimeparams localtime_buf;
1068 tm = *_XLocaltime(&t, localtime_buf);
1069 tm.tm_mday = monthlength(t);
1072 tm = *_XLocaltime(&t, localtime_buf);
1077 _DtCmsInExceptionList(cms_entry *eptr, time_t tick)
1079 CSA_date_time_entry *dt = NULL;
1082 if (eptr->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value)
1083 dt = eptr->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value->\
1084 item.date_time_list_value;
1086 for (; dt != NULL; dt = dt->next) {
1087 if (_csa_iso8601_to_tick(dt->date_time, &time))
1098 nextnyear(time_t t, int n)
1101 _Xltimeparams localtime_buf;
1103 tm = *_XLocaltime(&t, localtime_buf);
1106 return(mktime(&tm));
1108 return(timelocal(&tm));
1115 int r =((t >= bot) &&(t <= eot));
1120 prevnyear(time_t t, int n)
1123 _Xltimeparams localtime_buf;
1125 tm = *_XLocaltime(&t, localtime_buf);
1128 return(mktime(&tm));
1130 return(timelocal(&tm));
1135 prevmonth_exactday(time_t t)
1137 time_t prev; int day;
1140 _Xltimeparams localtime_buf;
1142 tm = *_XLocaltime(&t, localtime_buf);
1143 sdelta = tm.tm_hour * hrsec + tm.tm_min * minsec + tm.tm_sec;
1145 if((tm.tm_mday < 31 && tm.tm_mon != 0) || /* at least 30 days everywhere, except Feb.*/
1146 (tm.tm_mday==31 && tm.tm_mon==6) || /* two 31s -- Jul./Aug. */
1147 (tm.tm_mday==31 && tm.tm_mon==11) || /* two 31s -- Dec./Jan. */
1148 (tm.tm_mon == 0 &&(tm.tm_mday < 29 ||(tm.tm_mday==29 && leapyr(tm.tm_year+1900))))) {
1149 prev = t-monthseconds(previousmonth(t));
1150 prev = adjust_dst(t, prev);
1152 else { /* brute force */
1153 prev = previousmonth(previousmonth(t)); /* hop over the month */
1154 tm = *_XLocaltime(&prev, localtime_buf);
1158 prev =(mktime(&tm)) + sdelta;
1160 prev =(timelocal(&tm)) + sdelta;
1168 nextmonth_exactday(time_t t)
1170 time_t next; int day;
1173 _Xltimeparams localtime_buf;
1175 tm = *_XLocaltime(&t, localtime_buf);
1176 sdelta = tm.tm_hour * hrsec + tm.tm_min * minsec + tm.tm_sec;
1178 if((tm.tm_mday < 31 && tm.tm_mon != 0) || /* at least 30 days everywhere, except Feb.*/
1179 (tm.tm_mday==31 && tm.tm_mon==6) || /* two 31s -- Jul./Aug. */
1180 (tm.tm_mday==31 && tm.tm_mon==11) || /* two 31s -- Dec./Jan. */
1181 (tm.tm_mon == 0 &&(tm.tm_mday < 29 ||(tm.tm_mday==29 && leapyr(tm.tm_year+1900))))) {
1182 next = t+monthseconds(t);
1183 next = adjust_dst(t, next);
1185 else { /* brute force */
1186 next = next_nmonth(t, 2); /* hop over the month */
1187 tm = *_XLocaltime(&next, localtime_buf);
1191 next = mktime(&tm) + sdelta;
1193 next =(timelocal(&tm)) + sdelta;
1200 previousmonth(time_t t)
1203 _Xltimeparams localtime_buf;
1205 tm = *_XLocaltime(&t, localtime_buf);
1220 return(mktime(&tm));
1222 return(timelocal(&tm));
1227 monthseconds(time_t t)
1231 _Xltimeparams localtime_buf;
1233 tm = *_XLocaltime(&t, localtime_buf);
1235 return(((mon==1) && leapyr(tm.tm_year+1900)) ?
1236 29*daysec : monthsecs[mon]);
1240 * find the number of instances to be subtracted
1243 get_ndelta(time_t startdate, Period_4 period, int ntimes)
1249 _Xltimeparams localtime_buf;
1251 if (period.enddate == 0)
1254 /* find last day of the series */
1255 dlastdate = startdate + (double)wksec * (ntimes - 1); /* last week */
1256 if (dlastdate > EOT)
1259 lastdate = (time_t)dlastdate;
1261 tm = _XLocaltime(&lastdate, localtime_buf);
1262 if (period.period == monThruFri_4 || period.period == monWedFri_4)
1263 lastdate = lastdate + daysec * (5 - tm->tm_wday);
1264 else if (period.period == tueThur_4)
1265 lastdate = lastdate + daysec * (4 - tm->tm_wday);
1266 else if (period.period == daysOfWeek_4)
1267 lastdate = lastdate + daysec *
1268 (lastapptofweek((u_int)period.nth) - tm->tm_wday);
1270 if (period.enddate > lastdate)
1273 tm = _XLocaltime(&period.enddate, localtime_buf);
1274 switch (period.period) {
1276 ndelta = 5 - tm->tm_wday;
1279 if (tm->tm_wday < 3)
1281 else if (tm->tm_wday < 5)
1285 if (tm->tm_wday < 2)
1287 else if (tm->tm_wday < 4)
1291 ndelta = ntimes_this_week((u_int)period.nth, tm->tm_wday) - 1;
1298 lastnthweekday(time_t t, int nth, int ntimes)
1304 _Xltimeparams localtime_buf;
1307 * if nth is not specified, assume it's the
1308 * 4th week for the ambiguous case.
1311 nthweekdayofmonth(t, &nth);
1316 tm1 = *_XLocaltime(&t, localtime_buf);
1317 sdelta = tm1.tm_hour * hrsec + tm1.tm_min * minsec + tm1.tm_sec;
1320 if ((tick = next_nmonth(t, ntimes)) == EOT || tick < 0)
1323 tm2 = *_XLocaltime(&tick, localtime_buf);
1325 delta = tm1.tm_wday - tm2.tm_wday;
1329 ntick = tick + (((nth - 1) * 7 + delta) * daysec) + sdelta;
1331 if ((tick = next_nmonth(t, ntimes + 1)) == EOT || tick < 0)
1334 tm2 = *_XLocaltime(&tick, localtime_buf);
1336 delta = tm2.tm_wday - tm1.tm_wday;
1337 if (tm1.tm_wday >= tm2.tm_wday)
1340 ntick = tick - (delta * daysec) + sdelta;
1342 ntick = adjust_dst(tick, ntick);
1348 nextnthweekday(time_t t, int nth)
1354 _Xltimeparams localtime_buf;
1357 * if nth is not specified, assume it's the
1358 * 4th week for the ambiguous case.
1361 nthweekdayofmonth(t, &nth);
1366 tm1 = *_XLocaltime(&t, localtime_buf);
1367 sdelta = tm1.tm_hour * hrsec + tm1.tm_min * minsec + tm1.tm_sec;
1370 tick = next_nmonth(t, 1);
1371 tm2 = *_XLocaltime(&tick, localtime_buf);
1373 delta = tm1.tm_wday - tm2.tm_wday;
1377 ntick = tick + (((nth - 1) * 7 + delta) * daysec) + sdelta;
1379 tick = next_nmonth(t, 2);
1380 tm2 = *_XLocaltime(&tick, localtime_buf);
1382 delta = tm2.tm_wday - tm1.tm_wday;
1383 if (tm1.tm_wday >= tm2.tm_wday)
1386 ntick = tick - (delta * daysec) + sdelta;
1388 ntick = adjust_dst(tick, ntick);
1394 prevnthweekday(time_t t, int nth)
1400 _Xltimeparams localtime_buf;
1403 * if nth is not specified, assume it's the
1404 * 4th week for the ambiguous case.
1407 nthweekdayofmonth(t, &nth);
1412 tm1 = *_XLocaltime(&t, localtime_buf);
1413 sdelta = tm1.tm_hour * hrsec + tm1.tm_min * minsec + tm1.tm_sec;
1416 tick = prev_nmonth(t, 1);
1417 tm2 = *_XLocaltime(&tick, localtime_buf);
1419 delta = tm1.tm_wday - tm2.tm_wday;
1423 ptick = tick + (((nth - 1) * 7 + delta) * daysec) + sdelta;
1425 tick = prev_nmonth(next_nmonth(t, 1), 1);
1426 tm2 = *_XLocaltime(&tick, localtime_buf);
1428 delta = tm2.tm_wday - tm1.tm_wday;
1429 if (tm1.tm_wday >= tm2.tm_wday)
1432 ptick = tick - (delta * daysec) + sdelta;
1434 ptick = adjust_dst(tick, ptick);
1439 /* use double in this routine to avoid integer overflow
1440 * in case n is very large.
1443 nextnday_exacttime(time_t t, int n)
1447 next = t + (double)n * daysec;
1448 if (next >= EOT || next < 0)
1451 next = adjust_dst(t, (time_t)next);
1452 return((time_t)next);
1457 * This is defined in the private library and is used also by the front
1458 * end -- should it be here?
1461 prevnday_exacttime(time_t t, int n)
1465 prev = t - (n * daysec);
1466 prev = adjust_dst(t, prev);
1470 /* use double in this routine to avoid integer overflow
1471 * in case n is very large.
1474 nextnwk_exacttime(time_t t, int n)
1478 next = t + (double)n * 7 * daysec;
1479 if (next >= EOT || next < 0)
1482 next = adjust_dst(t, (time_t)next);
1483 return((time_t)next);
1488 prevnwk_exacttime(time_t t, int n)
1492 prev = t - n * 7 * daysec;
1493 prev = adjust_dst(t, prev);
1498 nextnmth_exactday(time_t t, int n)
1501 boolean_t done = B_FALSE;
1503 _Xltimeparams localtime_buf;
1505 tm1 = *_XLocaltime(&t, localtime_buf);
1507 if ((next = next_nmonth(t, n)) == EOT || next < 0)
1510 tm2 = *_XLocaltime(&next, localtime_buf);
1512 /* 1. at least 30 days except feb
1513 * 2. 2/29 on leap year
1514 * 3. 31st on the appropriate month
1516 if ((tm1.tm_mday < 31 && tm2.tm_mon != 1) ||
1517 (tm2.tm_mon == 1 && (tm1.tm_mday < 29 ||
1518 (tm1.tm_mday == 29 && leapyr(tm2.tm_year + 1900)))) ||
1519 (tm1.tm_mday == 31 && ((tm2.tm_mon > 6 && tm2.tm_mon % 2) ||
1520 ((tm2.tm_mon <= 6 && (tm2.tm_mon % 2 == 0)))))) {
1521 tm2.tm_sec = tm1.tm_sec;
1522 tm2.tm_min = tm1.tm_min;
1523 tm2.tm_hour = tm1.tm_hour;
1524 tm2.tm_mday = tm1.tm_mday;
1532 next = mktime(&tm2);
1534 next = (timelocal(&tm2));
1540 prevnmth_exactday(time_t t, int n)
1543 boolean_t done = B_FALSE;
1545 _Xltimeparams localtime_buf;
1547 tm1 = *_XLocaltime(&t, localtime_buf);
1549 prev = prev_nmonth(t, n);
1550 tm2 = *_XLocaltime(&prev, localtime_buf);
1552 if ((tm1.tm_mday < 30 && tm2.tm_mon != 1) ||
1553 (tm2.tm_mon == 1 && (tm1.tm_mday < 29 ||
1554 (tm1.tm_mday == 29 && leapyr(tm2.tm_year + 1900)))) ||
1555 (tm1.tm_mday == 31 && ((tm2.tm_mon > 6 && tm2.tm_mon % 2) ||
1556 ((tm2.tm_mon <= 6 && (tm2.tm_mon % 2 == 0)))))) {
1557 tm2.tm_sec = tm1.tm_sec;
1558 tm2.tm_min = tm1.tm_min;
1559 tm2.tm_hour = tm1.tm_hour;
1560 tm2.tm_mday = tm1.tm_mday;
1568 prev = mktime(&tm2);
1570 prev = (timelocal(&tm2));
1576 nextmonTofri(time_t t)
1580 _Xltimeparams localtime_buf;
1582 tm = _XLocaltime(&t, localtime_buf);
1584 if (tm->tm_wday < 5)
1585 next = t + (int)daysec;
1587 next = t + (int)daysec * (8 - tm->tm_wday);
1589 next = adjust_dst(t, next);
1594 prevmonTofri(time_t t)
1598 _Xltimeparams localtime_buf;
1600 tm = _XLocaltime(&t, localtime_buf);
1602 if (tm->tm_wday > 1)
1603 prev = t - (int)daysec;
1605 prev = t - (int)daysec * (2 + tm->tm_wday);
1607 prev = adjust_dst(t, prev);
1612 nextmonwedfri(time_t t)
1616 _Xltimeparams localtime_buf;
1618 tm = _XLocaltime(&t, localtime_buf);
1620 if (tm->tm_wday == 5)
1621 next = t + (int)daysec * 3;
1622 else if (tm->tm_wday % 2 || tm->tm_wday == 6)
1623 next = t + (int)daysec * 2;
1625 next = t + (int)daysec;
1627 next = adjust_dst(t, next);
1632 prevmonwedfri(time_t t)
1636 _Xltimeparams localtime_buf;
1638 tm = _XLocaltime(&t, localtime_buf);
1640 if (tm->tm_wday == 1)
1641 prev = t - (int)daysec * 3;
1642 else if (tm->tm_wday % 2 || tm->tm_wday == 0)
1643 prev = t - (int)daysec * 2;
1645 prev = t - (int)daysec;
1647 prev = adjust_dst(t, prev);
1652 nexttuethur(time_t t)
1656 _Xltimeparams localtime_buf;
1658 tm = _XLocaltime(&t, localtime_buf);
1660 if (tm->tm_wday < 4) {
1661 if (tm->tm_wday % 2)
1662 next = t + (int)daysec;
1664 next = t + (int)daysec * 2;
1666 next = t + (int)daysec * (9 - tm->tm_wday);
1668 next = adjust_dst(t, next);
1673 prevtuethur(time_t t)
1677 _Xltimeparams localtime_buf;
1679 tm = _XLocaltime(&t, localtime_buf);
1681 if (tm->tm_wday > 2) {
1682 if (tm->tm_wday % 2)
1683 prev = t - (int)daysec;
1685 prev = t - (int)daysec * 2;
1687 prev = t - (int)daysec * (3 + tm->tm_wday);
1689 prev = adjust_dst(t, prev);
1694 * the 7-bit mask should be put in the last 7 bits of the int
1697 nextdaysofweek(time_t t, int weekmask)
1699 unsigned int doublemask;
1701 int i, ndays, daymask;
1703 _Xltimeparams localtime_buf;
1705 doublemask = weekmask | (weekmask << 7);
1706 tm = _XLocaltime(&t, localtime_buf);
1707 daymask = weekdaymasks[tm->tm_wday] << 1;
1709 for (i = 0, ndays = 1; i < 7; i++) {
1710 if (daymask & doublemask)
1718 next = t + (int)daysec * ndays;
1719 next = adjust_dst(t, next);
1724 prevdaysofweek(time_t t, int weekmask)
1726 unsigned int doublemask, daymask;
1730 _Xltimeparams localtime_buf;
1732 doublemask = weekmask | (weekmask << 7);
1733 tm = _XLocaltime(&t, localtime_buf);
1734 daymask = weekdaymasks[tm->tm_wday] << 6;
1736 for (i = 0, ndays = 1; i < 7; i++) {
1737 if (daymask & doublemask)
1745 prev = t - (int)daysec * ndays;
1746 prev = adjust_dst(t, prev);