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
50 #define alloc_size_t size_t
51 #define qsort_size_t size_t
52 #define fread_size_t size_t
53 #define fwrite_size_t size_t
55 #define ACCESS_MODE O_RDONLY|O_BINARY
56 #define OPEN_MODE O_RDONLY|O_BINARY
59 ** Someone might make incorrect use of a time zone abbreviation:
60 ** 1. They might reference tzname[0] before calling tzset (explicitly
62 ** 2. They might reference tzname[1] before calling tzset (explicitly
64 ** 3. They might reference tzname[1] after setting to a time zone
65 ** in which Daylight Saving Time is never observed.
66 ** 4. They might reference tzname[0] after setting to a time zone
67 ** in which Standard Time is never observed.
68 ** 5. They might reference tm.TM_ZONE after calling offtime.
69 ** What's best to do in the above cases is open to debate;
70 ** for now, we just set things up so that in any of the five cases
71 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
72 ** string "tzname[0] used before set", and similarly for the other cases.
73 ** And another: initialize tzname[0] to "ERA", with an explanation in the
74 ** manual page of what this "time zone abbreviation" means (doing this so
75 ** that tzname[0] has the "normal" length of three characters).
78 void _set_daylight_export(int);
79 void _set_timezone_export(int);
82 /* buffers must hold 64 characters! */
83 static char TZ_NAME
[64] = "PST";
84 static char TZ_DST_NAME
[64] = "PDT";
89 #endif /* !defined TRUE */
91 static const char GMT
[] = "GMT";
93 struct ttinfo
{ /* time type information */
94 long tt_gmtoff
; /* GMT offset in seconds */
95 int tt_isdst
; /* used to set tm_isdst */
96 int tt_abbrind
; /* abbreviation list index */
97 int tt_ttisstd
; /* TRUE if transition is std time */
100 struct lsinfo
{ /* leap second information */
101 time_t ls_trans
; /* transition time */
102 long ls_corr
; /* correction to apply */
110 time_t ats
[TZ_MAX_TIMES
];
111 unsigned char types
[TZ_MAX_TIMES
];
112 struct ttinfo ttis
[TZ_MAX_TYPES
];
113 char chars
[(TZ_MAX_CHARS
+ 1 > sizeof GMT
) ? TZ_MAX_CHARS
+ 1 : sizeof GMT
];
114 struct lsinfo lsis
[TZ_MAX_LEAPS
];
118 int r_type
; /* type of rule--see below */
119 int r_day
; /* day number of rule */
120 int r_week
; /* week number of rule */
121 int r_mon
; /* month number of rule */
122 long r_time
; /* transition time of rule */
125 #define JULIAN_DAY 0 /* Jn - Julian day */
126 #define DAY_OF_YEAR 1 /* n - day of year */
127 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
130 ** Prototypes for static functions.
133 static long detzcode
P((const char * codep
));
134 static const char * getzname
P((const char * strp
));
135 static const char * getnum
P((const char * strp
, int * nump
, int min
, int max
));
136 static const char * getsecs
P((const char * strp
, long * secsp
));
137 static const char * getoffset
P((const char * strp
, long * offsetp
));
138 static const char * getrule
P((const char * strp
, struct rule
* rulep
));
139 static void gmtload
P((struct state
* sp
));
140 static void gmtsub
P((const time_t * timep
, long offset
, struct tm
* tmp
));
141 static void localsub
P((const time_t * timep
, long offset
, struct tm
* tmp
));
142 static void normalize
P((int * tensptr
, int * unitsptr
, int base
));
143 static void settzname
P((void));
144 static time_t time1
P((struct tm
* tmp
, void (* funcp
)(const time_t * CPP_CONST
, const long, struct tm
* CPP_CONST
), long offset
));
145 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
));
146 static void timesub
P((const time_t * timep
, long offset
, const struct state
* sp
, struct tm
* tmp
));
147 static int tmcomp
P((const struct tm
* atmp
, const struct tm
* btmp
));
148 static time_t transtime
P((time_t janfirst
, int year
, const struct rule
* rulep
, long offset
));
149 static int tzload
P((const char * name
, struct state
* sp
));
150 static int tzparse
P((const char * name
, struct state
* sp
, int lastditch
));
151 static void tzsetwall(void);
155 static const char * getnum(const char * strp
, int * CPP_CONST nump
, const int min
, const int max
);
156 static void timesub(const time_t * CPP_CONST timep
, const long offset
, const struct state
* CPP_CONST sp
, struct tm
* CPP_CONST tmp
);
157 static time_t transtime(const time_t janfirst
, const int year
, const struct rule
* CPP_CONST rulep
, const long offset
);
158 static void tzsetwall(void);
163 static struct state
*lclptr
;
164 static struct state
*gmtptr
;
165 #endif /* defined ALL_STATE */
168 static struct state lclmem
;
169 static struct state gmtmem
;
170 #define lclptr (&lclmem)
171 #define gmtptr (&gmtmem)
172 #endif /* State Farm */
174 static int lcl_is_set
;
175 static int gmt_is_set
;
177 char * _tzname
[2] = {
183 detzcode(const char * CPP_CONST codep
)
189 for (i
= 0; i
< 4; ++i
)
190 result
= (result
<< 8) | (codep
[i
] & 0xff);
197 const struct state
* CPP_CONST sp
= lclptr
;
200 _tzname
[0] = TZ_NAME
;
201 _tzname
[1] = TZ_DST_NAME
;
205 _tzname
[0] = _tzname
[1] = GMT
;
208 #endif /* defined ALL_STATE */
209 for (i
= 0; i
< sp
->typecnt
; ++i
)
211 register const struct ttinfo
* CPP_CONST ttisp
= &sp
->ttis
[i
];
213 _tzname
[ttisp
->tt_isdst
] =
214 (char *)&sp
->chars
[ttisp
->tt_abbrind
];
216 if (ttisp
->tt_isdst
) {
218 _set_daylight_export(1);
220 if (i
== 0 || !ttisp
->tt_isdst
) {
221 //_timezone_dll = -(ttisp->tt_gmtoff);
222 _set_timezone_export(-(ttisp
->tt_gmtoff
));
224 if (i
== 0 || ttisp
->tt_isdst
) {
225 _altzone
= -(ttisp
->tt_gmtoff
);
230 ** And to get the latest zone names into tzname. . .
232 for (i
= 0; i
< sp
->timecnt
; ++i
)
234 const struct ttinfo
* CPP_CONST ttisp
= &sp
->ttis
[sp
->types
[i
]];
236 _tzname
[ttisp
->tt_isdst
] = (char *)&sp
->chars
[ttisp
->tt_abbrind
];
240 static char* tzdir(void)
242 static char dir
[80]={0}, *cp
;
245 if ((cp
= getenv("TZDIR")))
249 else if ((cp
= getenv("DJDIR")))
252 strcat(dir
, "/zoneinfo");
260 static int tzload(const char* name
, struct state
* CPP_CONST sp
)
265 char fullname
[FILENAME_MAX
+ 1];
266 const struct tzhead
* tzhp
;
267 char buf
[sizeof *sp
+ sizeof *tzhp
];
270 if (name
== NULL
&& (name
= TZDEFAULT
) == NULL
)
277 if ((p
= tzdir()) == NULL
)
279 if ((strlen(p
) + strlen(name
) + 1) >= sizeof fullname
)
282 strcat(fullname
, "/");
283 strcat(fullname
, name
);
287 if ((fid
= _open(name
, OPEN_MODE
)) == -1)
289 const char *base
= strrchr(name
, '/');
294 if (strcmp(base
, "posixrules"))
297 /* We've got a built-in copy of posixrules just in case */
298 memcpy(buf
, _posixrules_data
, sizeof(_posixrules_data
));
299 i
= sizeof(_posixrules_data
);
303 i
= _read(fid
, buf
, sizeof buf
);
304 if (_close(fid
) != 0 || i
< (int)sizeof *tzhp
)
308 tzhp
= (struct tzhead
*) buf
;
309 ttisstdcnt
= (int) detzcode(tzhp
->tzh_ttisstdcnt
);
310 sp
->leapcnt
= (int) detzcode(tzhp
->tzh_leapcnt
);
311 sp
->timecnt
= (int) detzcode(tzhp
->tzh_timecnt
);
312 sp
->typecnt
= (int) detzcode(tzhp
->tzh_typecnt
);
313 sp
->charcnt
= (int) detzcode(tzhp
->tzh_charcnt
);
314 if (sp
->leapcnt
< 0 || sp
->leapcnt
> TZ_MAX_LEAPS
||
315 sp
->typecnt
<= 0 || sp
->typecnt
> TZ_MAX_TYPES
||
316 sp
->timecnt
< 0 || sp
->timecnt
> TZ_MAX_TIMES
||
317 sp
->charcnt
< 0 || sp
->charcnt
> TZ_MAX_CHARS
||
318 (ttisstdcnt
!= sp
->typecnt
&& ttisstdcnt
!= 0))
320 if (i
< (int)sizeof *tzhp
+
321 sp
->timecnt
* (4 + (int)sizeof (char)) +
322 sp
->typecnt
* (4 + 2 * (int)sizeof (char)) +
323 sp
->charcnt
* (int)sizeof (char) +
324 sp
->leapcnt
* 2 * 4 +
325 ttisstdcnt
* (int)sizeof (char))
327 p
= buf
+ sizeof *tzhp
;
328 for (i
= 0; i
< sp
->timecnt
; ++i
)
330 sp
->ats
[i
] = detzcode(p
);
333 for (i
= 0; i
< sp
->timecnt
; ++i
)
335 sp
->types
[i
] = (unsigned char) *p
++;
336 if (sp
->types
[i
] >= sp
->typecnt
)
339 for (i
= 0; i
< sp
->typecnt
; ++i
)
341 struct ttinfo
* ttisp
;
343 ttisp
= &sp
->ttis
[i
];
344 ttisp
->tt_gmtoff
= detzcode(p
);
346 ttisp
->tt_isdst
= (unsigned char) *p
++;
347 if (ttisp
->tt_isdst
!= 0 && ttisp
->tt_isdst
!= 1)
349 ttisp
->tt_abbrind
= (unsigned char) *p
++;
350 if (ttisp
->tt_abbrind
< 0 ||
351 ttisp
->tt_abbrind
> sp
->charcnt
)
354 for (i
= 0; i
< sp
->charcnt
; ++i
)
356 sp
->chars
[i
] = '\0'; /* ensure '\0' at end */
357 for (i
= 0; i
< sp
->leapcnt
; ++i
)
359 struct lsinfo
* lsisp
;
361 lsisp
= &sp
->lsis
[i
];
362 lsisp
->ls_trans
= detzcode(p
);
364 lsisp
->ls_corr
= detzcode(p
);
367 for (i
= 0; i
< sp
->typecnt
; ++i
)
369 struct ttinfo
* ttisp
;
371 ttisp
= &sp
->ttis
[i
];
373 ttisp
->tt_ttisstd
= FALSE
;
376 ttisp
->tt_ttisstd
= *p
++;
377 if (ttisp
->tt_ttisstd
!= TRUE
&&
378 ttisp
->tt_ttisstd
!= FALSE
)
385 static const int mon_lengths
[2][MONSPERYEAR
] = {
386 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
387 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
390 static const int year_lengths
[2] = {
391 DAYSPERNYEAR
, DAYSPERLYEAR
395 ** Given a pointer into a time zone string, scan until a character that is not
396 ** a valid character in a zone name is found. Return a pointer to that
401 getzname(const char* strp
)
405 while ((c
= *strp
) != '\0' && !isdigit(c
) && c
!= ',' && c
!= '-' &&
412 ** Given a pointer into a time zone string, extract a number from that string.
413 ** Check that the number is within a specified range; if it is not, return
415 ** Otherwise, return a pointer to the first character not part of the number.
419 getnum(const char* strp
, int* CPP_CONST nump
, const int min
, const int max
)
424 if (strp
== NULL
|| !isdigit(*strp
))
427 while ((c
= *strp
) != '\0' && isdigit(c
))
429 num
= num
* 10 + (c
- '0');
441 ** Given a pointer into a time zone string, extract a number of seconds,
442 ** in hh[:mm[:ss]] form, from the string.
443 ** If any error occurs, return NULL.
444 ** Otherwise, return a pointer to the first character not part of the number
449 getsecs(const char *strp
, long * CPP_CONST secsp
)
453 strp
= getnum(strp
, &num
, 0, HOURSPERDAY
);
456 *secsp
= num
* SECSPERHOUR
;
460 strp
= getnum(strp
, &num
, 0, MINSPERHOUR
- 1);
463 *secsp
+= num
* SECSPERMIN
;
467 strp
= getnum(strp
, &num
, 0, SECSPERMIN
- 1);
477 ** Given a pointer into a time zone string, extract an offset, in
478 ** [+-]hh[:mm[:ss]] form, from the string.
479 ** If any error occurs, return NULL.
480 ** Otherwise, return a pointer to the first character not part of the time.
484 getoffset(const char *strp
, long * CPP_CONST offsetp
)
493 else if (isdigit(*strp
) || *strp
++ == '+')
496 return NULL
; /* illegal offset */
497 strp
= getsecs(strp
, offsetp
);
499 return NULL
; /* illegal time */
501 *offsetp
= -*offsetp
;
506 ** Given a pointer into a time zone string, extract a rule in the form
507 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
508 ** If a valid rule is not found, return NULL.
509 ** Otherwise, return a pointer to the first character not part of the rule.
513 getrule(const char *strp
, struct rule
* CPP_CONST rulep
)
520 rulep
->r_type
= JULIAN_DAY
;
522 strp
= getnum(strp
, &rulep
->r_day
, 1, DAYSPERNYEAR
);
524 else if (*strp
== 'M')
529 rulep
->r_type
= MONTH_NTH_DAY_OF_WEEK
;
531 strp
= getnum(strp
, &rulep
->r_mon
, 1, MONSPERYEAR
);
536 strp
= getnum(strp
, &rulep
->r_week
, 1, 5);
541 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERWEEK
- 1);
543 else if (isdigit(*strp
))
548 rulep
->r_type
= DAY_OF_YEAR
;
549 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERLYEAR
- 1);
552 return NULL
; /* invalid format */
561 strp
= getsecs(strp
, &rulep
->r_time
);
564 rulep
->r_time
= 2 * SECSPERHOUR
; /* default = 2:00:00 */
569 ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
570 ** year, a rule, and the offset from GMT at the time that rule takes effect,
571 ** calculate the Epoch-relative time that rule takes effect.
575 transtime(const time_t janfirst
, const int year
, const struct rule
* CPP_CONST rulep
, const long offset
)
580 int d
, m1
, yy0
, yy1
, yy2
, dow
;
582 leapyear
= isleap(year
);
583 switch (rulep
->r_type
)
588 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
590 ** In non-leap years, or if the day number is 59 or less, just
591 ** add SECSPERDAY times the day number-1 to the time of
592 ** January 1, midnight, to get the day.
594 value
= janfirst
+ (rulep
->r_day
- 1) * SECSPERDAY
;
595 if (leapyear
&& rulep
->r_day
>= 60)
602 ** Just add SECSPERDAY times the day number to the time of
603 ** January 1, midnight, to get the day.
605 value
= janfirst
+ rulep
->r_day
* SECSPERDAY
;
608 case MONTH_NTH_DAY_OF_WEEK
:
610 ** Mm.n.d - nth "dth day" of month m.
613 for (i
= 0; i
< rulep
->r_mon
- 1; ++i
)
614 value
+= mon_lengths
[leapyear
][i
] * SECSPERDAY
;
617 ** Use Zeller's Congruence to get day-of-week of first day of
620 m1
= (rulep
->r_mon
+ 9) % 12 + 1;
621 yy0
= (rulep
->r_mon
<= 2) ? (year
- 1) : year
;
624 dow
= ((26 * m1
- 2) / 10 +
625 1 + yy2
+ yy2
/ 4 + yy1
/ 4 - 2 * yy1
) % 7;
630 ** "dow" is the day-of-week of the first day of the month. Get
631 ** the day-of-month (zero-origin) of the first "dow" day of the
634 d
= rulep
->r_day
- dow
;
637 for (i
= 1; i
< rulep
->r_week
; ++i
)
639 if (d
+ DAYSPERWEEK
>=
640 mon_lengths
[leapyear
][rulep
->r_mon
- 1])
646 ** "d" is the day-of-month (zero-origin) of the day we want.
648 value
+= d
* SECSPERDAY
;
653 ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
654 ** question. To get the Epoch-relative time of the specified local
655 ** time on that day, add the transition time and the current offset
658 return value
+ rulep
->r_time
+ offset
;
662 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
667 tzparse(const char *name
, struct state
* CPP_CONST sp
, const int lastditch
)
669 const char * stdname
;
670 const char * dstname
=0;
676 unsigned char * typep
;
683 stdlen
= strlen(name
); /* length of standard zone name */
685 if (stdlen
>= (int)sizeof sp
->chars
)
686 stdlen
= (int)(sizeof sp
->chars
) - 1;
690 name
= getzname(name
);
691 stdlen
= name
- stdname
;
699 name
= getoffset(name
, &stdoffset
);
703 load_result
= tzload(TZDEFRULES
, sp
);
704 if (load_result
!= 0)
705 sp
->leapcnt
= 0; /* so, we're off a little */
709 name
= getzname(name
);
710 dstlen
= name
- dstname
; /* length of DST zone name */
713 if (*name
!= '\0' && *name
!= ',' && *name
!= ';')
715 name
= getoffset(name
, &dstoffset
);
720 dstoffset
= stdoffset
- SECSPERHOUR
;
721 if (*name
== ',' || *name
== ';')
731 if ((name
= getrule(name
, &start
)) == NULL
)
735 if ((name
= getrule(name
, &end
)) == NULL
)
739 sp
->typecnt
= 2; /* standard time and DST */
741 ** Two transitions per year, from EPOCH_YEAR to 2037.
743 sp
->timecnt
= 2 * (2037 - EPOCH_YEAR
+ 1);
744 if (sp
->timecnt
> TZ_MAX_TIMES
)
746 sp
->ttis
[0].tt_gmtoff
= -dstoffset
;
747 sp
->ttis
[0].tt_isdst
= 1;
748 sp
->ttis
[0].tt_abbrind
= stdlen
+ 1;
749 sp
->ttis
[1].tt_gmtoff
= -stdoffset
;
750 sp
->ttis
[1].tt_isdst
= 0;
751 sp
->ttis
[1].tt_abbrind
= 0;
755 for (year
= EPOCH_YEAR
; year
<= 2037; ++year
)
757 starttime
= transtime(janfirst
, year
, &start
,
759 endtime
= transtime(janfirst
, year
, &end
,
761 if (starttime
> endtime
)
764 *typep
++ = 1; /* DST ends */
766 *typep
++ = 0; /* DST begins */
771 *typep
++ = 0; /* DST begins */
773 *typep
++ = 1; /* DST ends */
776 year_lengths
[isleap(year
)] * SECSPERDAY
;
791 if (load_result
!= 0)
794 ** Compute the difference between the real and
795 ** prototype standard and summer time offsets
796 ** from GMT, and put the real standard and summer
797 ** time offsets into the rules in place of the
798 ** prototype offsets.
804 for (i
= 0; i
< sp
->typecnt
; ++i
)
806 if (sp
->ttis
[i
].tt_isdst
)
810 sp
->ttis
[i
].tt_gmtoff
+ dstoffset
;
811 if (sawdst
&& (oldfix
!= dstfix
))
813 sp
->ttis
[i
].tt_gmtoff
= -dstoffset
;
814 sp
->ttis
[i
].tt_abbrind
= stdlen
+ 1;
821 sp
->ttis
[i
].tt_gmtoff
+ stdoffset
;
822 if (sawstd
&& (oldfix
!= stdfix
))
824 sp
->ttis
[i
].tt_gmtoff
= -stdoffset
;
825 sp
->ttis
[i
].tt_abbrind
= 0;
830 ** Make sure we have both standard and summer time.
832 if (!sawdst
|| !sawstd
)
835 ** Now correct the transition times by shifting
836 ** them by the difference between the real and
837 ** prototype offsets. Note that this difference
838 ** can be different in standard and summer time;
839 ** the prototype probably has a 1-hour difference
840 ** between standard and summer time, but a different
841 ** difference can be specified in TZ.
843 isdst
= FALSE
; /* we start in standard time */
844 for (i
= 0; i
< sp
->timecnt
; ++i
)
846 const struct ttinfo
* ttisp
;
849 ** If summer time is in effect, and the
850 ** transition time was not specified as
851 ** standard time, add the summer time
852 ** offset to the transition time;
853 ** otherwise, add the standard time offset
854 ** to the transition time.
856 ttisp
= &sp
->ttis
[sp
->types
[i
]];
858 (isdst
&& !ttisp
->tt_ttisstd
) ?
860 isdst
= ttisp
->tt_isdst
;
867 sp
->typecnt
= 1; /* only standard time */
869 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
870 sp
->ttis
[0].tt_isdst
= 0;
871 sp
->ttis
[0].tt_abbrind
= 0;
873 sp
->charcnt
= stdlen
+ 1;
875 sp
->charcnt
+= dstlen
+ 1;
876 if (sp
->charcnt
> (int)sizeof sp
->chars
)
879 (void) strncpy(cp
, stdname
, stdlen
);
884 (void) strncpy(cp
, dstname
, dstlen
);
885 *(cp
+ dstlen
) = '\0';
891 gmtload(struct state
* CPP_CONST sp
)
893 if (tzload(GMT
, sp
) != 0)
894 (void) tzparse(GMT
, sp
, TRUE
);
915 lclptr
= (struct state
*) malloc(sizeof *lclptr
);
918 settzname(); /* all we can do */
922 #endif /* defined ALL_STATE */
926 ** User wants it fast rather than right.
928 lclptr
->leapcnt
= 0; /* so, we're off a little */
930 lclptr
->ttis
[0].tt_gmtoff
= 0;
931 lclptr
->ttis
[0].tt_abbrind
= 0;
932 (void) strcpy(lclptr
->chars
, GMT
);
934 else if (tzload(name
, lclptr
) != 0)
935 if (name
[0] == ':' || tzparse(name
, lclptr
, FALSE
) != 0)
947 lclptr
= (struct state
*) malloc(sizeof *lclptr
);
950 settzname(); /* all we can do */
954 #endif /* defined ALL_STATE */
955 if (tzload((char *) NULL
, lclptr
) != 0)
961 ** The easy way to behave "as if no library function calls" localtime
962 ** is to not call it--so we drop its guts into "localsub", which can be
963 ** freely called. (And no, the PANS doesn't require the above behavior--
964 ** but it *is* desirable.)
966 ** The unused offset argument is for the benefit of mktime variants.
971 localsub(const time_t * CPP_CONST timep
, const long offset
, struct tm
* CPP_CONST tmp
)
973 const struct state
* sp
;
974 const struct ttinfo
* ttisp
;
976 const time_t t
= *timep
;
984 gmtsub(timep
, offset
, tmp
);
987 #endif /* defined ALL_STATE */
988 if (sp
->timecnt
== 0 || t
< sp
->ats
[0])
991 while (sp
->ttis
[i
].tt_isdst
)
992 if (++i
>= sp
->typecnt
)
1000 for (i
= 1; i
< sp
->timecnt
; ++i
)
1003 i
= sp
->types
[i
- 1];
1005 ttisp
= &sp
->ttis
[i
];
1007 ** To get (wrong) behavior that's compatible with System V Release 2.0
1008 ** you'd replace the statement below with
1009 ** t += ttisp->tt_gmtoff;
1010 ** timesub(&t, 0L, sp, tmp);
1012 timesub(&t
, ttisp
->tt_gmtoff
, sp
, tmp
);
1013 tmp
->tm_isdst
= ttisp
->tt_isdst
;
1014 _tzname
[tmp
->tm_isdst
] = (char *)&sp
->chars
[ttisp
->tt_abbrind
];
1016 /* tm_zone doesnt exist in windows msvcrt -Gunnar */
1017 tmp
->tm_zone
= (char *)&sp
->chars
[ttisp
->tt_abbrind
];
1025 localtime(const time_t * CPP_CONST timep
)
1027 static struct tm tm
;
1029 localsub(timep
, 0L, &tm
);
1034 ** gmtsub is to gmtime as localsub is to localtime.
1038 gmtsub(const time_t * CPP_CONST timep
, const long offset
, struct tm
* CPP_CONST tmp
)
1044 gmtptr
= (struct state
*) malloc(sizeof *gmtptr
);
1046 #endif /* defined ALL_STATE */
1049 timesub(timep
, offset
, gmtptr
, tmp
);
1051 ** Could get fancy here and deliver something such as
1052 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
1053 ** but this is no time for a treasure hunt.
1056 /* tm_zone doesnt exist in windows msvcrt -Gunnar */
1058 tmp
->tm_zone
= TZ_NAME
;
1065 tmp
->TM_ZONE
= gmtptr
->chars
;
1066 #endif /* defined ALL_STATE */
1068 tmp
->tm_zone
= gmtptr
->chars
;
1069 #endif /* State Farm */
1078 gmtime(const time_t * CPP_CONST timep
)
1080 static struct tm tm
;
1082 gmtsub(timep
, 0L, &tm
);
1087 timesub(const time_t * CPP_CONST timep
, const long offset
, const struct state
* CPP_CONST sp
, struct tm
* CPP_CONST tmp
)
1089 const struct lsinfo
* lp
;
1102 i
= (sp
== NULL
) ? 0 : sp
->leapcnt
;
1103 #endif /* defined ALL_STATE */
1106 #endif /* State Farm */
1110 if (*timep
>= lp
->ls_trans
)
1112 if (*timep
== lp
->ls_trans
)
1113 hit
= ((i
== 0 && lp
->ls_corr
> 0) ||
1114 lp
->ls_corr
> sp
->lsis
[i
- 1].ls_corr
);
1119 days
= *timep
/ SECSPERDAY
;
1120 rem
= *timep
% SECSPERDAY
;
1122 if (*timep
== 0x80000000)
1125 ** A 3B1 muffs the division on the most negative number.
1131 rem
+= (offset
- corr
);
1137 while (rem
>= SECSPERDAY
)
1142 tmp
->tm_hour
= (int) (rem
/ SECSPERHOUR
);
1143 rem
= rem
% SECSPERHOUR
;
1144 tmp
->tm_min
= (int) (rem
/ SECSPERMIN
);
1145 tmp
->tm_sec
= (int) (rem
% SECSPERMIN
);
1148 ** A positive leap second requires a special
1149 ** representation. This uses "... ??:59:60".
1152 tmp
->tm_wday
= (int) ((EPOCH_WDAY
+ days
) % DAYSPERWEEK
);
1153 if (tmp
->tm_wday
< 0)
1154 tmp
->tm_wday
+= DAYSPERWEEK
;
1160 if (days
< (long) year_lengths
[yleap
])
1163 days
= days
- (long) year_lengths
[yleap
];
1169 days
= days
+ (long) year_lengths
[yleap
];
1171 tmp
->tm_year
= y
- TM_YEAR_BASE
;
1172 tmp
->tm_yday
= (int) days
;
1173 ip
= mon_lengths
[yleap
];
1174 for (tmp
->tm_mon
= 0; days
>= (long) ip
[tmp
->tm_mon
]; ++(tmp
->tm_mon
))
1175 days
= days
- (long) ip
[tmp
->tm_mon
];
1176 tmp
->tm_mday
= (int) (days
+ 1);
1179 /* tm_gmtoff doesnt exist in windows msvcrt -Gunnar */
1180 tmp
->tm_gmtoff
= offset
;
1192 asctime(const struct tm
*timeptr
)
1194 static const char wday_name
[DAYSPERWEEK
][3] = {
1195 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1197 static const char mon_name
[MONSPERYEAR
][3] = {
1198 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1199 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1201 static char result
[26];
1203 (void) sprintf(result
, "%.3s %.3s%3d %02d:%02d:%02d %d\n",
1204 wday_name
[timeptr
->tm_wday
],
1205 mon_name
[timeptr
->tm_mon
],
1206 timeptr
->tm_mday
, timeptr
->tm_hour
,
1207 timeptr
->tm_min
, timeptr
->tm_sec
,
1208 TM_YEAR_BASE
+ timeptr
->tm_year
);
1216 ctime(const time_t * CPP_CONST timep
)
1218 return asctime(localtime(timep
));
1222 ** Adapted from code provided by Robert Elz, who writes:
1223 ** The "best" way to do mktime I think is based on an idea of Bob
1224 ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
1225 ** It does a binary search of the time_t space. Since time_t's are
1226 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
1227 ** would still be very reasonable).
1232 #endif /* !defined WRONG */
1235 normalize(int * CPP_CONST tensptr
, int * CPP_CONST unitsptr
, const int base
)
1237 if (*unitsptr
>= base
)
1239 *tensptr
+= *unitsptr
/ base
;
1242 else if (*unitsptr
< 0)
1248 *tensptr
-= 1 + (-*unitsptr
) / base
;
1249 *unitsptr
= base
- (-*unitsptr
) % base
;
1255 tmcomp(const struct tm
* CPP_CONST atmp
, const struct tm
* CPP_CONST btmp
)
1259 if ((result
= (atmp
->tm_year
- btmp
->tm_year
)) == 0 &&
1260 (result
= (atmp
->tm_mon
- btmp
->tm_mon
)) == 0 &&
1261 (result
= (atmp
->tm_mday
- btmp
->tm_mday
)) == 0 &&
1262 (result
= (atmp
->tm_hour
- btmp
->tm_hour
)) == 0 &&
1263 (result
= (atmp
->tm_min
- btmp
->tm_min
)) == 0)
1264 result
= atmp
->tm_sec
- btmp
->tm_sec
;
1269 time2(struct tm
*tmp
, void (*const funcp
)(const time_t * CPP_CONST
, const long, struct tm
*), const long offset
, int * CPP_CONST okayp
)
1271 const struct state
* sp
;
1278 struct tm yourtm
, mytm
;
1282 if (yourtm
.tm_sec
>= SECSPERMIN
+ 2 || yourtm
.tm_sec
< 0)
1283 normalize(&yourtm
.tm_min
, &yourtm
.tm_sec
, SECSPERMIN
);
1284 normalize(&yourtm
.tm_hour
, &yourtm
.tm_min
, MINSPERHOUR
);
1285 normalize(&yourtm
.tm_mday
, &yourtm
.tm_hour
, HOURSPERDAY
);
1286 normalize(&yourtm
.tm_year
, &yourtm
.tm_mon
, MONSPERYEAR
);
1287 while (yourtm
.tm_mday
<= 0)
1291 year_lengths
[isleap(yourtm
.tm_year
+ TM_YEAR_BASE
)];
1295 i
= mon_lengths
[isleap(yourtm
.tm_year
+
1296 TM_YEAR_BASE
)][yourtm
.tm_mon
];
1297 if (yourtm
.tm_mday
<= i
)
1299 yourtm
.tm_mday
-= i
;
1300 if (++yourtm
.tm_mon
>= MONSPERYEAR
)
1306 saved_seconds
= yourtm
.tm_sec
;
1309 ** Calculate the number of magnitude bits in a time_t
1310 ** (this works regardless of whether time_t is
1311 ** signed or unsigned, though lint complains if unsigned).
1313 for (bits
= 0, t
= 1; t
> 0; ++bits
, t
<<= 1)
1316 ** If time_t is signed, then 0 is the median value,
1317 ** if time_t is unsigned, then 1 << bits is median.
1320 t
= (time_t) ((1 << bits
) - 1);
1321 #else // TODO: FIXME: review which is correct
1322 t
= (time_t) 1 << bits
;
1323 #endif /*_MSVCRT_LIB_*/
1327 (*funcp
)(&t
, offset
, &mytm
);
1328 dir
= tmcomp(&mytm
, &yourtm
);
1336 t
-= (time_t) 1 << bits
;
1337 else t
+= (time_t) 1 << bits
;
1340 if (yourtm
.tm_isdst
< 0 || mytm
.tm_isdst
== yourtm
.tm_isdst
)
1343 ** Right time, wrong type.
1344 ** Hunt for right time, right type.
1345 ** It's okay to guess wrong since the guess
1348 sp
= (const struct state
*)
1349 ((funcp
== localsub
) ? lclptr
: gmtptr
);
1353 #endif /* defined ALL_STATE */
1354 for (i
= 0; i
< sp
->typecnt
; ++i
)
1356 if (sp
->ttis
[i
].tt_isdst
!= yourtm
.tm_isdst
)
1358 for (j
= 0; j
< sp
->typecnt
; ++j
)
1360 if (sp
->ttis
[j
].tt_isdst
== yourtm
.tm_isdst
)
1362 newt
= t
+ sp
->ttis
[j
].tt_gmtoff
-
1363 sp
->ttis
[i
].tt_gmtoff
;
1364 (*funcp
)(&newt
, offset
, &mytm
);
1365 if (tmcomp(&mytm
, &yourtm
) != 0)
1367 if (mytm
.tm_isdst
!= yourtm
.tm_isdst
)
1380 (*funcp
)(&t
, offset
, tmp
);
1386 time1(struct tm
* CPP_CONST tmp
, void (*const funcp
)(const time_t * CPP_CONST
, const long, struct tm
*), const long offset
)
1389 const struct state
* sp
;
1393 if (tmp
->tm_isdst
> 1)
1395 t
= time2(tmp
, funcp
, offset
, &okay
);
1396 if (okay
|| tmp
->tm_isdst
< 0)
1399 ** We're supposed to assume that somebody took a time of one type
1400 ** and did some math on it that yielded a "struct tm" that's bad.
1401 ** We try to divine the type they started from and adjust to the
1404 sp
= (const struct state
*) ((funcp
== localsub
) ? lclptr
: gmtptr
);
1408 #endif /* defined ALL_STATE */
1409 for (samei
= 0; samei
< sp
->typecnt
; ++samei
)
1411 if (sp
->ttis
[samei
].tt_isdst
!= tmp
->tm_isdst
)
1413 for (otheri
= 0; otheri
< sp
->typecnt
; ++otheri
)
1415 if (sp
->ttis
[otheri
].tt_isdst
== tmp
->tm_isdst
)
1417 tmp
->tm_sec
+= sp
->ttis
[otheri
].tt_gmtoff
-
1418 sp
->ttis
[samei
].tt_gmtoff
;
1419 tmp
->tm_isdst
= !tmp
->tm_isdst
;
1420 t
= time2(tmp
, funcp
, offset
, &okay
);
1423 tmp
->tm_sec
-= sp
->ttis
[otheri
].tt_gmtoff
-
1424 sp
->ttis
[samei
].tt_gmtoff
;
1425 tmp
->tm_isdst
= !tmp
->tm_isdst
;
1435 mktime(struct tm
* tmp
)
1437 return time1(tmp
, localsub
, 0L);