fd7eda2478ed30000309fc87bc32c0920d8b0218
4 /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
5 /* This file has been modified by DJ Delorie. These modifications are
6 ** Copyright (C) 1995 DJ Delorie, 24 Kirsten Ave, Rochester NH,
11 * Copyright (c) 1987, 1989 Regents of the University of California.
12 * All rights reserved.
14 * This code is derived from software contributed to Berkeley by
15 * Arthur David Olson of the National Cancer Institute.
17 * Redistribution and use in source and binary forms are permitted provided
18 * that: (1) source distributions retain this entire copyright notice and
19 * comment, and (2) distributions including binaries display the following
20 * acknowledgement: ``This product includes software developed by the
21 * University of California, Berkeley and its contributors'' in the
22 * documentation or other materials provided with the distribution and in
23 * all advertising materials mentioning features or use of this software.
24 * Neither the name of the University nor the names of its contributors may
25 * be used to endorse or promote products derived from this software without
26 * specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
28 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
29 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
33 ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
34 ** POSIX-style TZ environment variable handling from Guy Harris
44 #define CPP_CONST const
51 #define alloc_size_t size_t
52 #define qsort_size_t size_t
53 #define fread_size_t size_t
54 #define fwrite_size_t size_t
56 #define ACCESS_MODE O_RDONLY|O_BINARY
57 #define OPEN_MODE O_RDONLY|O_BINARY
60 ** Someone might make incorrect use of a time zone abbreviation:
61 ** 1. They might reference tzname[0] before calling tzset (explicitly
63 ** 2. They might reference tzname[1] before calling tzset (explicitly
65 ** 3. They might reference tzname[1] after setting to a time zone
66 ** in which Daylight Saving Time is never observed.
67 ** 4. They might reference tzname[0] after setting to a time zone
68 ** in which Standard Time is never observed.
69 ** 5. They might reference tm.TM_ZONE after calling offtime.
70 ** What's best to do in the above cases is open to debate;
71 ** for now, we just set things up so that in any of the five cases
72 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
73 ** string "tzname[0] used before set", and similarly for the other cases.
74 ** And another: initialize tzname[0] to "ERA", with an explanation in the
75 ** manual page of what this "time zone abbreviation" means (doing this so
76 ** that tzname[0] has the "normal" length of three characters).
79 void _set_daylight_export(int);
80 void _set_timezone_export(int);
83 /* buffers must hold 64 characters! */
84 static char TZ_NAME
[64] = "PST";
85 static char TZ_DST_NAME
[64] = "PDT";
90 #endif /* !defined TRUE */
92 static const char GMT
[] = "GMT";
94 struct ttinfo
{ /* time type information */
95 long tt_gmtoff
; /* GMT offset in seconds */
96 int tt_isdst
; /* used to set tm_isdst */
97 int tt_abbrind
; /* abbreviation list index */
98 int tt_ttisstd
; /* TRUE if transition is std time */
101 struct lsinfo
{ /* leap second information */
102 time_t ls_trans
; /* transition time */
103 long ls_corr
; /* correction to apply */
111 time_t ats
[TZ_MAX_TIMES
];
112 unsigned char types
[TZ_MAX_TIMES
];
113 struct ttinfo ttis
[TZ_MAX_TYPES
];
114 char chars
[(TZ_MAX_CHARS
+ 1 > sizeof GMT
) ? TZ_MAX_CHARS
+ 1 : sizeof GMT
];
115 struct lsinfo lsis
[TZ_MAX_LEAPS
];
119 int r_type
; /* type of rule--see below */
120 int r_day
; /* day number of rule */
121 int r_week
; /* week number of rule */
122 int r_mon
; /* month number of rule */
123 long r_time
; /* transition time of rule */
126 #define JULIAN_DAY 0 /* Jn - Julian day */
127 #define DAY_OF_YEAR 1 /* n - day of year */
128 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
131 ** Prototypes for static functions.
134 static long detzcode
P((const char * codep
));
135 static const char * getzname
P((const char * strp
));
136 static const char * getnum
P((const char * strp
, int * nump
, int min
, int max
));
137 static const char * getsecs
P((const char * strp
, long * secsp
));
138 static const char * getoffset
P((const char * strp
, long * offsetp
));
139 static const char * getrule
P((const char * strp
, struct rule
* rulep
));
140 static void gmtload
P((struct state
* sp
));
141 static void gmtsub
P((const time_t * timep
, long offset
, struct tm
* tmp
));
142 static void localsub
P((const time_t * timep
, long offset
, struct tm
* tmp
));
143 static void normalize
P((int * tensptr
, int * unitsptr
, int base
));
144 static void settzname
P((void));
145 static time_t time1
P((struct tm
* tmp
, void (* funcp
)(const time_t * CPP_CONST
, const long, struct tm
* CPP_CONST
), long offset
));
146 static time_t time2
P((struct tm
*tmp
, void (* funcp
)(const time_t * CPP_CONST
, const long, struct tm
* CPP_CONST
), long offset
, int * okayp
));
147 static void timesub
P((const time_t * timep
, long offset
, const struct state
* sp
, struct tm
* tmp
));
148 static int tmcomp
P((const struct tm
* atmp
, const struct tm
* btmp
));
149 static time_t transtime
P((time_t janfirst
, int year
, const struct rule
* rulep
, long offset
));
150 static int tzload
P((const char * name
, struct state
* sp
));
151 static int tzparse
P((const char * name
, struct state
* sp
, int lastditch
));
152 static void tzsetwall(void);
156 static const char * getnum(const char * strp
, int * CPP_CONST nump
, const int min
, const int max
);
157 static void timesub(const time_t * CPP_CONST timep
, const long offset
, const struct state
* CPP_CONST sp
, struct tm
* CPP_CONST tmp
);
158 static time_t transtime(const time_t janfirst
, const int year
, const struct rule
* CPP_CONST rulep
, const long offset
);
159 static void tzsetwall(void);
164 static struct state
*lclptr
;
165 static struct state
*gmtptr
;
166 #endif /* defined ALL_STATE */
169 static struct state lclmem
;
170 static struct state gmtmem
;
171 #define lclptr (&lclmem)
172 #define gmtptr (&gmtmem)
173 #endif /* State Farm */
175 static int lcl_is_set
;
176 static int gmt_is_set
;
178 char * _tzname
[2] = {
184 detzcode(const char * CPP_CONST codep
)
190 for (i
= 0; i
< 4; ++i
)
191 result
= (result
<< 8) | (codep
[i
] & 0xff);
198 const struct state
* CPP_CONST sp
= lclptr
;
201 _tzname
[0] = TZ_NAME
;
202 _tzname
[1] = TZ_DST_NAME
;
206 _tzname
[0] = _tzname
[1] = GMT
;
209 #endif /* defined ALL_STATE */
210 for (i
= 0; i
< sp
->typecnt
; ++i
)
212 register const struct ttinfo
* CPP_CONST ttisp
= &sp
->ttis
[i
];
214 _tzname
[ttisp
->tt_isdst
] =
215 (char *)&sp
->chars
[ttisp
->tt_abbrind
];
217 if (ttisp
->tt_isdst
) {
219 _set_daylight_export(1);
221 if (i
== 0 || !ttisp
->tt_isdst
) {
222 //_timezone_dll = -(ttisp->tt_gmtoff);
223 _set_timezone_export(-(ttisp
->tt_gmtoff
));
225 if (i
== 0 || ttisp
->tt_isdst
) {
226 _altzone
= -(ttisp
->tt_gmtoff
);
231 ** And to get the latest zone names into tzname. . .
233 for (i
= 0; i
< sp
->timecnt
; ++i
)
235 const struct ttinfo
* CPP_CONST ttisp
= &sp
->ttis
[sp
->types
[i
]];
237 _tzname
[ttisp
->tt_isdst
] = (char *)&sp
->chars
[ttisp
->tt_abbrind
];
241 static char* tzdir(void)
243 static char dir
[80]={0}, *cp
;
246 if ((cp
= getenv("TZDIR")))
250 else if ((cp
= getenv("DJDIR")))
253 strcat(dir
, "/zoneinfo");
261 static int tzload(const char* name
, struct state
* CPP_CONST sp
)
266 char fullname
[FILENAME_MAX
+ 1];
267 const struct tzhead
* tzhp
;
268 char buf
[sizeof *sp
+ sizeof *tzhp
];
271 if (name
== NULL
&& (name
= TZDEFAULT
) == NULL
)
278 if ((p
= tzdir()) == NULL
)
280 if ((strlen(p
) + strlen(name
) + 1) >= sizeof fullname
)
283 strcat(fullname
, "/");
284 strcat(fullname
, name
);
288 if ((fid
= _open(name
, OPEN_MODE
)) == -1)
290 const char *base
= strrchr(name
, '/');
295 if (strcmp(base
, "posixrules"))
298 /* We've got a built-in copy of posixrules just in case */
299 memcpy(buf
, _posixrules_data
, sizeof(_posixrules_data
));
300 i
= sizeof(_posixrules_data
);
304 i
= _read(fid
, buf
, sizeof buf
);
305 if (_close(fid
) != 0 || i
< (int)sizeof *tzhp
)
309 tzhp
= (struct tzhead
*) buf
;
310 ttisstdcnt
= (int) detzcode(tzhp
->tzh_ttisstdcnt
);
311 sp
->leapcnt
= (int) detzcode(tzhp
->tzh_leapcnt
);
312 sp
->timecnt
= (int) detzcode(tzhp
->tzh_timecnt
);
313 sp
->typecnt
= (int) detzcode(tzhp
->tzh_typecnt
);
314 sp
->charcnt
= (int) detzcode(tzhp
->tzh_charcnt
);
315 if (sp
->leapcnt
< 0 || sp
->leapcnt
> TZ_MAX_LEAPS
||
316 sp
->typecnt
<= 0 || sp
->typecnt
> TZ_MAX_TYPES
||
317 sp
->timecnt
< 0 || sp
->timecnt
> TZ_MAX_TIMES
||
318 sp
->charcnt
< 0 || sp
->charcnt
> TZ_MAX_CHARS
||
319 (ttisstdcnt
!= sp
->typecnt
&& ttisstdcnt
!= 0))
321 if (i
< (int)sizeof *tzhp
+
322 sp
->timecnt
* (4 + (int)sizeof (char)) +
323 sp
->typecnt
* (4 + 2 * (int)sizeof (char)) +
324 sp
->charcnt
* (int)sizeof (char) +
325 sp
->leapcnt
* 2 * 4 +
326 ttisstdcnt
* (int)sizeof (char))
328 p
= buf
+ sizeof *tzhp
;
329 for (i
= 0; i
< sp
->timecnt
; ++i
)
331 sp
->ats
[i
] = detzcode(p
);
334 for (i
= 0; i
< sp
->timecnt
; ++i
)
336 sp
->types
[i
] = (unsigned char) *p
++;
337 if (sp
->types
[i
] >= sp
->typecnt
)
340 for (i
= 0; i
< sp
->typecnt
; ++i
)
342 struct ttinfo
* ttisp
;
344 ttisp
= &sp
->ttis
[i
];
345 ttisp
->tt_gmtoff
= detzcode(p
);
347 ttisp
->tt_isdst
= (unsigned char) *p
++;
348 if (ttisp
->tt_isdst
!= 0 && ttisp
->tt_isdst
!= 1)
350 ttisp
->tt_abbrind
= (unsigned char) *p
++;
351 if (ttisp
->tt_abbrind
< 0 ||
352 ttisp
->tt_abbrind
> sp
->charcnt
)
355 for (i
= 0; i
< sp
->charcnt
; ++i
)
357 sp
->chars
[i
] = '\0'; /* ensure '\0' at end */
358 for (i
= 0; i
< sp
->leapcnt
; ++i
)
360 struct lsinfo
* lsisp
;
362 lsisp
= &sp
->lsis
[i
];
363 lsisp
->ls_trans
= detzcode(p
);
365 lsisp
->ls_corr
= detzcode(p
);
368 for (i
= 0; i
< sp
->typecnt
; ++i
)
370 struct ttinfo
* ttisp
;
372 ttisp
= &sp
->ttis
[i
];
374 ttisp
->tt_ttisstd
= FALSE
;
377 ttisp
->tt_ttisstd
= *p
++;
378 if (ttisp
->tt_ttisstd
!= TRUE
&&
379 ttisp
->tt_ttisstd
!= FALSE
)
386 static const int mon_lengths
[2][MONSPERYEAR
] = {
387 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
388 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
391 static const int year_lengths
[2] = {
392 DAYSPERNYEAR
, DAYSPERLYEAR
396 ** Given a pointer into a time zone string, scan until a character that is not
397 ** a valid character in a zone name is found. Return a pointer to that
402 getzname(const char* strp
)
406 while ((c
= *strp
) != '\0' && !isdigit(c
) && c
!= ',' && c
!= '-' &&
413 ** Given a pointer into a time zone string, extract a number from that string.
414 ** Check that the number is within a specified range; if it is not, return
416 ** Otherwise, return a pointer to the first character not part of the number.
420 getnum(const char* strp
, int* CPP_CONST nump
, const int min
, const int max
)
425 if (strp
== NULL
|| !isdigit(*strp
))
428 while ((c
= *strp
) != '\0' && isdigit(c
))
430 num
= num
* 10 + (c
- '0');
442 ** Given a pointer into a time zone string, extract a number of seconds,
443 ** in hh[:mm[:ss]] form, from the string.
444 ** If any error occurs, return NULL.
445 ** Otherwise, return a pointer to the first character not part of the number
450 getsecs(const char *strp
, long * CPP_CONST secsp
)
454 strp
= getnum(strp
, &num
, 0, HOURSPERDAY
);
457 *secsp
= num
* SECSPERHOUR
;
461 strp
= getnum(strp
, &num
, 0, MINSPERHOUR
- 1);
464 *secsp
+= num
* SECSPERMIN
;
468 strp
= getnum(strp
, &num
, 0, SECSPERMIN
- 1);
478 ** Given a pointer into a time zone string, extract an offset, in
479 ** [+-]hh[:mm[:ss]] form, from the string.
480 ** If any error occurs, return NULL.
481 ** Otherwise, return a pointer to the first character not part of the time.
485 getoffset(const char *strp
, long * CPP_CONST offsetp
)
494 else if (isdigit(*strp
) || *strp
++ == '+')
497 return NULL
; /* illegal offset */
498 strp
= getsecs(strp
, offsetp
);
500 return NULL
; /* illegal time */
502 *offsetp
= -*offsetp
;
507 ** Given a pointer into a time zone string, extract a rule in the form
508 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
509 ** If a valid rule is not found, return NULL.
510 ** Otherwise, return a pointer to the first character not part of the rule.
514 getrule(const char *strp
, struct rule
* CPP_CONST rulep
)
521 rulep
->r_type
= JULIAN_DAY
;
523 strp
= getnum(strp
, &rulep
->r_day
, 1, DAYSPERNYEAR
);
525 else if (*strp
== 'M')
530 rulep
->r_type
= MONTH_NTH_DAY_OF_WEEK
;
532 strp
= getnum(strp
, &rulep
->r_mon
, 1, MONSPERYEAR
);
537 strp
= getnum(strp
, &rulep
->r_week
, 1, 5);
542 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERWEEK
- 1);
544 else if (isdigit(*strp
))
549 rulep
->r_type
= DAY_OF_YEAR
;
550 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERLYEAR
- 1);
553 return NULL
; /* invalid format */
562 strp
= getsecs(strp
, &rulep
->r_time
);
565 rulep
->r_time
= 2 * SECSPERHOUR
; /* default = 2:00:00 */
570 ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
571 ** year, a rule, and the offset from GMT at the time that rule takes effect,
572 ** calculate the Epoch-relative time that rule takes effect.
576 transtime(const time_t janfirst
, const int year
, const struct rule
* CPP_CONST rulep
, const long offset
)
581 int d
, m1
, yy0
, yy1
, yy2
, dow
;
583 leapyear
= isleap(year
);
584 switch (rulep
->r_type
)
589 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
591 ** In non-leap years, or if the day number is 59 or less, just
592 ** add SECSPERDAY times the day number-1 to the time of
593 ** January 1, midnight, to get the day.
595 value
= janfirst
+ (rulep
->r_day
- 1) * SECSPERDAY
;
596 if (leapyear
&& rulep
->r_day
>= 60)
603 ** Just add SECSPERDAY times the day number to the time of
604 ** January 1, midnight, to get the day.
606 value
= janfirst
+ rulep
->r_day
* SECSPERDAY
;
609 case MONTH_NTH_DAY_OF_WEEK
:
611 ** Mm.n.d - nth "dth day" of month m.
614 for (i
= 0; i
< rulep
->r_mon
- 1; ++i
)
615 value
+= mon_lengths
[leapyear
][i
] * SECSPERDAY
;
618 ** Use Zeller's Congruence to get day-of-week of first day of
621 m1
= (rulep
->r_mon
+ 9) % 12 + 1;
622 yy0
= (rulep
->r_mon
<= 2) ? (year
- 1) : year
;
625 dow
= ((26 * m1
- 2) / 10 +
626 1 + yy2
+ yy2
/ 4 + yy1
/ 4 - 2 * yy1
) % 7;
631 ** "dow" is the day-of-week of the first day of the month. Get
632 ** the day-of-month (zero-origin) of the first "dow" day of the
635 d
= rulep
->r_day
- dow
;
638 for (i
= 1; i
< rulep
->r_week
; ++i
)
640 if (d
+ DAYSPERWEEK
>=
641 mon_lengths
[leapyear
][rulep
->r_mon
- 1])
647 ** "d" is the day-of-month (zero-origin) of the day we want.
649 value
+= d
* SECSPERDAY
;
654 ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
655 ** question. To get the Epoch-relative time of the specified local
656 ** time on that day, add the transition time and the current offset
659 return value
+ rulep
->r_time
+ offset
;
663 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
668 tzparse(const char *name
, struct state
* CPP_CONST sp
, const int lastditch
)
670 const char * stdname
;
671 const char * dstname
=0;
677 unsigned char * typep
;
684 stdlen
= strlen(name
); /* length of standard zone name */
686 if (stdlen
>= (int)sizeof sp
->chars
)
687 stdlen
= (int)(sizeof sp
->chars
) - 1;
691 name
= getzname(name
);
692 stdlen
= name
- stdname
;
700 name
= getoffset(name
, &stdoffset
);
704 load_result
= tzload(TZDEFRULES
, sp
);
705 if (load_result
!= 0)
706 sp
->leapcnt
= 0; /* so, we're off a little */
710 name
= getzname(name
);
711 dstlen
= name
- dstname
; /* length of DST zone name */
714 if (*name
!= '\0' && *name
!= ',' && *name
!= ';')
716 name
= getoffset(name
, &dstoffset
);
721 dstoffset
= stdoffset
- SECSPERHOUR
;
722 if (*name
== ',' || *name
== ';')
732 if ((name
= getrule(name
, &start
)) == NULL
)
736 if ((name
= getrule(name
, &end
)) == NULL
)
740 sp
->typecnt
= 2; /* standard time and DST */
742 ** Two transitions per year, from EPOCH_YEAR to 2037.
744 sp
->timecnt
= 2 * (2037 - EPOCH_YEAR
+ 1);
745 if (sp
->timecnt
> TZ_MAX_TIMES
)
747 sp
->ttis
[0].tt_gmtoff
= -dstoffset
;
748 sp
->ttis
[0].tt_isdst
= 1;
749 sp
->ttis
[0].tt_abbrind
= stdlen
+ 1;
750 sp
->ttis
[1].tt_gmtoff
= -stdoffset
;
751 sp
->ttis
[1].tt_isdst
= 0;
752 sp
->ttis
[1].tt_abbrind
= 0;
756 for (year
= EPOCH_YEAR
; year
<= 2037; ++year
)
758 starttime
= transtime(janfirst
, year
, &start
,
760 endtime
= transtime(janfirst
, year
, &end
,
762 if (starttime
> endtime
)
765 *typep
++ = 1; /* DST ends */
767 *typep
++ = 0; /* DST begins */
772 *typep
++ = 0; /* DST begins */
774 *typep
++ = 1; /* DST ends */
777 year_lengths
[isleap(year
)] * SECSPERDAY
;
792 if (load_result
!= 0)
795 ** Compute the difference between the real and
796 ** prototype standard and summer time offsets
797 ** from GMT, and put the real standard and summer
798 ** time offsets into the rules in place of the
799 ** prototype offsets.
805 for (i
= 0; i
< sp
->typecnt
; ++i
)
807 if (sp
->ttis
[i
].tt_isdst
)
811 sp
->ttis
[i
].tt_gmtoff
+ dstoffset
;
812 if (sawdst
&& (oldfix
!= dstfix
))
814 sp
->ttis
[i
].tt_gmtoff
= -dstoffset
;
815 sp
->ttis
[i
].tt_abbrind
= stdlen
+ 1;
822 sp
->ttis
[i
].tt_gmtoff
+ stdoffset
;
823 if (sawstd
&& (oldfix
!= stdfix
))
825 sp
->ttis
[i
].tt_gmtoff
= -stdoffset
;
826 sp
->ttis
[i
].tt_abbrind
= 0;
831 ** Make sure we have both standard and summer time.
833 if (!sawdst
|| !sawstd
)
836 ** Now correct the transition times by shifting
837 ** them by the difference between the real and
838 ** prototype offsets. Note that this difference
839 ** can be different in standard and summer time;
840 ** the prototype probably has a 1-hour difference
841 ** between standard and summer time, but a different
842 ** difference can be specified in TZ.
844 isdst
= FALSE
; /* we start in standard time */
845 for (i
= 0; i
< sp
->timecnt
; ++i
)
847 const struct ttinfo
* ttisp
;
850 ** If summer time is in effect, and the
851 ** transition time was not specified as
852 ** standard time, add the summer time
853 ** offset to the transition time;
854 ** otherwise, add the standard time offset
855 ** to the transition time.
857 ttisp
= &sp
->ttis
[sp
->types
[i
]];
859 (isdst
&& !ttisp
->tt_ttisstd
) ?
861 isdst
= ttisp
->tt_isdst
;
868 sp
->typecnt
= 1; /* only standard time */
870 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
871 sp
->ttis
[0].tt_isdst
= 0;
872 sp
->ttis
[0].tt_abbrind
= 0;
874 sp
->charcnt
= stdlen
+ 1;
876 sp
->charcnt
+= dstlen
+ 1;
877 if (sp
->charcnt
> (int)sizeof sp
->chars
)
880 (void) strncpy(cp
, stdname
, stdlen
);
885 (void) strncpy(cp
, dstname
, dstlen
);
886 *(cp
+ dstlen
) = '\0';
892 gmtload(struct state
* CPP_CONST sp
)
894 if (tzload(GMT
, sp
) != 0)
895 (void) tzparse(GMT
, sp
, TRUE
);
916 lclptr
= (struct state
*) malloc(sizeof *lclptr
);
919 settzname(); /* all we can do */
923 #endif /* defined ALL_STATE */
927 ** User wants it fast rather than right.
929 lclptr
->leapcnt
= 0; /* so, we're off a little */
931 lclptr
->ttis
[0].tt_gmtoff
= 0;
932 lclptr
->ttis
[0].tt_abbrind
= 0;
933 (void) strcpy(lclptr
->chars
, GMT
);
935 else if (tzload(name
, lclptr
) != 0)
936 if (name
[0] == ':' || tzparse(name
, lclptr
, FALSE
) != 0)
948 lclptr
= (struct state
*) malloc(sizeof *lclptr
);
951 settzname(); /* all we can do */
955 #endif /* defined ALL_STATE */
956 if (tzload((char *) NULL
, lclptr
) != 0)
962 ** The easy way to behave "as if no library function calls" localtime
963 ** is to not call it--so we drop its guts into "localsub", which can be
964 ** freely called. (And no, the PANS doesn't require the above behavior--
965 ** but it *is* desirable.)
967 ** The unused offset argument is for the benefit of mktime variants.
972 localsub(const time_t * CPP_CONST timep
, const long offset
, struct tm
* CPP_CONST tmp
)
974 const struct state
* sp
;
975 const struct ttinfo
* ttisp
;
977 const time_t t
= *timep
;
985 gmtsub(timep
, offset
, tmp
);
988 #endif /* defined ALL_STATE */
989 if (sp
->timecnt
== 0 || t
< sp
->ats
[0])
992 while (sp
->ttis
[i
].tt_isdst
)
993 if (++i
>= sp
->typecnt
)
1001 for (i
= 1; i
< sp
->timecnt
; ++i
)
1004 i
= sp
->types
[i
- 1];
1006 ttisp
= &sp
->ttis
[i
];
1008 ** To get (wrong) behavior that's compatible with System V Release 2.0
1009 ** you'd replace the statement below with
1010 ** t += ttisp->tt_gmtoff;
1011 ** timesub(&t, 0L, sp, tmp);
1013 timesub(&t
, ttisp
->tt_gmtoff
, sp
, tmp
);
1014 tmp
->tm_isdst
= ttisp
->tt_isdst
;
1015 _tzname
[tmp
->tm_isdst
] = (char *)&sp
->chars
[ttisp
->tt_abbrind
];
1017 /* tm_zone doesnt exist in windows msvcrt -Gunnar */
1018 tmp
->tm_zone
= (char *)&sp
->chars
[ttisp
->tt_abbrind
];
1026 localtime(const time_t * CPP_CONST timep
)
1028 static struct tm tm
;
1030 localsub(timep
, 0L, &tm
);
1035 ** gmtsub is to gmtime as localsub is to localtime.
1039 gmtsub(const time_t * CPP_CONST timep
, const long offset
, struct tm
* CPP_CONST tmp
)
1045 gmtptr
= (struct state
*) malloc(sizeof *gmtptr
);
1047 #endif /* defined ALL_STATE */
1050 timesub(timep
, offset
, gmtptr
, tmp
);
1052 ** Could get fancy here and deliver something such as
1053 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
1054 ** but this is no time for a treasure hunt.
1057 /* tm_zone doesnt exist in windows msvcrt -Gunnar */
1059 tmp
->tm_zone
= TZ_NAME
;
1066 tmp
->TM_ZONE
= gmtptr
->chars
;
1067 #endif /* defined ALL_STATE */
1069 tmp
->tm_zone
= gmtptr
->chars
;
1070 #endif /* State Farm */
1079 gmtime(const time_t * CPP_CONST timep
)
1081 static struct tm tm
;
1083 gmtsub(timep
, 0L, &tm
);
1088 timesub(const time_t * CPP_CONST timep
, const long offset
, const struct state
* CPP_CONST sp
, struct tm
* CPP_CONST tmp
)
1090 const struct lsinfo
* lp
;
1103 i
= (sp
== NULL
) ? 0 : sp
->leapcnt
;
1104 #endif /* defined ALL_STATE */
1107 #endif /* State Farm */
1111 if (*timep
>= lp
->ls_trans
)
1113 if (*timep
== lp
->ls_trans
)
1114 hit
= ((i
== 0 && lp
->ls_corr
> 0) ||
1115 lp
->ls_corr
> sp
->lsis
[i
- 1].ls_corr
);
1120 days
= *timep
/ SECSPERDAY
;
1121 rem
= *timep
% SECSPERDAY
;
1123 if (*timep
== 0x80000000)
1126 ** A 3B1 muffs the division on the most negative number.
1132 rem
+= (offset
- corr
);
1138 while (rem
>= SECSPERDAY
)
1143 tmp
->tm_hour
= (int) (rem
/ SECSPERHOUR
);
1144 rem
= rem
% SECSPERHOUR
;
1145 tmp
->tm_min
= (int) (rem
/ SECSPERMIN
);
1146 tmp
->tm_sec
= (int) (rem
% SECSPERMIN
);
1149 ** A positive leap second requires a special
1150 ** representation. This uses "... ??:59:60".
1153 tmp
->tm_wday
= (int) ((EPOCH_WDAY
+ days
) % DAYSPERWEEK
);
1154 if (tmp
->tm_wday
< 0)
1155 tmp
->tm_wday
+= DAYSPERWEEK
;
1161 if (days
< (long) year_lengths
[yleap
])
1164 days
= days
- (long) year_lengths
[yleap
];
1170 days
= days
+ (long) year_lengths
[yleap
];
1172 tmp
->tm_year
= y
- TM_YEAR_BASE
;
1173 tmp
->tm_yday
= (int) days
;
1174 ip
= mon_lengths
[yleap
];
1175 for (tmp
->tm_mon
= 0; days
>= (long) ip
[tmp
->tm_mon
]; ++(tmp
->tm_mon
))
1176 days
= days
- (long) ip
[tmp
->tm_mon
];
1177 tmp
->tm_mday
= (int) (days
+ 1);
1180 /* tm_gmtoff doesnt exist in windows msvcrt -Gunnar */
1181 tmp
->tm_gmtoff
= offset
;
1193 asctime(const struct tm
*timeptr
)
1195 static const char wday_name
[DAYSPERWEEK
][3] = {
1196 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1198 static const char mon_name
[MONSPERYEAR
][3] = {
1199 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1200 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1202 static char result
[26];
1204 (void) sprintf(result
, "%.3s %.3s%3d %02d:%02d:%02d %d\n",
1205 wday_name
[timeptr
->tm_wday
],
1206 mon_name
[timeptr
->tm_mon
],
1207 timeptr
->tm_mday
, timeptr
->tm_hour
,
1208 timeptr
->tm_min
, timeptr
->tm_sec
,
1209 TM_YEAR_BASE
+ timeptr
->tm_year
);
1217 ctime(const time_t * CPP_CONST timep
)
1219 return asctime(localtime(timep
));
1223 ** Adapted from code provided by Robert Elz, who writes:
1224 ** The "best" way to do mktime I think is based on an idea of Bob
1225 ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
1226 ** It does a binary search of the time_t space. Since time_t's are
1227 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
1228 ** would still be very reasonable).
1233 #endif /* !defined WRONG */
1236 normalize(int * CPP_CONST tensptr
, int * CPP_CONST unitsptr
, const int base
)
1238 if (*unitsptr
>= base
)
1240 *tensptr
+= *unitsptr
/ base
;
1243 else if (*unitsptr
< 0)
1249 *tensptr
-= 1 + (-*unitsptr
) / base
;
1250 *unitsptr
= base
- (-*unitsptr
) % base
;
1256 tmcomp(const struct tm
* CPP_CONST atmp
, const struct tm
* CPP_CONST btmp
)
1260 if ((result
= (atmp
->tm_year
- btmp
->tm_year
)) == 0 &&
1261 (result
= (atmp
->tm_mon
- btmp
->tm_mon
)) == 0 &&
1262 (result
= (atmp
->tm_mday
- btmp
->tm_mday
)) == 0 &&
1263 (result
= (atmp
->tm_hour
- btmp
->tm_hour
)) == 0 &&
1264 (result
= (atmp
->tm_min
- btmp
->tm_min
)) == 0)
1265 result
= atmp
->tm_sec
- btmp
->tm_sec
;
1270 time2(struct tm
*tmp
, void (*const funcp
)(const time_t * CPP_CONST
, const long, struct tm
*), const long offset
, int * CPP_CONST okayp
)
1272 const struct state
* sp
;
1280 /* GCC complaints that it may be used uninitialized */
1281 struct tm yourtm
, mytm
= { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1285 if (yourtm
.tm_sec
>= SECSPERMIN
+ 2 || yourtm
.tm_sec
< 0)
1286 normalize(&yourtm
.tm_min
, &yourtm
.tm_sec
, SECSPERMIN
);
1287 normalize(&yourtm
.tm_hour
, &yourtm
.tm_min
, MINSPERHOUR
);
1288 normalize(&yourtm
.tm_mday
, &yourtm
.tm_hour
, HOURSPERDAY
);
1289 normalize(&yourtm
.tm_year
, &yourtm
.tm_mon
, MONSPERYEAR
);
1290 while (yourtm
.tm_mday
<= 0)
1294 year_lengths
[isleap(yourtm
.tm_year
+ TM_YEAR_BASE
)];
1298 i
= mon_lengths
[isleap(yourtm
.tm_year
+
1299 TM_YEAR_BASE
)][yourtm
.tm_mon
];
1300 if (yourtm
.tm_mday
<= i
)
1302 yourtm
.tm_mday
-= i
;
1303 if (++yourtm
.tm_mon
>= MONSPERYEAR
)
1309 saved_seconds
= yourtm
.tm_sec
;
1312 ** Calculate the number of magnitude bits in a time_t
1313 ** (this works regardless of whether time_t is
1314 ** signed or unsigned, though lint complains if unsigned).
1316 for (bits
= 0, t
= 1; t
> 0; ++bits
, t
<<= 1)
1319 ** If time_t is signed, then 0 is the median value,
1320 ** if time_t is unsigned, then 1 << bits is median.
1323 t
= (time_t) ((1 << bits
) - 1);
1324 #else // TODO: FIXME: review which is correct
1325 t
= (time_t) 1 << bits
;
1326 #endif /*_MSVCRT_LIB_*/
1330 (*funcp
)(&t
, offset
, &mytm
);
1331 dir
= tmcomp(&mytm
, &yourtm
);
1339 t
-= (time_t) 1 << bits
;
1340 else t
+= (time_t) 1 << bits
;
1343 if (yourtm
.tm_isdst
< 0 || mytm
.tm_isdst
== yourtm
.tm_isdst
)
1346 ** Right time, wrong type.
1347 ** Hunt for right time, right type.
1348 ** It's okay to guess wrong since the guess
1351 sp
= (const struct state
*)
1352 ((funcp
== localsub
) ? lclptr
: gmtptr
);
1356 #endif /* defined ALL_STATE */
1357 for (i
= 0; i
< sp
->typecnt
; ++i
)
1359 if (sp
->ttis
[i
].tt_isdst
!= yourtm
.tm_isdst
)
1361 for (j
= 0; j
< sp
->typecnt
; ++j
)
1363 if (sp
->ttis
[j
].tt_isdst
== yourtm
.tm_isdst
)
1365 newt
= t
+ sp
->ttis
[j
].tt_gmtoff
-
1366 sp
->ttis
[i
].tt_gmtoff
;
1367 (*funcp
)(&newt
, offset
, &mytm
);
1368 if (tmcomp(&mytm
, &yourtm
) != 0)
1370 if (mytm
.tm_isdst
!= yourtm
.tm_isdst
)
1383 (*funcp
)(&t
, offset
, tmp
);
1389 time1(struct tm
* CPP_CONST tmp
, void (*const funcp
)(const time_t * CPP_CONST
, const long, struct tm
*), const long offset
)
1392 const struct state
* sp
;
1396 if (tmp
->tm_isdst
> 1)
1398 t
= time2(tmp
, funcp
, offset
, &okay
);
1399 if (okay
|| tmp
->tm_isdst
< 0)
1402 ** We're supposed to assume that somebody took a time of one type
1403 ** and did some math on it that yielded a "struct tm" that's bad.
1404 ** We try to divine the type they started from and adjust to the
1407 sp
= (const struct state
*) ((funcp
== localsub
) ? lclptr
: gmtptr
);
1411 #endif /* defined ALL_STATE */
1412 for (samei
= 0; samei
< sp
->typecnt
; ++samei
)
1414 if (sp
->ttis
[samei
].tt_isdst
!= tmp
->tm_isdst
)
1416 for (otheri
= 0; otheri
< sp
->typecnt
; ++otheri
)
1418 if (sp
->ttis
[otheri
].tt_isdst
== tmp
->tm_isdst
)
1420 tmp
->tm_sec
+= sp
->ttis
[otheri
].tt_gmtoff
-
1421 sp
->ttis
[samei
].tt_gmtoff
;
1422 tmp
->tm_isdst
= !tmp
->tm_isdst
;
1423 t
= time2(tmp
, funcp
, offset
, &okay
);
1426 tmp
->tm_sec
-= sp
->ttis
[otheri
].tt_gmtoff
-
1427 sp
->ttis
[samei
].tt_gmtoff
;
1428 tmp
->tm_isdst
= !tmp
->tm_isdst
;
1438 mktime(struct tm
* tmp
)
1440 return time1(tmp
, localsub
, 0L);
1452 /*********************************************************************
1453 * _dstbias (MSVCRT.@)
1457 /*********************************************************************
1458 * __p_dstbias (MSVCRT.@)
1460 long * __p__dstbias(void)