1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
27 * Time_t conversion support
29 * relative times inspired by Steve Bellovin's netnews getdate(3)
36 #define dig1(s,n) ((n)=((*(s)++)-'0'))
37 #define dig2(s,n) ((n)=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0')
38 #define dig3(s,n) ((n)=((*(s)++)-'0')*100,(n)+=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0')
39 #define dig4(s,n) ((n)=((*(s)++)-'0')*1000,(n)+=((*(s)++)-'0')*100,(n)+=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0')
44 #define CCYYMMDDHHMMSS (1<<1)
53 #define MINUTE (1<<10)
57 #define ORDINAL (1<<14)
58 #define SECOND (1<<15)
65 #define FFMT "%s%s%s%s%s%s%s|"
66 #define FLAGS(f) (f&EXACT)?"|EXACT":"",(f&LAST)?"|LAST":"",(f&THIS)?"|THIS":"",(f&NEXT)?"|NEXT":"",(f&ORDINAL)?"|ORDINAL":"",(f&FINAL)?"|FINAL":"",(f&WORK)?"|WORK":""
68 * parse cron range into set
69 * return: -1:error 0:* 1:some
73 range(register char* s
, char** e
, char* set
, int lo
, int hi
)
80 while (isspace(*s
) || *s
== '_')
87 memset(set
, 0, hi
+ 1);
90 n
= strtol(s
, &t
, 10);
91 if (s
== t
|| n
< lo
|| n
> hi
)
96 m
= strtol(++s
, &t
, 10);
97 if (s
== t
|| m
< n
|| m
> hi
)
101 i
= strtol(++s
, &t
, 10);
109 for (; n
<= m
; n
+= i
)
120 * normalize <p,q> to power of 10 u in tm
124 powerize(Tm_t
* tm
, unsigned long p
, unsigned long q
, unsigned long u
)
138 tm
->tm_nsec
+= (int)(t
% TMX_RESOLUTION
);
139 tm
->tm_sec
+= (int)(t
/ TMX_RESOLUTION
);
143 #define K2(c1,c2) (((c1)<<8)|(c2))
144 #define K3(c1,c2,c3) (((c1)<<16)|((c2)<<8)|(c3))
145 #define K4(c1,c2,c3,c4) (((c1)<<24)|((c2)<<16)|((c3)<<8)|(c4))
147 #define P_INIT(n) w = n; p = q = 0; u = (char*)s + 1
150 * parse date expression in s and return Time_t value
152 * if non-null, e points to the first invalid sequence in s
153 * now provides default values
157 tmxdate(register const char* s
, char** e
, Time_t now
)
187 char skip
[UCHAR_MAX
+ 1];
190 * check DATEMSK first
193 debug((error(-1, "AHA tmxdate 2009-03-06")));
194 fix
= tmxscan(s
, &last
, NiL
, &t
, now
, 0);
206 * use now for defaults
209 tm
= tmxtm(&ts
, now
, NiL
);
210 tm_info
.date
= tm
->tm_zone
;
218 for (n
= 1; n
<= UCHAR_MAX
; n
++)
219 skip
[n
] = isspace(n
) || strchr("_,;@=|!^()[]{}", n
);
222 * get <weekday year month day hour minutes seconds ?[ds]t [ap]m>
228 state
&= (state
& HOLD
) ? ~(HOLD
) : ~(EXACT
|LAST
|NEXT
|THIS
);
229 if ((set
|state
) & (YEAR
|MONTH
|DAY
))
231 message((-1, "AHA#%d state=" FFMT
" set=" FFMT
, __LINE__
, FLAGS(state
), FLAGS(set
)));
234 if (*s
== '.' || *s
== '-' || *s
== '+')
236 if (((set
|state
) & (YEAR
|MONTH
|HOUR
|MINUTE
|ZONE
)) == (YEAR
|MONTH
|HOUR
|MINUTE
) && (i
= tmgoff(s
, &t
, TM_LOCALZONE
)) != TM_LOCALZONE
)
250 if (!*(last
= (char*)s
))
256 now
= strtoull(s
, &t
, 0);
262 while (isdigit(*++s
))
263 fix
+= (*s
- '0') * (m
/= 10);
264 now
= tmxsns(now
, fix
);
266 else if (now
<= 0x7fffffff)
267 now
= tmxsns(now
, 0);
270 else if (*s
++ == '#')
272 now
= tmxtime(tm
, zone
);
277 if ((*s
== 'P' || *s
== 'p') && (!isalpha(*(s
+ 1)) || (*(s
+ 1) == 'T' || *(s
+ 1) == 't') && !isalpha(*(s
+ 2))))
318 tm
->tm_sec
+= (365L*24L*60L*60L) * p
/ q
;
354 tm
->tm_sec
+= (3042L*24L*60L*60L) * p
/ q
/ 100L;
361 tm
->tm_sec
+= (60L) * p
/ q
;
367 powerize(tm
, p
, q
, 1000UL);
369 tm
->tm_nsec
+= p
* 1000000L;
378 tm
->tm_sec
+= (7L*24L*60L*60L) * p
/ q
;
380 tm
->tm_mday
+= 7 * p
;
387 tm
->tm_sec
+= (24L*60L*60L) * p
/ q
;
396 tm
->tm_sec
+= (60L*60L) * p
/ q
;
412 powerize(tm
, p
, q
, 1000000000UL);
428 powerize(tm
, p
, q
, 1000000UL);
430 tm
->tm_nsec
+= p
* 1000L;
444 powerize(tm
, p
, q
, 1000000000UL);
457 while (*++u
&& *u
!= ':')
485 p
= p
* 10 + (c
- '0');
490 s
= (const char*)t
+ 1;
494 set
&= ~(EXACT
|LAST
|NEXT
|THIS
);
495 set
|= state
& (EXACT
|LAST
|NEXT
|THIS
);
506 while (isspace(*++s
) || *s
== '_');
507 n
= strtol(s
, &t
, 0);
510 for (s
= t
; skip
[*s
]; s
++);
511 state
|= (f
= n
) ? NEXT
: THIS
;
512 set
&= ~(EXACT
|LAST
|NEXT
|THIS
);
513 set
|= state
& (EXACT
|LAST
|NEXT
|THIS
);
521 * check for cron date
523 * min hour day-of-month month day-of-week
525 * if it's cron then determine the next time
526 * that satisfies the specification
528 * NOTE: the only spacing is ' '||'_'||';'
537 else if (!isdigit(n
))
540 while ((n
= *++s
) == ',' || n
== '-' || n
== '/' || isdigit(n
));
541 if (n
!= ' ' && n
!= '_' && n
!= ';')
548 while ((n
= *++s
) == ' ' || n
== '_');
567 if ((k
= range(t
, &t
, hit
, 0, 59)) < 0)
569 if (k
&& !hit
[i
= tm
->tm_min
])
575 if (++tm
->tm_hour
> 59)
588 if ((k
= range(t
, &t
, hit
, 0, 23)) < 0)
590 if (k
&& !hit
[i
= tm
->tm_hour
])
596 if (++tm
->tm_mday
> 28)
609 if ((k
= range(t
, &t
, hit
, 1, 31)) < 0)
618 if ((k
= range(t
, &t
, mon
, 1, 12)) < 0)
623 for (i
= 1; i
<= 12; i
++)
630 if ((k
= range(t
, &t
, day
, 0, 6)) < 0)
635 if (flags
& (MONTH
|MDAY
|WDAY
))
637 fix
= tmxtime(tm
, zone
);
638 tm
= tmxtm(tm
, fix
, tm
->tm_zone
);
653 tt
= tmxtime(tm
, zone
);
656 tm
= tmxtm(tm
, tt
, tm
->tm_zone
);
662 if (flags
& (MDAY
|WDAY
))
664 if ((flags
& (MDAY
|WDAY
)) == (MDAY
|WDAY
))
666 if (hit
[j
] && day
[k
])
669 else if ((flags
& MDAY
) && hit
[j
])
671 else if ((flags
& WDAY
) && day
[k
])
677 tm
= tmxtm(tm
, tmxtime(tm
, zone
), tm
->tm_zone
);
682 else if ((flags
& WDAY
) && ++k
> 6)
685 else if (flags
& MONTH
)
699 n
= strtol(s
, &t
, 10);
700 if ((w
= t
- s
) && *t
== '.' && isdigit(*(t
+ 1)) && isdigit(*(t
+ 2)) && isdigit(*(t
+ 3)))
705 if ((*t
== 'T' || *t
== 't') && ((set
|state
) & (YEAR
|MONTH
|DAY
)) == (YEAR
|MONTH
) && isdigit(*(t
+ 1)))
708 if ((w
== 2 || w
== 4) && (*u
== 'W' || *u
== 'w') && isdigit(*(u
+ 1)))
712 if ((n
-= 1900) < TM_WINDOW
)
715 else if (n
< TM_WINDOW
)
718 n
= strtol(++u
, &t
, 10);
719 if ((i
= (t
- u
)) < 2 || i
> 3)
728 else if (*++t
&& dig1(t
, k
) < 1 || k
> 7)
736 set
|= YEAR
|MONTH
|DAY
;
740 else if (w
== 6 || w
== 8 && (n
/ 1000000) > 12)
744 if (w
== 8 || w
== 6 && *u
!= 'T' && *u
!= 't')
747 if ((m
-= 1900) < TM_WINDOW
)
757 if (dig2(t
, l
) <= 0 || l
> 12)
760 if (*t
!= 'T' && *t
!= 't' || !isdigit(*++t
))
764 if (dig2(t
, k
) < 1 || k
> 31)
769 n
= strtol(s
= t
, &t
, 0);
776 if ((t
- s
) == 1 || *t
++ != '-')
778 n
= strtol(s
= t
, &t
, 0);
784 flags
|= HOUR
|MINUTE
;
787 if (dig2(s
, n
) > (59 + TM_MAXLEAP
))
799 while (isdigit(*++t
))
800 p
+= (*t
- '0') * (q
/= 10);
803 if (n
> (59 + TM_MAXLEAP
))
807 else if (f
== -1 && isalpha(*t
) && tmlex(t
, &t
, tm_info
.format
+ TM_ORDINAL
, TM_ORDINALS
- TM_ORDINAL
, NiL
, 0) >= 0)
809 message((-1, "AHA#%d n=%d", __LINE__
, n
));
813 message((-1, "AHA#%d n=%d", __LINE__
, n
));
814 state
|= ((f
= n
) ? NEXT
: THIS
)|ORDINAL
;
815 set
&= ~(EXACT
|LAST
|NEXT
|THIS
);
816 set
|= state
& (EXACT
|LAST
|NEXT
|THIS
);
817 for (s
= t
; skip
[*s
]; s
++);
820 if (n
= strtol(s
, &t
, 10))
829 message((-1, "AHA#%d f=%d n=%d state=" FFMT
, __LINE__
, f
, n
, FLAGS(state
)));
833 if (!(state
& (LAST
|NEXT
|THIS
)) && ((i
= t
- s
) == 4 && (*t
== '.' && isdigit(*(t
+ 1)) && isdigit(*(t
+ 2)) && *(t
+ 3) != '.' || (!*t
|| isspace(*t
) || *t
== '_' || isalnum(*t
)) && n
>= 0 && (n
% 100) < 60 && ((m
= (n
/ 100)) < 20 || m
< 24 && !((set
|state
) & (YEAR
|MONTH
|HOUR
|MINUTE
)))) || i
> 4 && i
<= 12))
836 * various { date(1) touch(1) } formats
838 * [[cc]yy[mm]]ddhhmm[.ss[.nn...]]
844 if (state
& CCYYMMDDHHMMSS
)
846 state
|= CCYYMMDDHHMMSS
;
848 if ((i
== 7 || i
== 5) && (!*t
|| *t
== 'Z' || *t
== 'z'))
853 if ((m
-= 1900) < TM_WINDOW
)
856 else if (dig2(s
, m
) < TM_WINDOW
)
883 if (m
< 1969 || m
>= 3000)
890 if (!dig2(x
, m
) || m
> 12 || !dig2(x
, m
) || m
> 31 || dig2(x
, m
) > 24 || dig2(x
, m
) > 60 || dig2(x
, m
) <= 60 && !(tm_info
.flags
& TM_DATESTYLE
))
906 else if (dig2(s
, l
) <= 0 || l
> 12)
912 else if (dig2(s
, k
) < 1 || k
> 31)
922 flags
|= HOUR
|MINUTE
;
934 n
= strtol(t
+ 1, &t
, 10);
939 while (isdigit(*++t
))
940 p
+= (*t
- '0') * (q
/= 10);
944 if (n
> (59 + TM_MAXLEAP
))
961 for (s
= t
; skip
[*s
]; s
++);
962 if (*s
== ':' || *s
== '.' && ((set
|state
) & (YEAR
|MONTH
|DAY
|HOUR
)) == (YEAR
|MONTH
|DAY
))
965 if ((state
& HOUR
) || n
> 24)
967 while (isspace(*++s
) || *s
== '_');
971 n
= strtol(s
, &t
, 10);
972 for (s
= t
; isspace(*s
) || *s
== '_'; s
++);
979 while (isspace(*++s
) || *s
== '_');
982 n
= strtol(s
, &t
, 10);
984 if (n
> (59 + TM_MAXLEAP
))
992 while (isdigit(*++s
))
993 m
+= (*s
- '0') * (q
/= 10);
1009 switch (tmlex(s
, &t
, tm_info
.format
, TM_NFORM
, tm_info
.format
+ TM_MERIDIAN
, 2))
1014 tm
->tm_hour
= i
= 0;
1018 tm
->tm_hour
= i
+= 12;
1021 if (f
>= 0 || (state
& (LAST
|NEXT
)))
1023 message((-1, "AHA#%d f=%d i=%d j=%d k=%d l=%d", __LINE__
, f
, i
, j
, k
, l
));
1029 else if (state
& NEXT
)
1036 if (i
> k
|| i
== k
&& j
> l
)
1039 else if (i
< k
|| i
== k
&& j
< l
)
1043 tm
->tm_hour
+= f
* 24;
1044 while (tm
->tm_hour
>= 24)
1052 tm
->tm_hour
+= f
* 24;
1053 while (tm
->tm_hour
< 24)
1066 if (*s
== '-' || *s
== '+')
1068 if (((set
|state
) & (MONTH
|DAY
|HOUR
|MINUTE
)) == (MONTH
|DAY
|HOUR
|MINUTE
) || *s
== '+' && (!isdigit(s
[1]) || !isdigit(s
[2]) || s
[3] != ':' && (s
[3] != '.' || ((set
|state
) & (YEAR
|MONTH
)) != (YEAR
|MONTH
))))
1089 if (tmlex(s
, &t
, tm_info
.format
+ TM_SUFFIXES
, TM_PARTS
- TM_SUFFIXES
, NiL
, 0) >= 0)
1124 tm
->tm_mday
+= n
* 7;
1157 case K3('m','s','c'):
1158 case K4('m','s','e','c'):
1160 case K3('M','S','C'):
1161 case K4('M','S','E','C'):
1162 tm
->tm_nsec
+= n
* 1000000L;
1166 case K3('u','s','c'):
1167 case K4('u','s','e','c'):
1170 case K3('U','S','C'):
1171 case K4('U','S','E','C'):
1172 tm
->tm_nsec
+= n
* 1000L;
1175 case K3('n','s','c'):
1176 case K4('n','s','e','c'):
1178 case K3('N','S','C'):
1179 case K4('N','S','E','C'):
1187 if ((j
= tmlex(s
, &t
, tm_info
.format
, TM_NFORM
, tm_info
.format
+ TM_SUFFIXES
, TM_PARTS
- TM_SUFFIXES
)) >= 0)
1190 switch (tm_data
.lex
[j
])
1193 state
|= HOLD
|EXACT
;
1194 set
&= ~(EXACT
|LAST
|NEXT
|THIS
);
1195 set
|= state
& (EXACT
|LAST
|NEXT
|THIS
);
1199 set
&= ~(EXACT
|LAST
|NEXT
|THIS
);
1200 set
|= state
& (EXACT
|LAST
|NEXT
|THIS
);
1204 set
&= ~(EXACT
|LAST
|NEXT
|THIS
);
1205 set
|= state
& (EXACT
|LAST
|NEXT
|THIS
);
1210 * disambiguate english "last ... in"
1213 if (!((state
|set
) & LAST
))
1216 set
&= ~(EXACT
|LAST
|NEXT
|THIS
);
1217 set
|= state
& (EXACT
|LAST
|NEXT
|THIS
);
1222 state
|= HOLD
|THIS
|FINAL
;
1223 set
&= ~(EXACT
|LAST
|NEXT
|THIS
);
1224 set
|= state
& (EXACT
|LAST
|NEXT
|THIS
|FINAL
);
1227 message((-1, "AHA#%d WORK", __LINE__
));
1239 j
+= TM_ORDINALS
- TM_ORDINAL
;
1240 message((-1, "AHA#%d j=%d", __LINE__
, j
));
1243 n
= j
- TM_ORDINALS
+ 1;
1244 message((-1, "AHA#%d n=%d", __LINE__
, n
));
1249 else if (state
& LAST
)
1251 else if (state
& THIS
)
1253 else if (state
& NEXT
)
1263 for (k
= tm
->tm_hour
; k
< 0; k
+= 24);
1265 if (j
== TM_MERIDIAN
)
1276 j
+= TM_DAY
- TM_DAY_ABBREV
;
1281 state
|= set
& (EXACT
|LAST
|NEXT
|THIS
);
1282 if (!(state
& (LAST
|NEXT
|THIS
)))
1287 if ((k
= tmlex(s
, &t
, tm_info
.format
+ TM_LAST
, TM_NOISE
- TM_LAST
, NiL
, 0)) >= 0)
1301 state
|= (n
> 0) ? NEXT
: THIS
;
1304 set
&= ~(EXACT
|LAST
|NEXT
|THIS
);
1305 set
|= state
& (EXACT
|LAST
|NEXT
|THIS
);
1309 message((-1, "AHA#%d n=%d j=%d f=%d state=" FFMT
, __LINE__
, n
, j
, f
, FLAGS(state
)));
1313 * disambiguate english "second"
1316 if (j
== TM_PARTS
&& f
== -1)
1318 state
&= ~(LAST
|NEXT
|THIS
|ORDINAL
); /*AHA*/
1326 * disambiguate "last" vs. { "previous" "final" }
1331 message((-1, "AHA#%d disambiguate LAST s='%s'", __LINE__
, s
));
1332 if ((k
= tmlex(s
, &t
, tm_info
.format
+ TM_NEXT
, TM_EXACT
- TM_NEXT
, NiL
, 0)) >= 0 || (k
= tmlex(s
, &t
, tm_info
.format
+ TM_PARTS
+ 3, 1, NiL
, 0)) >= 0)
1341 message((-1, "AHA#%d LAST => FINAL", __LINE__
));
1344 state
&= ~(THIS
|NEXT
);
1346 message((-1, "AHA#%d disambiguate LAST k=%d", __LINE__
, k
));
1349 else if (!(state
& NEXT
))
1351 m
= (f
> 0) ? f
* n
: n
;
1352 message((-1, "AHA#%d f=%d n=%d i=%d j=%d k=%d l=%d m=%d state=" FFMT
, __LINE__
, f
, n
, i
, j
, k
, l
, m
, FLAGS(state
)));
1368 if ((m
< 0 ? -m
: m
) > (365L*24L*60L*60L))
1370 now
= tmxtime(tm
, zone
) + tmxsns(m
, 0);
1384 message((-1, "AHA#%d DAY m=%d n=%d%s", __LINE__
, m
, n
, (state
& LAST
) ? " LAST" : ""));
1385 if ((state
& (LAST
|NEXT
|THIS
)) == LAST
)
1386 tm
->tm_mday
= tm_data
.days
[tm
->tm_mon
] + (tm
->tm_mon
== 1 && tmisleapyear(tm
->tm_year
));
1387 else if (state
& ORDINAL
)
1388 tm
->tm_mday
= m
+ 1;
1391 if (!(set
& (FINAL
|WORK
)))
1395 tm
= tmxtm(tm
, tmxtime(tm
, zone
), tm
->tm_zone
);
1396 tm
->tm_mday
+= 7 * m
- tm
->tm_wday
+ 1;
1426 if (m
>= 0 && (state
& ORDINAL
))
1428 tm
= tmxtm(tm
, tmxtime(tm
, zone
), tm
->tm_zone
);
1432 message((-1, "AHA#%d j=%d m=%d", __LINE__
, j
, m
));
1434 message((-1, "AHA#%d mday=%d wday=%d day=%d dir=%d f=%d i=%d j=%d l=%d m=%d", __LINE__
, tm
->tm_mday
, tm
->tm_wday
, day
, dir
, f
, i
, j
, l
, m
));
1435 if (state
& (LAST
|NEXT
|THIS
))
1437 if (state
& ORDINAL
)
1441 if (isdigit(*s
) || tmlex(s
, &t
, tm_info
.format
, TM_DAY_ABBREV
, NiL
, 0) >= 0)
1443 state
&= ~(LAST
|NEXT
|THIS
);
1452 message((-1, "AHA#%d day=%d mday=%d f=%d m=%d j=%d state=" FFMT
, __LINE__
, day
, tm
->tm_mday
, f
, m
, j
, FLAGS(state
)));
1454 if (set
& (FINAL
|WORK
))
1456 else if (state
& (LAST
|NEXT
|THIS
))
1460 else if (m
> 0 && (state
& (NEXT
|YEAR
|MONTH
)) == NEXT
&& j
>= 0)
1462 tm
->tm_mday
+= j
+ m
* 7;
1463 set
&= ~(LAST
|NEXT
|THIS
|ORDINAL
); /*AHA*/
1464 state
&= ~(LAST
|NEXT
|THIS
|ORDINAL
); /*AHA*/
1465 if (!(state
& EXACT
))
1469 case TM_MONTH_ABBREV
:
1470 j
+= TM_MONTH
- TM_MONTH_ABBREV
;
1477 tm
->tm_mon
= j
- TM_MONTH
;
1484 n
= strtol(s
, &t
, 10);
1485 if (n
<= 31 && *t
!= ':')
1500 if (state
& (LAST
|NEXT
|THIS
))
1510 zone
= tmgoff(s
, &t
, 0);
1516 if (!(state
& ZONE
))
1518 dst
= tm
->tm_zone
->dst
;
1519 zone
= tm
->tm_zone
->west
;
1521 zone
+= tmgoff(s
, &t
, dst
);
1530 if (!(state
& ZONE
) && (zp
= tmzone(s
, &t
, type
, &dst
)))
1533 zone
= zp
->west
+ dst
;
1539 else if (!type
&& (zp
= tmtype(s
, &t
)))
1551 if (!(state
& (YEAR
|MONTH
)) && n
>= 1969 && n
< 3000 && (i
= strtol(s
+ 1, &t
, 10)) > 0 && i
<= 12)
1554 tm
->tm_year
= n
- 1900;
1560 if ((state
& MONTH
) || n
<= 0 || n
> 31)
1564 if ((i
= tmlex(s
, &t
, tm_info
.format
, TM_DAY_ABBREV
, NiL
, 0)) < 0)
1573 n
= strtol(s
, &t
, 10);
1575 if (n
<= 0 || n
> 31)
1577 if (*s
== '/' && !isdigit(*(s
+ 1)))
1588 n
= strtol(++s
, &t
, 10);
1591 if (*s
== '/' || *s
== ':' || *s
== '-' || *s
== '_')
1596 if (state
& (LAST
|NEXT
|THIS
))
1600 tm
->tm_year
-= (tm
->tm_mon
< n
) ? 0 : 1;
1602 tm
->tm_year
+= ((state
& NEXT
) ? 1 : 0) + ((tm
->tm_mon
< n
) ? 1 : 0);
1605 set
&= ~(LAST
|NEXT
|THIS
); /*AHA*/
1606 state
&= ~(LAST
|NEXT
|THIS
); /*AHA*/
1616 if ((state
& YEAR
) || n
< 1969 || n
>= 3000)
1619 tm
->tm_year
= n
- 1900;
1623 if (state
& (MONTH
|MDAY
|WDAY
))
1625 state
|= MONTH
|DAY
|MDAY
;
1629 else if (w
== 2 && !(state
& YEAR
))
1636 else if (!(state
& MONTH
) && n
>= 1 && n
<= 12)
1641 else if (!(state
& (MDAY
|WDAY
)) && n
>= 1 && n
<= 31)
1643 state
|= DAY
|MDAY
|WDAY
;
1655 if ((set
|state
) & (EXACT
|MONTH
))
1660 if ((set
|state
) & (EXACT
|DAY
|HOUR
))
1664 message((-1, "AHA#%d DAY", __LINE__
));
1666 if ((set
|state
) & (EXACT
|HOUR
))
1671 if ((set
|state
) & (EXACT
|MINUTE
))
1676 if ((set
|state
) & (EXACT
|SECOND
))
1681 if ((set
|state
) & (EXACT
|NSEC
))
1686 if (day
>= 0 && !(state
& (MDAY
|WDAY
)))
1688 message((-1, "AHA#%d day=%d dir=%d state=" FFMT
, __LINE__
, day
, dir
, FLAGS(state
)));
1695 tm
= tmxtm(tm
, tmxtime(tm
, zone
), tm
->tm_zone
);
1696 j
= day
- tm
->tm_wday
;
1699 tm
->tm_mday
+= j
+ m
* 7;
1701 for (n
= tm_data
.days
[tm
->tm_mon
] + (tm
->tm_mon
== 1 && tmisleapyear(tm
->tm_year
)); (tm
->tm_mday
+ 7) <= n
; tm
->tm_mday
+= 7);
1703 else if (day
< 0 && (state
& FINAL
) && (set
& DAY
))
1706 tm
->tm_mday
= tm_data
.days
[tm
->tm_mon
] + (tm
->tm_mon
== 1 && tmisleapyear(tm
->tm_year
));
1710 tm
->tm_mday
= (set
& FINAL
) ? (tm_data
.days
[tm
->tm_mon
] + (tm
->tm_mon
== 1 && tmisleapyear(tm
->tm_year
))) : 1;
1712 message((-1, "AHA#%d WORK mday=%d wday=%d", __LINE__
, tm
->tm_mday
, tm
->tm_wday
));
1713 if (tm
->tm_wday
== 0 && (j
= 1) || tm
->tm_wday
== 6 && (j
= 2))
1715 if ((tm
->tm_mday
+ j
) > (tm_data
.days
[tm
->tm_mon
] + (tm
->tm_mon
== 1 && tmisleapyear(tm
->tm_year
))))
1720 now
= tmxtime(tm
, zone
);
1721 if (tm
->tm_year
<= 70 && tmxsec(now
) > 31536000)