2 Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
4 See the accompanying file LICENSE, version 2000-Apr-09 or later
5 (the contents of which are also included in zip.h) for terms of use.
6 If, for some reason, all these files are missing, the Info-ZIP license
7 also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
9 /* Replacement time library functions, based on platform independent public
10 * domain timezone code from ftp://elsie.nci.nih.gov/pub, with mktime and
11 * mkgmtime from our own mktime.c in Zip.
19 * GetPlatformLocalTimezone() [different versions]
23 * 17 Jun 00, Paul Kienitz, added the PD-based tzset(), localtime(), and so on
24 * to amiga/filedate.c, replacing GNU-based functions which had
25 * replaced time_lib.c, both having been rejected for licensing
26 * reasons. Support for timezone files and leap seconds was removed.
28 * 23 Aug 00, Paul Kienitz, split into separate timezone.c file, made platform
29 * independent, copied in mktime() and mkgmtime() from Zip, renamed
30 * locale_TZ as GetPlatformLocalTimezone(), for use as a generic
31 * hook by other platforms.
43 #ifdef IZTZ_DEFINESTDGLOBALS
49 #ifndef IZTZ_GETLOCALETZINFO
50 # define IZTZ_GETLOCALETZINFO(ptzstruct, pgenrulefunct) (FALSE)
53 int real_timezone_is_set
= FALSE
; /* set by tzset() */
56 #define TZDEFRULESTRING ",M4.1.0,M10.5.0"
57 #define TZDEFAULT "EST5EDT"
60 #define MINSPERHOUR 60
61 #define HOURSPERDAY 24
63 #define DAYSPERNYEAR 365
64 #define DAYSPERLYEAR 366
65 #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
66 #define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
67 #define MONSPERYEAR 12
69 #define EPOCH_WDAY 4 /* Jan 1, 1970 was thursday */
70 #define EPOCH_YEAR 1970
71 #define TM_YEAR_BASE 1900
72 #define FIRST_GOOD_YEAR ((time_t) -1 < (time_t) 1 ? EPOCH_YEAR-68 : EPOCH_YEAR)
73 #define LAST_GOOD_YEAR (EPOCH_YEAR + ((time_t) -1 < (time_t) 1 ? 67 : 135))
75 #define YDAYS(month, year) yr_days[leap(year)][month]
77 /* Nonzero if `y' is a leap year, else zero. */
78 #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
80 /* Number of leap years from EPOCH_YEAR to `y' (not including `y' itself). */
81 #define _P4 ((EPOCH_YEAR / 4) * 4 + 1)
82 #define _P100 ((EPOCH_YEAR / 100) * 100 + 1)
83 #define _P400 ((EPOCH_YEAR / 400) * 400 + 1)
84 #define nleap(y) (((y) - _P4) / 4 - ((y) - _P100) / 100 + ((y) - _P400) / 400)
86 /* Length of month `m' (0 .. 11) */
87 #define monthlen(m, y) (yr_days[0][(m)+1] - yr_days[0][m] + \
88 ((m) == 1 && leap(y)))
90 /* internal module-level constants */
91 #ifndef IZ_MKTIME_ONLY
92 static ZCONST
char gmt
[] = "GMT";
93 static ZCONST
int mon_lengths
[2][MONSPERYEAR
] = {
94 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
95 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
97 #endif /* !IZ_MKTIME_ONLY */
98 static ZCONST
int yr_days
[2][MONSPERYEAR
+1] = {
99 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
100 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
102 #ifndef IZ_MKTIME_ONLY
103 static ZCONST
int year_lengths
[2] = {
104 DAYSPERNYEAR
, DAYSPERLYEAR
107 /* internal variables */
108 static struct state statism
;
111 /* prototypes of static functions */
112 static time_t transtime
OF((ZCONST
time_t janfirst
, ZCONST
int year
,
113 ZCONST
struct rule
* ZCONST rulep
,
114 ZCONST
long offset
));
115 static void generate_transitions
OF((register struct state
* ZCONST sp
,
116 ZCONST
struct rule
* ZCONST start
,
117 ZCONST
struct rule
* ZCONST end
));
118 static ZCONST
char *getzname
OF((ZCONST
char *strp
));
119 static ZCONST
char *getnum
OF((ZCONST
char *strp
, int * ZCONST nump
,
120 ZCONST
int min
, ZCONST
int max
));
121 static ZCONST
char *getsecs
OF((ZCONST
char *strp
, long * ZCONST secsp
));
122 static ZCONST
char *getoffset
OF((ZCONST
char *strp
, long * ZCONST offsetp
));
123 static ZCONST
char *getrule
OF((ZCONST
char *strp
, struct rule
* ZCONST rulep
));
124 static int Parse_TZ
OF((ZCONST
char *name
, register struct state
* ZCONST sp
));
127 static time_t transtime(janfirst
, year
, rulep
, offset
)
128 ZCONST
time_t janfirst
;
130 ZCONST
struct rule
* ZCONST rulep
;
133 register int leapyear
;
134 register time_t value
;
136 int d
, m1
, yy0
, yy1
, yy2
, dow
;
139 leapyear
= leap(year
);
140 switch (rulep
->r_type
) {
144 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
146 ** In non-leap years, or if the day number is 59 or less, just
147 ** add SECSPERDAY times the day number-1 to the time of
148 ** January 1, midnight, to get the day.
150 value
= janfirst
+ (rulep
->r_day
- 1) * SECSPERDAY
;
151 if (leapyear
&& rulep
->r_day
>= 60)
158 ** Just add SECSPERDAY times the day number to the time of
159 ** January 1, midnight, to get the day.
161 value
= janfirst
+ rulep
->r_day
* SECSPERDAY
;
164 case MONTH_NTH_DAY_OF_WEEK
:
166 ** Mm.n.d - nth "dth day" of month m.
170 for (i = 0; i < rulep->r_mon - 1; ++i)
171 value += mon_lengths[leapyear][i] * SECSPERDAY;
173 value
+= yr_days
[leapyear
][rulep
->r_mon
- 1] * SECSPERDAY
;
176 ** Use Zeller's Congruence to get day-of-week of first day of
179 m1
= (rulep
->r_mon
+ 9) % 12 + 1;
180 yy0
= (rulep
->r_mon
<= 2) ? (year
- 1) : year
;
183 dow
= ((26 * m1
- 2) / 10 +
184 1 + yy2
+ yy2
/ 4 + yy1
/ 4 - 2 * yy1
) % 7;
189 ** "dow" is the day-of-week of the first day of the month. Get
190 ** the day-of-month (zero-origin) of the first "dow" day of the
193 d
= rulep
->r_day
- dow
;
196 for (i
= 1; i
< rulep
->r_week
; ++i
) {
197 if (d
+ DAYSPERWEEK
>= mon_lengths
[leapyear
][rulep
->r_mon
- 1])
203 ** "d" is the day-of-month (zero-origin) of the day we want.
205 value
+= d
* SECSPERDAY
;
210 ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
211 ** question. To get the Epoch-relative time of the specified local
212 ** time on that day, add the transition time and the current offset
215 return value
+ rulep
->r_time
+ offset
;
218 static void generate_transitions(sp
, start
, end
)
219 register struct state
* ZCONST sp
;
220 ZCONST
struct rule
* ZCONST start
;
221 ZCONST
struct rule
* ZCONST end
;
224 register time_t janfirst
;
227 long stdoffset
= -sp
->ttis
[0].tt_gmtoff
;
228 long dstoffset
= -sp
->ttis
[1].tt_gmtoff
;
229 register time_t * atp
;
230 register unsigned char * typep
;
233 ** Two transitions per year, from EPOCH_YEAR to LAST_GOOD_YEAR.
235 sp
->timecnt
= 2 * (LAST_GOOD_YEAR
- EPOCH_YEAR
+ 1);
239 for (year
= EPOCH_YEAR
; year
<= LAST_GOOD_YEAR
; ++year
) {
240 starttime
= transtime(janfirst
, year
, start
, stdoffset
);
241 endtime
= transtime(janfirst
, year
, end
, dstoffset
);
242 if (starttime
> endtime
) {
244 *typep
++ = 0; /* DST ends */
246 *typep
++ = 1; /* DST begins */
249 *typep
++ = 1; /* DST begins */
251 *typep
++ = 0; /* DST ends */
253 janfirst
+= year_lengths
[leap(year
)] * SECSPERDAY
;
257 static ZCONST
char *getzname(strp
)
262 while ((c
= *strp
) != '\0' && !isdigit(c
) && c
!= ',' && c
!= '-' &&
268 static ZCONST
char *getnum(strp
, nump
, min
, max
)
277 if (strp
== NULL
|| !isdigit(c
= *strp
))
281 num
= num
* 10 + (c
- '0');
283 return NULL
; /* illegal value */
285 } while (isdigit(c
));
287 return NULL
; /* illegal value */
292 static ZCONST
char *getsecs(strp
, secsp
)
299 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
300 ** "M10.4.6/26", which does not conform to Posix,
301 ** but which specifies the equivalent of
302 ** ``02:00 on the first Sunday on or after 23 Oct''.
304 strp
= getnum(strp
, &num
, 0, HOURSPERDAY
* DAYSPERWEEK
- 1);
307 *secsp
= num
* (long) SECSPERHOUR
;
310 strp
= getnum(strp
, &num
, 0, MINSPERHOUR
- 1);
313 *secsp
+= num
* SECSPERMIN
;
316 /* `SECSPERMIN' allows for leap seconds. */
317 strp
= getnum(strp
, &num
, 0, SECSPERMIN
);
326 static ZCONST
char *getoffset(strp
, offsetp
)
328 long * ZCONST offsetp
;
330 register int neg
= 0;
335 } else if (*strp
== '+')
337 strp
= getsecs(strp
, offsetp
);
339 return NULL
; /* illegal time */
341 *offsetp
= -*offsetp
;
345 static ZCONST
char *getrule(strp
, rulep
)
347 struct rule
* ZCONST rulep
;
353 rulep
->r_type
= JULIAN_DAY
;
355 strp
= getnum(strp
, &rulep
->r_day
, 1, DAYSPERNYEAR
);
356 } else if (*strp
== 'M') {
360 rulep
->r_type
= MONTH_NTH_DAY_OF_WEEK
;
362 strp
= getnum(strp
, &rulep
->r_mon
, 1, MONSPERYEAR
);
367 strp
= getnum(strp
, &rulep
->r_week
, 1, 5);
372 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERWEEK
- 1);
373 } else if (isdigit(*strp
)) {
377 rulep
->r_type
= DAY_OF_YEAR
;
378 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERLYEAR
- 1);
379 } else return NULL
; /* invalid format */
387 strp
= getsecs(strp
, &rulep
->r_time
);
389 rulep
->r_time
= 2 * SECSPERHOUR
; /* default = 2:00:00 */
393 static int Parse_TZ(name
, sp
)
395 register struct state
* ZCONST sp
;
397 ZCONST
char * stdname
;
398 ZCONST
char * dstname
;
407 name
= getzname(name
);
408 stdlen
= name
- stdname
;
413 name
= getoffset(name
, &stdoffset
);
418 name
= getzname(name
);
419 dstlen
= name
- dstname
; /* length of DST zone name */
422 if (*name
!= '\0' && *name
!= ',' && *name
!= ';') {
423 name
= getoffset(name
, &dstoffset
);
427 dstoffset
= stdoffset
- SECSPERHOUR
;
429 name
= TZDEFRULESTRING
;
430 if (*name
== ',' || *name
== ';') {
435 if ((name
= getrule(name
, &start
)) == NULL
)
439 if ((name
= getrule(name
, &end
)) == NULL
)
443 sp
->typecnt
= 2; /* standard time and DST */
444 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
445 sp
->ttis
[0].tt_isdst
= 0;
446 sp
->ttis
[0].tt_abbrind
= 0;
447 sp
->ttis
[1].tt_gmtoff
= -dstoffset
;
448 sp
->ttis
[1].tt_isdst
= 1;
449 sp
->ttis
[1].tt_abbrind
= stdlen
+ 1;
450 generate_transitions(sp
, &start
, &end
);
454 sp
->typecnt
= 1; /* only standard time */
456 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
457 sp
->ttis
[0].tt_isdst
= 0;
458 sp
->ttis
[0].tt_abbrind
= 0;
460 sp
->charcnt
= stdlen
+ 1;
462 sp
->charcnt
+= dstlen
+ 1;
463 if ((size_t) sp
->charcnt
> sizeof(sp
->chars
))
466 (void) strncpy(cp
, stdname
, stdlen
);
470 (void) strncpy(cp
, dstname
, dstlen
);
471 *(cp
+ dstlen
) = '\0';
480 static char *old_TZstring
= NULL
;
482 TZstring
= getenv("TZ"); /* read TZ envvar */
483 if (old_TZstring
&& TZstring
&& !strcmp(old_TZstring
, TZstring
))
484 /* do not repeatedly parse an unchanged TZ specification */
486 if ((TZstring
&& TZstring
[0] && Parse_TZ(TZstring
, &statism
) == 0)
487 || IZTZ_GETLOCALETZINFO(&statism
, generate_transitions
)
488 || Parse_TZ(gmt
, &statism
) == 0) {
489 daylight
= statism
.typecnt
> 1;
490 dstfirst
= daylight
&& statism
.ttis
[0].tt_isdst
&& !statism
.ttis
[1].tt_isdst
;
491 timezone
= -statism
.ttis
[dstfirst
].tt_gmtoff
;
492 tzname
[0] = statism
.chars
+ statism
.ttis
[dstfirst
].tt_abbrind
;
493 tzname
[1] = statism
.chars
+ statism
.ttis
[!dstfirst
].tt_abbrind
;
494 real_timezone_is_set
= TRUE
;
497 old_TZstring
= realloc(old_TZstring
, strlen(TZstring
) + 1);
499 old_TZstring
= malloc(strlen(TZstring
) + 1);
501 strcpy(old_TZstring
, TZstring
);
504 timezone
= 0; /* default is GMT0 which means no offsets */
505 daylight
= 0; /* from local system time */
506 real_timezone_is_set
= FALSE
;
512 #ifdef IZTZ_SETLOCALTZINFO
513 /* Some SAS/C library functions, e.g. stat(), call library */
514 /* __tzset() themselves. So envvar TZ *must* exist in order to */
515 /* to get the right offset from GMT. XXX TRY HARD to fix this! */
516 set_TZ(timezone
, daylight
);
517 #endif /* IZTZ_SETLOCALTZINFO */
520 /* XXX Does this also help SAS/C library work? */
523 if (!real_timezone_is_set
) tzset();
526 static struct tm _tmbuf
;
528 struct tm
*gmtime(when
)
531 long days
= *when
/ SECSPERDAY
;
532 long secs
= *when
% SECSPERDAY
;
535 memset(&_tmbuf
, 0, sizeof(_tmbuf
)); /* get any nonstandard fields */
536 _tmbuf
.tm_wday
= (days
+ EPOCH_WDAY
) % 7;
537 _tmbuf
.tm_year
= EPOCH_YEAR
- TM_YEAR_BASE
;
538 isleap
= leap(_tmbuf
.tm_year
+ TM_YEAR_BASE
);
539 while (days
>= year_lengths
[isleap
]) {
540 days
-= year_lengths
[isleap
];
542 isleap
= leap(_tmbuf
.tm_year
+ TM_YEAR_BASE
);
545 _tmbuf
.tm_yday
= days
;
546 while (days
>= mon_lengths
[isleap
][_tmbuf
.tm_mon
])
547 days
-= mon_lengths
[isleap
][_tmbuf
.tm_mon
++];
548 _tmbuf
.tm_mday
= days
+ 1;
550 _tmbuf
.tm_sec
= secs
% SECSPERMIN
;
551 _tmbuf
.tm_min
= (secs
/ SECSPERMIN
) % SECSPERMIN
;
552 _tmbuf
.tm_hour
= secs
/ SECSPERHOUR
;
556 struct tm
*localtime(when
)
559 time_t localwhen
= *when
;
564 if (statism
.timecnt
== 0 || localwhen
< statism
.ats
[0])
565 timetype
= statism
.ttis
[0].tt_isdst
&& statism
.typecnt
> 1 &&
566 !statism
.ttis
[1].tt_isdst
;
568 for (timetype
= 1; timetype
< statism
.timecnt
; ++timetype
)
569 if (localwhen
< statism
.ats
[timetype
])
571 timetype
= statism
.types
[timetype
- 1];
573 localwhen
+= statism
.ttis
[timetype
].tt_gmtoff
;
574 ret
= gmtime(&localwhen
);
575 ret
->tm_isdst
= statism
.ttis
[timetype
].tt_isdst
;
583 time_t localt
; /* time_t equivalent of given tm struct */
584 time_t univt
; /* assumed UTC value of given time */
585 long tzoffset_adj
; /* timezone-adjustment `remainder' */
586 int bailout_cnt
; /* counter of tries for tz correction */
591 /* when DST is unsupported in current timezone, DST is always off */
592 if (statism
.typecnt
<= 1) return FALSE
;
594 localt
= mkgmtime(tb
);
595 if (localt
== (time_t)-1)
596 /* specified time is out-of-range, default to FALSE */
599 univt
= localt
- statism
.ttis
[0].tt_gmtoff
;
602 if (statism
.timecnt
== 0 || univt
< statism
.ats
[0])
603 timetype
= statism
.ttis
[0].tt_isdst
&& statism
.typecnt
> 1 &&
604 !statism
.ttis
[1].tt_isdst
;
606 for (timetype
= 1; timetype
< statism
.timecnt
; ++timetype
)
607 if (univt
< statism
.ats
[timetype
])
609 timetype
= statism
.types
[timetype
- 1];
611 if ((tzoffset_adj
= localt
- univt
- statism
.ttis
[timetype
].tt_gmtoff
)
614 univt
+= tzoffset_adj
;
615 } while (--bailout_cnt
> 0);
617 /* return TRUE when DST is active at given time */
618 return (statism
.ttis
[timetype
].tt_isdst
);
620 #endif /* NEED__ISINDST */
621 #endif /* !IZ_MKTIME_ONLY */
623 /* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT
624 of the local time and date in the exploded time structure `tm',
625 adjust out of range fields in `tm' and set `tm->tm_yday', `tm->tm_wday'.
626 If `tm->tm_isdst < 0' was passed to mktime(), the correct setting of
627 tm_isdst is determined and returned. Otherwise, mktime() assumes this
628 field as valid; its information is used when converting local time
630 Return -1 if time in `tm' cannot be represented as time_t value. */
635 struct tm
*ltm
; /* Local time. */
636 time_t loctime
; /* The time_t value of local time. */
637 time_t then
; /* The time to return. */
638 long tzoffset_adj
; /* timezone-adjustment `remainder' */
639 int bailout_cnt
; /* counter of tries for tz correction */
640 int save_isdst
; /* Copy of the tm->isdst input value */
642 save_isdst
= tm
->tm_isdst
;
643 loctime
= mkgmtime(tm
);
645 tm
->tm_isdst
= save_isdst
;
649 /* Correct for the timezone and any daylight savings time.
650 The correction is verified and repeated when not correct, to
651 take into account the rare case that a change to or from daylight
652 savings time occurs between when it is the time in `tm' locally
653 and when it is that time in Greenwich. After the second correction,
654 the "timezone & daylight" offset should be correct in all cases. To
655 be sure, we allow a third try, but then the loop is stopped. */
659 ltm
= localtime(&then
);
660 if (ltm
== (struct tm
*)NULL
||
661 (tzoffset_adj
= loctime
- mkgmtime(ltm
)) == 0L)
663 then
+= tzoffset_adj
;
664 } while (--bailout_cnt
> 0);
666 if (ltm
== (struct tm
*)NULL
|| tzoffset_adj
!= 0L) {
667 /* Signal failure if timezone adjustment did not converge. */
668 tm
->tm_isdst
= save_isdst
;
672 if (save_isdst
>= 0) {
673 if (ltm
->tm_isdst
&& !save_isdst
)
675 if (then
+ 3600 < then
)
680 else if (!ltm
->tm_isdst
&& save_isdst
)
682 if (then
- 3600 > then
)
687 ltm
->tm_isdst
= save_isdst
;
690 if (tm
!= ltm
) /* `tm' may already point to localtime's internal storage */
697 #ifndef NO_TIME_T_MAX
698 /* Provide default values for the upper limit of the time_t range.
699 These are the result of the decomposition into a `struct tm' for
700 the time value 0xFFFFFFFEL ( = (time_t)-2 ).
701 Note: `(time_t)-1' is reserved for "invalid time"! */
703 # define TM_YEAR_MAX 2106
706 # define TM_MON_MAX 1 /* February */
709 # define TM_MDAY_MAX 7
712 # define TM_HOUR_MAX 6
715 # define TM_MIN_MAX 28
718 # define TM_SEC_MAX 14
720 #endif /* NO_TIME_T_MAX */
722 /* Adjusts out-of-range values for `tm' field `tm_member'. */
723 #define ADJUST_TM(tm_member, tm_carry, modulus) \
724 if ((tm_member) < 0) { \
725 tm_carry -= (1 - ((tm_member)+1) / (modulus)); \
726 tm_member = (modulus-1) + (((tm_member)+1) % (modulus)); \
727 } else if ((tm_member) >= (modulus)) { \
728 tm_carry += (tm_member) / (modulus); \
729 tm_member = (tm_member) % (modulus); \
732 /* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT
733 of the Greenwich Mean time and date in the exploded time structure `tm'.
734 This function does always put back normalized values into the `tm' struct,
735 parameter, including the calculated numbers for `tm->tm_yday',
736 `tm->tm_wday', and `tm->tm_isdst'.
737 Returns -1 if the time in the `tm' parameter cannot be represented
738 as valid `time_t' number. */
743 int years
, months
, days
, hours
, minutes
, seconds
;
745 years
= tm
->tm_year
+ TM_YEAR_BASE
; /* year - 1900 -> year */
746 months
= tm
->tm_mon
; /* 0..11 */
747 days
= tm
->tm_mday
- 1; /* 1..31 -> 0..30 */
748 hours
= tm
->tm_hour
; /* 0..23 */
749 minutes
= tm
->tm_min
; /* 0..59 */
750 seconds
= tm
->tm_sec
; /* 0..61 in ANSI C. */
752 ADJUST_TM(seconds
, minutes
, 60)
753 ADJUST_TM(minutes
, hours
, 60)
754 ADJUST_TM(hours
, days
, 24)
755 ADJUST_TM(months
, years
, 12)
762 days
+= monthlen(months
, years
);
765 while (days
>= monthlen(months
, years
)) {
766 days
-= monthlen(months
, years
);
767 if (++months
>= 12) {
773 /* Restore adjusted values in tm structure */
774 tm
->tm_year
= years
- TM_YEAR_BASE
;
776 tm
->tm_mday
= days
+ 1;
778 tm
->tm_min
= minutes
;
779 tm
->tm_sec
= seconds
;
781 /* Set `days' to the number of days into the year. */
782 days
+= YDAYS(months
, years
);
785 /* Now calculate `days' to the number of days since Jan 1, 1970. */
786 days
= (unsigned)days
+ 365 * (unsigned)(years
- EPOCH_YEAR
) +
787 (unsigned)(nleap (years
));
788 tm
->tm_wday
= ((unsigned)days
+ EPOCH_WDAY
) % 7;
791 if (years
< EPOCH_YEAR
)
794 #if (defined(TM_YEAR_MAX) && defined(TM_MON_MAX) && defined(TM_MDAY_MAX))
795 #if (defined(TM_HOUR_MAX) && defined(TM_MIN_MAX) && defined(TM_SEC_MAX))
796 if (years
> TM_YEAR_MAX
||
797 (years
== TM_YEAR_MAX
&&
798 (tm
->tm_yday
> (YDAYS(TM_MON_MAX
, TM_YEAR_MAX
) + (TM_MDAY_MAX
- 1)) ||
799 (tm
->tm_yday
== (YDAYS(TM_MON_MAX
, TM_YEAR_MAX
) + (TM_MDAY_MAX
- 1)) &&
800 (hours
> TM_HOUR_MAX
||
801 (hours
== TM_HOUR_MAX
&&
802 (minutes
> TM_MIN_MAX
||
803 (minutes
== TM_MIN_MAX
&& seconds
> TM_SEC_MAX
) )))))))
808 return (time_t)(SECSPERDAY
* (unsigned long)(unsigned)days
+
809 SECSPERHOUR
* (unsigned long)hours
+
810 (unsigned long)(SECSPERMIN
* minutes
+ seconds
));
813 #endif /* __timezone_c */