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
39 #include <msvcrt/fcntl.h>
40 #include <msvcrt/time.h>
41 #include <msvcrt/string.h>
42 #include <msvcrt/ctype.h>
43 #include <msvcrt/stdio.h>
44 #include <msvcrt/stdlib.h>
48 #include <msvcrt/io.h>
54 #define CPP_CONST const
60 #define alloc_size_t size_t
61 #define qsort_size_t size_t
62 #define fread_size_t size_t
63 #define fwrite_size_t size_t
65 #define ACCESS_MODE O_RDONLY|O_BINARY
66 #define OPEN_MODE O_RDONLY|O_BINARY
69 ** Someone might make incorrect use of a time zone abbreviation:
70 ** 1. They might reference tzname[0] before calling tzset (explicitly
72 ** 2. They might reference tzname[1] before calling tzset (explicitly
74 ** 3. They might reference tzname[1] after setting to a time zone
75 ** in which Daylight Saving Time is never observed.
76 ** 4. They might reference tzname[0] after setting to a time zone
77 ** in which Standard Time is never observed.
78 ** 5. They might reference tm.TM_ZONE after calling offtime.
79 ** What's best to do in the above cases is open to debate;
80 ** for now, we just set things up so that in any of the five cases
81 ** 4ABBR is used. Another possibility: initialize tzname[0] to the
82 ** string "tzname[0] used before set", and similarly for the other cases.
83 ** And another: initialize tzname[0] to "ERA", with an explanation in the
84 ** manual page of what this "time zone abbreviation" means (doing this so
85 ** that tzname[0] has the "normal" length of three characters).
88 void _set_daylight_export(int);
89 void _set_timezone_export(int);
91 static char TZ_NAME
[16] = "JST";
92 static char TZ_DST_NAME
[12] = "";
97 #endif /* !defined TRUE */
99 static const char GMT
[] = "GMT";
101 struct ttinfo
{ /* time type information */
102 long tt_gmtoff
; /* GMT offset in seconds */
103 int tt_isdst
; /* used to set tm_isdst */
104 int tt_abbrind
; /* abbreviation list index */
105 int tt_ttisstd
; /* TRUE if transition is std time */
108 struct lsinfo
{ /* leap second information */
109 time_t ls_trans
; /* transition time */
110 long ls_corr
; /* correction to apply */
118 time_t ats
[TZ_MAX_TIMES
];
119 unsigned char types
[TZ_MAX_TIMES
];
120 struct ttinfo ttis
[TZ_MAX_TYPES
];
121 char chars
[(TZ_MAX_CHARS
+ 1 > sizeof GMT
) ? TZ_MAX_CHARS
+ 1 : sizeof GMT
];
122 struct lsinfo lsis
[TZ_MAX_LEAPS
];
126 int r_type
; /* type of rule--see below */
127 int r_day
; /* day number of rule */
128 int r_week
; /* week number of rule */
129 int r_mon
; /* month number of rule */
130 long r_time
; /* transition time of rule */
133 #define JULIAN_DAY 0 /* Jn - Julian day */
134 #define DAY_OF_YEAR 1 /* n - day of year */
135 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
138 ** Prototypes for static functions.
141 static long detzcode
P((const char * codep
));
142 static const char * getzname
P((const char * strp
));
143 static const char * getnum
P((const char * strp
, int * nump
, int min
, int max
));
144 static const char * getsecs
P((const char * strp
, long * secsp
));
145 static const char * getoffset
P((const char * strp
, long * offsetp
));
146 static const char * getrule
P((const char * strp
, struct rule
* rulep
));
147 static void gmtload
P((struct state
* sp
));
148 static void gmtsub
P((const time_t * timep
, long offset
, struct tm
* tmp
));
149 static void localsub
P((const time_t * timep
, long offset
, struct tm
* tmp
));
150 static void normalize
P((int * tensptr
, int * unitsptr
, int base
));
151 static void settzname
P((void));
152 static time_t time1
P((struct tm
* tmp
, void (* funcp
)(const time_t * CPP_CONST
, const long, struct tm
* CPP_CONST
), long offset
));
153 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
));
154 static void timesub
P((const time_t * timep
, long offset
, const struct state
* sp
, struct tm
* tmp
));
155 static int tmcomp
P((const struct tm
* atmp
, const struct tm
* btmp
));
156 static time_t transtime
P((time_t janfirst
, int year
, const struct rule
* rulep
, long offset
));
157 static int tzload
P((const char * name
, struct state
* sp
));
158 static int tzparse
P((const char * name
, struct state
* sp
, int lastditch
));
159 static void tzsetwall(void);
163 static const char * getnum(const char * strp
, int * CPP_CONST nump
, const int min
, const int max
);
164 static void timesub(const time_t * CPP_CONST timep
, const long offset
, const struct state
* CPP_CONST sp
, struct tm
* CPP_CONST tmp
);
165 static time_t transtime(const time_t janfirst
, const int year
, const struct rule
* CPP_CONST rulep
, const long offset
);
166 static void tzsetwall(void);
171 static struct state
*lclptr
;
172 static struct state
*gmtptr
;
173 #endif /* defined ALL_STATE */
176 static struct state lclmem
;
177 static struct state gmtmem
;
178 #define lclptr (&lclmem)
179 #define gmtptr (&gmtmem)
180 #endif /* State Farm */
182 static int lcl_is_set
;
183 static int gmt_is_set
;
185 char * _tzname
[2] = {
191 detzcode(const char * CPP_CONST codep
)
197 for (i
= 0; i
< 4; ++i
)
198 result
= (result
<< 8) | (codep
[i
] & 0xff);
205 const struct state
* CPP_CONST sp
= lclptr
;
208 _tzname
[0] = TZ_NAME
;
209 _tzname
[1] = TZ_DST_NAME
;
213 _tzname
[0] = _tzname
[1] = GMT
;
216 #endif /* defined ALL_STATE */
217 for (i
= 0; i
< sp
->typecnt
; ++i
)
219 register const struct ttinfo
* CPP_CONST ttisp
= &sp
->ttis
[i
];
221 _tzname
[ttisp
->tt_isdst
] =
222 (char *)&sp
->chars
[ttisp
->tt_abbrind
];
224 if (ttisp
->tt_isdst
) {
226 _set_daylight_export(1);
228 if (i
== 0 || !ttisp
->tt_isdst
) {
229 //_timezone_dll = -(ttisp->tt_gmtoff);
230 _set_timezone_export(-(ttisp
->tt_gmtoff
));
232 if (i
== 0 || ttisp
->tt_isdst
) {
233 _altzone
= -(ttisp
->tt_gmtoff
);
238 ** And to get the latest zone names into tzname. . .
240 for (i
= 0; i
< sp
->timecnt
; ++i
)
242 const struct ttinfo
* CPP_CONST ttisp
= &sp
->ttis
[sp
->types
[i
]];
244 _tzname
[ttisp
->tt_isdst
] = (char *)&sp
->chars
[ttisp
->tt_abbrind
];
251 static char dir
[80]={0}, *cp
;
254 if ((cp
= getenv("TZDIR")))
258 else if ((cp
= getenv("DJDIR")))
261 strcat(dir
, "/zoneinfo");
270 tzload(const char *name
, struct state
* CPP_CONST sp
)
275 char fullname
[FILENAME_MAX
+ 1];
276 const struct tzhead
* tzhp
;
277 char buf
[sizeof *sp
+ sizeof *tzhp
];
280 if (name
== NULL
&& (name
= TZDEFAULT
) == NULL
)
287 if ((p
= tzdir()) == NULL
)
289 if ((strlen(p
) + strlen(name
) + 1) >= sizeof fullname
)
292 strcat(fullname
, "/");
293 strcat(fullname
, name
);
297 if ((fid
= open(name
, OPEN_MODE
)) == -1)
299 const char *base
= strrchr(name
, '/');
304 if (strcmp(base
, "posixrules"))
307 /* We've got a built-in copy of posixrules just in case */
308 memcpy(buf
, _posixrules_data
, sizeof(_posixrules_data
));
309 i
= sizeof(_posixrules_data
);
313 i
= read(fid
, buf
, sizeof buf
);
314 if (close(fid
) != 0 || i
< sizeof *tzhp
)
318 tzhp
= (struct tzhead
*) buf
;
319 ttisstdcnt
= (int) detzcode(tzhp
->tzh_ttisstdcnt
);
320 sp
->leapcnt
= (int) detzcode(tzhp
->tzh_leapcnt
);
321 sp
->timecnt
= (int) detzcode(tzhp
->tzh_timecnt
);
322 sp
->typecnt
= (int) detzcode(tzhp
->tzh_typecnt
);
323 sp
->charcnt
= (int) detzcode(tzhp
->tzh_charcnt
);
324 if (sp
->leapcnt
< 0 || sp
->leapcnt
> TZ_MAX_LEAPS
||
325 sp
->typecnt
<= 0 || sp
->typecnt
> TZ_MAX_TYPES
||
326 sp
->timecnt
< 0 || sp
->timecnt
> TZ_MAX_TIMES
||
327 sp
->charcnt
< 0 || sp
->charcnt
> TZ_MAX_CHARS
||
328 (ttisstdcnt
!= sp
->typecnt
&& ttisstdcnt
!= 0))
330 if (i
< sizeof *tzhp
+
331 sp
->timecnt
* (4 + sizeof (char)) +
332 sp
->typecnt
* (4 + 2 * sizeof (char)) +
333 sp
->charcnt
* sizeof (char) +
334 sp
->leapcnt
* 2 * 4 +
335 ttisstdcnt
* sizeof (char))
337 p
= buf
+ sizeof *tzhp
;
338 for (i
= 0; i
< sp
->timecnt
; ++i
)
340 sp
->ats
[i
] = detzcode(p
);
343 for (i
= 0; i
< sp
->timecnt
; ++i
)
345 sp
->types
[i
] = (unsigned char) *p
++;
346 if (sp
->types
[i
] >= sp
->typecnt
)
349 for (i
= 0; i
< sp
->typecnt
; ++i
)
351 struct ttinfo
* ttisp
;
353 ttisp
= &sp
->ttis
[i
];
354 ttisp
->tt_gmtoff
= detzcode(p
);
356 ttisp
->tt_isdst
= (unsigned char) *p
++;
357 if (ttisp
->tt_isdst
!= 0 && ttisp
->tt_isdst
!= 1)
359 ttisp
->tt_abbrind
= (unsigned char) *p
++;
360 if (ttisp
->tt_abbrind
< 0 ||
361 ttisp
->tt_abbrind
> sp
->charcnt
)
364 for (i
= 0; i
< sp
->charcnt
; ++i
)
366 sp
->chars
[i
] = '\0'; /* ensure '\0' at end */
367 for (i
= 0; i
< sp
->leapcnt
; ++i
)
369 struct lsinfo
* lsisp
;
371 lsisp
= &sp
->lsis
[i
];
372 lsisp
->ls_trans
= detzcode(p
);
374 lsisp
->ls_corr
= detzcode(p
);
377 for (i
= 0; i
< sp
->typecnt
; ++i
)
379 struct ttinfo
* ttisp
;
381 ttisp
= &sp
->ttis
[i
];
383 ttisp
->tt_ttisstd
= FALSE
;
386 ttisp
->tt_ttisstd
= *p
++;
387 if (ttisp
->tt_ttisstd
!= TRUE
&&
388 ttisp
->tt_ttisstd
!= FALSE
)
395 static const int mon_lengths
[2][MONSPERYEAR
] = {
396 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
397 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
400 static const int year_lengths
[2] = {
401 DAYSPERNYEAR
, DAYSPERLYEAR
405 ** Given a pointer into a time zone string, scan until a character that is not
406 ** a valid character in a zone name is found. Return a pointer to that
411 getzname(const char *strp
)
415 while ((c
= *strp
) != '\0' && !isdigit(c
) && c
!= ',' && c
!= '-' &&
422 ** Given a pointer into a time zone string, extract a number from that string.
423 ** Check that the number is within a specified range; if it is not, return
425 ** Otherwise, return a pointer to the first character not part of the number.
429 getnum(const char *strp
, int * CPP_CONST nump
, const int min
, const int max
)
434 if (strp
== NULL
|| !isdigit(*strp
))
437 while ((c
= *strp
) != '\0' && isdigit(c
))
439 num
= num
* 10 + (c
- '0');
451 ** Given a pointer into a time zone string, extract a number of seconds,
452 ** in hh[:mm[:ss]] form, from the string.
453 ** If any error occurs, return NULL.
454 ** Otherwise, return a pointer to the first character not part of the number
459 getsecs(const char *strp
, long * CPP_CONST secsp
)
463 strp
= getnum(strp
, &num
, 0, HOURSPERDAY
);
466 *secsp
= num
* SECSPERHOUR
;
470 strp
= getnum(strp
, &num
, 0, MINSPERHOUR
- 1);
473 *secsp
+= num
* SECSPERMIN
;
477 strp
= getnum(strp
, &num
, 0, SECSPERMIN
- 1);
487 ** Given a pointer into a time zone string, extract an offset, in
488 ** [+-]hh[:mm[:ss]] form, from the string.
489 ** If any error occurs, return NULL.
490 ** Otherwise, return a pointer to the first character not part of the time.
494 getoffset(const char *strp
, long * CPP_CONST offsetp
)
503 else if (isdigit(*strp
) || *strp
++ == '+')
506 return NULL
; /* illegal offset */
507 strp
= getsecs(strp
, offsetp
);
509 return NULL
; /* illegal time */
511 *offsetp
= -*offsetp
;
516 ** Given a pointer into a time zone string, extract a rule in the form
517 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
518 ** If a valid rule is not found, return NULL.
519 ** Otherwise, return a pointer to the first character not part of the rule.
523 getrule(const char *strp
, struct rule
* CPP_CONST rulep
)
530 rulep
->r_type
= JULIAN_DAY
;
532 strp
= getnum(strp
, &rulep
->r_day
, 1, DAYSPERNYEAR
);
534 else if (*strp
== 'M')
539 rulep
->r_type
= MONTH_NTH_DAY_OF_WEEK
;
541 strp
= getnum(strp
, &rulep
->r_mon
, 1, MONSPERYEAR
);
546 strp
= getnum(strp
, &rulep
->r_week
, 1, 5);
551 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERWEEK
- 1);
553 else if (isdigit(*strp
))
558 rulep
->r_type
= DAY_OF_YEAR
;
559 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERLYEAR
- 1);
562 return NULL
; /* invalid format */
571 strp
= getsecs(strp
, &rulep
->r_time
);
574 rulep
->r_time
= 2 * SECSPERHOUR
; /* default = 2:00:00 */
579 ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
580 ** year, a rule, and the offset from GMT at the time that rule takes effect,
581 ** calculate the Epoch-relative time that rule takes effect.
585 transtime(const time_t janfirst
, const int year
, const struct rule
* CPP_CONST rulep
, const long offset
)
590 int d
, m1
, yy0
, yy1
, yy2
, dow
;
592 leapyear
= isleap(year
);
593 switch (rulep
->r_type
)
598 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
600 ** In non-leap years, or if the day number is 59 or less, just
601 ** add SECSPERDAY times the day number-1 to the time of
602 ** January 1, midnight, to get the day.
604 value
= janfirst
+ (rulep
->r_day
- 1) * SECSPERDAY
;
605 if (leapyear
&& rulep
->r_day
>= 60)
612 ** Just add SECSPERDAY times the day number to the time of
613 ** January 1, midnight, to get the day.
615 value
= janfirst
+ rulep
->r_day
* SECSPERDAY
;
618 case MONTH_NTH_DAY_OF_WEEK
:
620 ** Mm.n.d - nth "dth day" of month m.
623 for (i
= 0; i
< rulep
->r_mon
- 1; ++i
)
624 value
+= mon_lengths
[leapyear
][i
] * SECSPERDAY
;
627 ** Use Zeller's Congruence to get day-of-week of first day of
630 m1
= (rulep
->r_mon
+ 9) % 12 + 1;
631 yy0
= (rulep
->r_mon
<= 2) ? (year
- 1) : year
;
634 dow
= ((26 * m1
- 2) / 10 +
635 1 + yy2
+ yy2
/ 4 + yy1
/ 4 - 2 * yy1
) % 7;
640 ** "dow" is the day-of-week of the first day of the month. Get
641 ** the day-of-month (zero-origin) of the first "dow" day of the
644 d
= rulep
->r_day
- dow
;
647 for (i
= 1; i
< rulep
->r_week
; ++i
)
649 if (d
+ DAYSPERWEEK
>=
650 mon_lengths
[leapyear
][rulep
->r_mon
- 1])
656 ** "d" is the day-of-month (zero-origin) of the day we want.
658 value
+= d
* SECSPERDAY
;
663 ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
664 ** question. To get the Epoch-relative time of the specified local
665 ** time on that day, add the transition time and the current offset
668 return value
+ rulep
->r_time
+ offset
;
672 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
677 tzparse(const char *name
, struct state
* CPP_CONST sp
, const int lastditch
)
679 const char * stdname
;
680 const char * dstname
=0;
686 unsigned char * typep
;
693 stdlen
= strlen(name
); /* length of standard zone name */
695 if (stdlen
>= sizeof sp
->chars
)
696 stdlen
= (sizeof sp
->chars
) - 1;
700 name
= getzname(name
);
701 stdlen
= name
- stdname
;
709 name
= getoffset(name
, &stdoffset
);
713 load_result
= tzload(TZDEFRULES
, sp
);
714 if (load_result
!= 0)
715 sp
->leapcnt
= 0; /* so, we're off a little */
719 name
= getzname(name
);
720 dstlen
= name
- dstname
; /* length of DST zone name */
723 if (*name
!= '\0' && *name
!= ',' && *name
!= ';')
725 name
= getoffset(name
, &dstoffset
);
730 dstoffset
= stdoffset
- SECSPERHOUR
;
731 if (*name
== ',' || *name
== ';')
741 if ((name
= getrule(name
, &start
)) == NULL
)
745 if ((name
= getrule(name
, &end
)) == NULL
)
749 sp
->typecnt
= 2; /* standard time and DST */
751 ** Two transitions per year, from EPOCH_YEAR to 2037.
753 sp
->timecnt
= 2 * (2037 - EPOCH_YEAR
+ 1);
754 if (sp
->timecnt
> TZ_MAX_TIMES
)
756 sp
->ttis
[0].tt_gmtoff
= -dstoffset
;
757 sp
->ttis
[0].tt_isdst
= 1;
758 sp
->ttis
[0].tt_abbrind
= stdlen
+ 1;
759 sp
->ttis
[1].tt_gmtoff
= -stdoffset
;
760 sp
->ttis
[1].tt_isdst
= 0;
761 sp
->ttis
[1].tt_abbrind
= 0;
765 for (year
= EPOCH_YEAR
; year
<= 2037; ++year
)
767 starttime
= transtime(janfirst
, year
, &start
,
769 endtime
= transtime(janfirst
, year
, &end
,
771 if (starttime
> endtime
)
774 *typep
++ = 1; /* DST ends */
776 *typep
++ = 0; /* DST begins */
781 *typep
++ = 0; /* DST begins */
783 *typep
++ = 1; /* DST ends */
786 year_lengths
[isleap(year
)] * SECSPERDAY
;
801 if (load_result
!= 0)
804 ** Compute the difference between the real and
805 ** prototype standard and summer time offsets
806 ** from GMT, and put the real standard and summer
807 ** time offsets into the rules in place of the
808 ** prototype offsets.
814 for (i
= 0; i
< sp
->typecnt
; ++i
)
816 if (sp
->ttis
[i
].tt_isdst
)
820 sp
->ttis
[i
].tt_gmtoff
+ dstoffset
;
821 if (sawdst
&& (oldfix
!= dstfix
))
823 sp
->ttis
[i
].tt_gmtoff
= -dstoffset
;
824 sp
->ttis
[i
].tt_abbrind
= stdlen
+ 1;
831 sp
->ttis
[i
].tt_gmtoff
+ stdoffset
;
832 if (sawstd
&& (oldfix
!= stdfix
))
834 sp
->ttis
[i
].tt_gmtoff
= -stdoffset
;
835 sp
->ttis
[i
].tt_abbrind
= 0;
840 ** Make sure we have both standard and summer time.
842 if (!sawdst
|| !sawstd
)
845 ** Now correct the transition times by shifting
846 ** them by the difference between the real and
847 ** prototype offsets. Note that this difference
848 ** can be different in standard and summer time;
849 ** the prototype probably has a 1-hour difference
850 ** between standard and summer time, but a different
851 ** difference can be specified in TZ.
853 isdst
= FALSE
; /* we start in standard time */
854 for (i
= 0; i
< sp
->timecnt
; ++i
)
856 const struct ttinfo
* ttisp
;
859 ** If summer time is in effect, and the
860 ** transition time was not specified as
861 ** standard time, add the summer time
862 ** offset to the transition time;
863 ** otherwise, add the standard time offset
864 ** to the transition time.
866 ttisp
= &sp
->ttis
[sp
->types
[i
]];
868 (isdst
&& !ttisp
->tt_ttisstd
) ?
870 isdst
= ttisp
->tt_isdst
;
877 sp
->typecnt
= 1; /* only standard time */
879 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
880 sp
->ttis
[0].tt_isdst
= 0;
881 sp
->ttis
[0].tt_abbrind
= 0;
883 sp
->charcnt
= stdlen
+ 1;
885 sp
->charcnt
+= dstlen
+ 1;
886 if (sp
->charcnt
> sizeof sp
->chars
)
889 (void) strncpy(cp
, stdname
, stdlen
);
894 (void) strncpy(cp
, dstname
, dstlen
);
895 *(cp
+ dstlen
) = '\0';
901 gmtload(struct state
* CPP_CONST sp
)
903 if (tzload(GMT
, sp
) != 0)
904 (void) tzparse(GMT
, sp
, TRUE
);
925 lclptr
= (struct state
*) malloc(sizeof *lclptr
);
928 settzname(); /* all we can do */
932 #endif /* defined ALL_STATE */
936 ** User wants it fast rather than right.
938 lclptr
->leapcnt
= 0; /* so, we're off a little */
940 lclptr
->ttis
[0].tt_gmtoff
= 0;
941 lclptr
->ttis
[0].tt_abbrind
= 0;
942 (void) strcpy(lclptr
->chars
, GMT
);
944 else if (tzload(name
, lclptr
) != 0)
945 if (name
[0] == ':' || tzparse(name
, lclptr
, FALSE
) != 0)
957 lclptr
= (struct state
*) malloc(sizeof *lclptr
);
960 settzname(); /* all we can do */
964 #endif /* defined ALL_STATE */
965 if (tzload((char *) NULL
, lclptr
) != 0)
971 ** The easy way to behave "as if no library function calls" localtime
972 ** is to not call it--so we drop its guts into "localsub", which can be
973 ** freely called. (And no, the PANS doesn't require the above behavior--
974 ** but it *is* desirable.)
976 ** The unused offset argument is for the benefit of mktime variants.
981 localsub(const time_t * CPP_CONST timep
, const long offset
, struct tm
* CPP_CONST tmp
)
983 const struct state
* sp
;
984 const struct ttinfo
* ttisp
;
986 const time_t t
= *timep
;
994 gmtsub(timep
, offset
, tmp
);
997 #endif /* defined ALL_STATE */
998 if (sp
->timecnt
== 0 || t
< sp
->ats
[0])
1001 while (sp
->ttis
[i
].tt_isdst
)
1002 if (++i
>= sp
->typecnt
)
1010 for (i
= 1; i
< sp
->timecnt
; ++i
)
1013 i
= sp
->types
[i
- 1];
1015 ttisp
= &sp
->ttis
[i
];
1017 ** To get (wrong) behavior that's compatible with System V Release 2.0
1018 ** you'd replace the statement below with
1019 ** t += ttisp->tt_gmtoff;
1020 ** timesub(&t, 0L, sp, tmp);
1022 timesub(&t
, ttisp
->tt_gmtoff
, sp
, tmp
);
1023 tmp
->tm_isdst
= ttisp
->tt_isdst
;
1024 _tzname
[tmp
->tm_isdst
] = (char *)&sp
->chars
[ttisp
->tt_abbrind
];
1025 tmp
->tm_zone
= (char *)&sp
->chars
[ttisp
->tt_abbrind
];
1032 localtime(const time_t * CPP_CONST timep
)
1034 static struct tm tm
;
1036 localsub(timep
, 0L, &tm
);
1041 ** gmtsub is to gmtime as localsub is to localtime.
1045 gmtsub(const time_t * CPP_CONST timep
, const long offset
, struct tm
* CPP_CONST tmp
)
1051 gmtptr
= (struct state
*) malloc(sizeof *gmtptr
);
1053 #endif /* defined ALL_STATE */
1056 timesub(timep
, offset
, gmtptr
, tmp
);
1058 ** Could get fancy here and deliver something such as
1059 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
1060 ** but this is no time for a treasure hunt.
1063 tmp
->tm_zone
= TZ_NAME
;
1070 tmp
->TM_ZONE
= gmtptr
->chars
;
1071 #endif /* defined ALL_STATE */
1073 tmp
->tm_zone
= gmtptr
->chars
;
1074 #endif /* State Farm */
1082 gmtime(const time_t * CPP_CONST timep
)
1084 static struct tm tm
;
1086 gmtsub(timep
, 0L, &tm
);
1091 timesub(const time_t * CPP_CONST timep
, const long offset
, const struct state
* CPP_CONST sp
, struct tm
* CPP_CONST tmp
)
1093 const struct lsinfo
* lp
;
1106 i
= (sp
== NULL
) ? 0 : sp
->leapcnt
;
1107 #endif /* defined ALL_STATE */
1110 #endif /* State Farm */
1114 if (*timep
>= lp
->ls_trans
)
1116 if (*timep
== lp
->ls_trans
)
1117 hit
= ((i
== 0 && lp
->ls_corr
> 0) ||
1118 lp
->ls_corr
> sp
->lsis
[i
- 1].ls_corr
);
1123 days
= *timep
/ SECSPERDAY
;
1124 rem
= *timep
% SECSPERDAY
;
1126 if (*timep
== 0x80000000)
1129 ** A 3B1 muffs the division on the most negative number.
1135 rem
+= (offset
- corr
);
1141 while (rem
>= SECSPERDAY
)
1146 tmp
->tm_hour
= (int) (rem
/ SECSPERHOUR
);
1147 rem
= rem
% SECSPERHOUR
;
1148 tmp
->tm_min
= (int) (rem
/ SECSPERMIN
);
1149 tmp
->tm_sec
= (int) (rem
% SECSPERMIN
);
1152 ** A positive leap second requires a special
1153 ** representation. This uses "... ??:59:60".
1156 tmp
->tm_wday
= (int) ((EPOCH_WDAY
+ days
) % DAYSPERWEEK
);
1157 if (tmp
->tm_wday
< 0)
1158 tmp
->tm_wday
+= DAYSPERWEEK
;
1164 if (days
< (long) year_lengths
[yleap
])
1167 days
= days
- (long) year_lengths
[yleap
];
1173 days
= days
+ (long) year_lengths
[yleap
];
1175 tmp
->tm_year
= y
- TM_YEAR_BASE
;
1176 tmp
->tm_yday
= (int) days
;
1177 ip
= mon_lengths
[yleap
];
1178 for (tmp
->tm_mon
= 0; days
>= (long) ip
[tmp
->tm_mon
]; ++(tmp
->tm_mon
))
1179 days
= days
- (long) ip
[tmp
->tm_mon
];
1180 tmp
->tm_mday
= (int) (days
+ 1);
1182 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
;
1279 struct tm yourtm
, mytm
;
1283 if (yourtm
.tm_sec
>= SECSPERMIN
+ 2 || yourtm
.tm_sec
< 0)
1284 normalize(&yourtm
.tm_min
, &yourtm
.tm_sec
, SECSPERMIN
);
1285 normalize(&yourtm
.tm_hour
, &yourtm
.tm_min
, MINSPERHOUR
);
1286 normalize(&yourtm
.tm_mday
, &yourtm
.tm_hour
, HOURSPERDAY
);
1287 normalize(&yourtm
.tm_year
, &yourtm
.tm_mon
, MONSPERYEAR
);
1288 while (yourtm
.tm_mday
<= 0)
1292 year_lengths
[isleap(yourtm
.tm_year
+ TM_YEAR_BASE
)];
1296 i
= mon_lengths
[isleap(yourtm
.tm_year
+
1297 TM_YEAR_BASE
)][yourtm
.tm_mon
];
1298 if (yourtm
.tm_mday
<= i
)
1300 yourtm
.tm_mday
-= i
;
1301 if (++yourtm
.tm_mon
>= MONSPERYEAR
)
1307 saved_seconds
= yourtm
.tm_sec
;
1310 ** Calculate the number of magnitude bits in a time_t
1311 ** (this works regardless of whether time_t is
1312 ** signed or unsigned, though lint complains if unsigned).
1314 for (bits
= 0, t
= 1; t
> 0; ++bits
, t
<<= 1)
1317 ** If time_t is signed, then 0 is the median value,
1318 ** if time_t is unsigned, then 1 << bits is median.
1321 t
= (time_t) ((1 << bits
) - 1);
1322 #else // TODO: FIXME: review which is correct
1323 t
= (time_t) 1 << bits
;
1324 #endif /*_MSVCRT_LIB_*/
1328 (*funcp
)(&t
, offset
, &mytm
);
1329 dir
= tmcomp(&mytm
, &yourtm
);
1337 t
-= (time_t) 1 << bits
;
1338 else t
+= (time_t) 1 << bits
;
1341 if (yourtm
.tm_isdst
< 0 || mytm
.tm_isdst
== yourtm
.tm_isdst
)
1344 ** Right time, wrong type.
1345 ** Hunt for right time, right type.
1346 ** It's okay to guess wrong since the guess
1349 sp
= (const struct state
*)
1350 ((funcp
== localsub
) ? lclptr
: gmtptr
);
1354 #endif /* defined ALL_STATE */
1355 for (i
= 0; i
< sp
->typecnt
; ++i
)
1357 if (sp
->ttis
[i
].tt_isdst
!= yourtm
.tm_isdst
)
1359 for (j
= 0; j
< sp
->typecnt
; ++j
)
1361 if (sp
->ttis
[j
].tt_isdst
== yourtm
.tm_isdst
)
1363 newt
= t
+ sp
->ttis
[j
].tt_gmtoff
-
1364 sp
->ttis
[i
].tt_gmtoff
;
1365 (*funcp
)(&newt
, offset
, &mytm
);
1366 if (tmcomp(&mytm
, &yourtm
) != 0)
1368 if (mytm
.tm_isdst
!= yourtm
.tm_isdst
)
1381 (*funcp
)(&t
, offset
, tmp
);
1387 time1(struct tm
* CPP_CONST tmp
, void (*const funcp
)(const time_t * CPP_CONST
, const long, struct tm
*), const long offset
)
1390 const struct state
* sp
;
1394 if (tmp
->tm_isdst
> 1)
1396 t
= time2(tmp
, funcp
, offset
, &okay
);
1397 if (okay
|| tmp
->tm_isdst
< 0)
1400 ** We're supposed to assume that somebody took a time of one type
1401 ** and did some math on it that yielded a "struct tm" that's bad.
1402 ** We try to divine the type they started from and adjust to the
1405 sp
= (const struct state
*) ((funcp
== localsub
) ? lclptr
: gmtptr
);
1409 #endif /* defined ALL_STATE */
1410 for (samei
= 0; samei
< sp
->typecnt
; ++samei
)
1412 if (sp
->ttis
[samei
].tt_isdst
!= tmp
->tm_isdst
)
1414 for (otheri
= 0; otheri
< sp
->typecnt
; ++otheri
)
1416 if (sp
->ttis
[otheri
].tt_isdst
== tmp
->tm_isdst
)
1418 tmp
->tm_sec
+= sp
->ttis
[otheri
].tt_gmtoff
-
1419 sp
->ttis
[samei
].tt_gmtoff
;
1420 tmp
->tm_isdst
= !tmp
->tm_isdst
;
1421 t
= time2(tmp
, funcp
, offset
, &okay
);
1424 tmp
->tm_sec
-= sp
->ttis
[otheri
].tt_gmtoff
-
1425 sp
->ttis
[samei
].tt_gmtoff
;
1426 tmp
->tm_isdst
= !tmp
->tm_isdst
;
1436 mktime(struct tm
* tmp
)
1438 return time1(tmp
, localsub
, 0L);