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.
32 #if defined(LIBC_SCCS) && !defined(lint)
33 static char sccsid
[] = "@(#)ctime.c 5.23 (Berkeley) 6/22/90";
34 #endif /* LIBC_SCCS and not lint */
37 ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
38 ** POSIX-style TZ environment variable handling from Guy Harris
42 #include <msvcrt/fcntl.h>
43 #include <msvcrt/time.h>
44 #include <msvcrt/string.h>
45 #include <msvcrt/ctype.h>
46 #include <msvcrt/stdio.h>
47 #include <msvcrt/stdlib.h>
52 #include <msvcrt/io.h>
57 #define CPP_CONST const
63 #define alloc_size_t size_t
64 #define qsort_size_t size_t
65 #define fread_size_t size_t
66 #define fwrite_size_t size_t
68 #define ACCESS_MODE O_RDONLY|O_BINARY
69 #define OPEN_MODE O_RDONLY|O_BINARY
72 ** Someone might make incorrect use of a time zone abbreviation:
73 ** 1. They might reference tzname[0] before calling tzset (explicitly
75 ** 2. They might reference tzname[1] before calling tzset (explicitly
77 ** 3. They might reference tzname[1] after setting to a time zone
78 ** in which Daylight Saving Time is never observed.
79 ** 4. They might reference tzname[0] after setting to a time zone
80 ** in which Standard Time is never observed.
81 ** 5. They might reference tm.TM_ZONE after calling offtime.
82 ** What's best to do in the above cases is open to debate;
83 ** for now, we just set things up so that in any of the five cases
84 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
85 ** string "tzname[0] used before set", and similarly for the other cases.
86 ** And another: initialize tzname[0] to "ERA", with an explanation in the
87 ** manual page of what this "time zone abbreviation" means (doing this so
88 ** that tzname[0] has the "normal" length of three characters).
97 #endif /*_MSVCRT_LIB_*/
99 static char WILDABBR
[] = " ";
104 #endif /* !defined TRUE */
106 static const char GMT
[] = "GMT";
108 struct ttinfo
{ /* time type information */
109 long tt_gmtoff
; /* GMT offset in seconds */
110 int tt_isdst
; /* used to set tm_isdst */
111 int tt_abbrind
; /* abbreviation list index */
112 int tt_ttisstd
; /* TRUE if transition is std time */
115 struct lsinfo
{ /* leap second information */
116 time_t ls_trans
; /* transition time */
117 long ls_corr
; /* correction to apply */
125 time_t ats
[TZ_MAX_TIMES
];
126 unsigned char types
[TZ_MAX_TIMES
];
127 struct ttinfo ttis
[TZ_MAX_TYPES
];
128 char chars
[(TZ_MAX_CHARS
+ 1 > sizeof GMT
) ? TZ_MAX_CHARS
+ 1 : sizeof GMT
];
129 struct lsinfo lsis
[TZ_MAX_LEAPS
];
133 int r_type
; /* type of rule--see below */
134 int r_day
; /* day number of rule */
135 int r_week
; /* week number of rule */
136 int r_mon
; /* month number of rule */
137 long r_time
; /* transition time of rule */
140 #define JULIAN_DAY 0 /* Jn - Julian day */
141 #define DAY_OF_YEAR 1 /* n - day of year */
142 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
145 ** Prototypes for static functions.
148 static long detzcode
P((const char * codep
));
149 static const char * getzname
P((const char * strp
));
150 static const char * getnum
P((const char * strp
, int * nump
, int min
, int max
));
151 static const char * getsecs
P((const char * strp
, long * secsp
));
152 static const char * getoffset
P((const char * strp
, long * offsetp
));
153 static const char * getrule
P((const char * strp
, struct rule
* rulep
));
154 static void gmtload
P((struct state
* sp
));
155 static void gmtsub
P((const time_t * timep
, long offset
, struct tm
* tmp
));
156 static void localsub
P((const time_t * timep
, long offset
, struct tm
* tmp
));
157 static void normalize
P((int * tensptr
, int * unitsptr
, int base
));
158 static void settzname
P((void));
159 static time_t time1
P((struct tm
* tmp
, void (* funcp
)(const time_t * CPP_CONST
, const long, struct tm
* CPP_CONST
), long offset
));
160 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
));
161 static void timesub
P((const time_t * timep
, long offset
, const struct state
* sp
, struct tm
* tmp
));
162 static int tmcomp
P((const struct tm
* atmp
, const struct tm
* btmp
));
163 static time_t transtime
P((time_t janfirst
, int year
, const struct rule
* rulep
, long offset
));
164 static int tzload
P((const char * name
, struct state
* sp
));
165 static int tzparse
P((const char * name
, struct state
* sp
, int lastditch
));
166 static void tzsetwall(void);
170 static const char * getnum(const char * strp
, int * CPP_CONST nump
, const int min
, const int max
);
171 static void timesub(const time_t * CPP_CONST timep
, const long offset
, const struct state
* CPP_CONST sp
, struct tm
* CPP_CONST tmp
);
172 static time_t transtime(const time_t janfirst
, const int year
, const struct rule
* CPP_CONST rulep
, const long offset
);
173 static void tzsetwall(void);
178 static struct state
*lclptr
;
179 static struct state
*gmtptr
;
180 #endif /* defined ALL_STATE */
183 static struct state lclmem
;
184 static struct state gmtmem
;
185 #define lclptr (&lclmem)
186 #define gmtptr (&gmtmem)
187 #endif /* State Farm */
189 static int lcl_is_set
;
190 static int gmt_is_set
;
192 char * _tzname
[2] = {
198 detzcode(const char * CPP_CONST codep
)
204 for (i
= 0; i
< 4; ++i
)
205 result
= (result
<< 8) | (codep
[i
] & 0xff);
212 const struct state
* CPP_CONST sp
= lclptr
;
215 _tzname
[0] = WILDABBR
;
216 _tzname
[1] = WILDABBR
;
220 _tzname
[0] = _tzname
[1] = GMT
;
223 #endif /* defined ALL_STATE */
224 for (i
= 0; i
< sp
->typecnt
; ++i
)
226 register const struct ttinfo
* CPP_CONST ttisp
= &sp
->ttis
[i
];
228 _tzname
[ttisp
->tt_isdst
] =
229 (char *)&sp
->chars
[ttisp
->tt_abbrind
];
233 if (i
== 0 || !ttisp
->tt_isdst
)
234 _timezone_dll
= -(ttisp
->tt_gmtoff
);
235 if (i
== 0 || ttisp
->tt_isdst
)
236 _altzone
= -(ttisp
->tt_gmtoff
);
240 ** And to get the latest zone names into tzname. . .
242 for (i
= 0; i
< sp
->timecnt
; ++i
)
244 const struct ttinfo
* CPP_CONST ttisp
= &sp
->ttis
[sp
->types
[i
]];
246 _tzname
[ttisp
->tt_isdst
] = (char *)&sp
->chars
[ttisp
->tt_abbrind
];
253 static char dir
[80]={0}, *cp
;
256 if ((cp
= getenv("TZDIR")))
260 else if ((cp
= getenv("DJDIR")))
263 strcat(dir
, "/zoneinfo");
272 tzload(const char *name
, struct state
* CPP_CONST sp
)
277 char fullname
[FILENAME_MAX
+ 1];
278 const struct tzhead
* tzhp
;
279 char buf
[sizeof *sp
+ sizeof *tzhp
];
282 if (name
== NULL
&& (name
= TZDEFAULT
) == NULL
)
289 if ((p
= tzdir()) == NULL
)
291 if ((strlen(p
) + strlen(name
) + 1) >= sizeof fullname
)
294 strcat(fullname
, "/");
295 strcat(fullname
, name
);
299 if ((fid
= open(name
, OPEN_MODE
)) == -1)
301 const char *base
= strrchr(name
, '/');
306 if (strcmp(base
, "posixrules"))
309 /* We've got a built-in copy of posixrules just in case */
310 memcpy(buf
, _posixrules_data
, sizeof(_posixrules_data
));
311 i
= sizeof(_posixrules_data
);
315 i
= read(fid
, buf
, sizeof buf
);
316 if (close(fid
) != 0 || i
< sizeof *tzhp
)
320 tzhp
= (struct tzhead
*) buf
;
321 ttisstdcnt
= (int) detzcode(tzhp
->tzh_ttisstdcnt
);
322 sp
->leapcnt
= (int) detzcode(tzhp
->tzh_leapcnt
);
323 sp
->timecnt
= (int) detzcode(tzhp
->tzh_timecnt
);
324 sp
->typecnt
= (int) detzcode(tzhp
->tzh_typecnt
);
325 sp
->charcnt
= (int) detzcode(tzhp
->tzh_charcnt
);
326 if (sp
->leapcnt
< 0 || sp
->leapcnt
> TZ_MAX_LEAPS
||
327 sp
->typecnt
<= 0 || sp
->typecnt
> TZ_MAX_TYPES
||
328 sp
->timecnt
< 0 || sp
->timecnt
> TZ_MAX_TIMES
||
329 sp
->charcnt
< 0 || sp
->charcnt
> TZ_MAX_CHARS
||
330 (ttisstdcnt
!= sp
->typecnt
&& ttisstdcnt
!= 0))
332 if (i
< sizeof *tzhp
+
333 sp
->timecnt
* (4 + sizeof (char)) +
334 sp
->typecnt
* (4 + 2 * sizeof (char)) +
335 sp
->charcnt
* sizeof (char) +
336 sp
->leapcnt
* 2 * 4 +
337 ttisstdcnt
* sizeof (char))
339 p
= buf
+ sizeof *tzhp
;
340 for (i
= 0; i
< sp
->timecnt
; ++i
)
342 sp
->ats
[i
] = detzcode(p
);
345 for (i
= 0; i
< sp
->timecnt
; ++i
)
347 sp
->types
[i
] = (unsigned char) *p
++;
348 if (sp
->types
[i
] >= sp
->typecnt
)
351 for (i
= 0; i
< sp
->typecnt
; ++i
)
353 struct ttinfo
* ttisp
;
355 ttisp
= &sp
->ttis
[i
];
356 ttisp
->tt_gmtoff
= detzcode(p
);
358 ttisp
->tt_isdst
= (unsigned char) *p
++;
359 if (ttisp
->tt_isdst
!= 0 && ttisp
->tt_isdst
!= 1)
361 ttisp
->tt_abbrind
= (unsigned char) *p
++;
362 if (ttisp
->tt_abbrind
< 0 ||
363 ttisp
->tt_abbrind
> sp
->charcnt
)
366 for (i
= 0; i
< sp
->charcnt
; ++i
)
368 sp
->chars
[i
] = '\0'; /* ensure '\0' at end */
369 for (i
= 0; i
< sp
->leapcnt
; ++i
)
371 struct lsinfo
* lsisp
;
373 lsisp
= &sp
->lsis
[i
];
374 lsisp
->ls_trans
= detzcode(p
);
376 lsisp
->ls_corr
= detzcode(p
);
379 for (i
= 0; i
< sp
->typecnt
; ++i
)
381 struct ttinfo
* ttisp
;
383 ttisp
= &sp
->ttis
[i
];
385 ttisp
->tt_ttisstd
= FALSE
;
388 ttisp
->tt_ttisstd
= *p
++;
389 if (ttisp
->tt_ttisstd
!= TRUE
&&
390 ttisp
->tt_ttisstd
!= FALSE
)
397 static const int mon_lengths
[2][MONSPERYEAR
] = {
398 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
399 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
402 static const int year_lengths
[2] = {
403 DAYSPERNYEAR
, DAYSPERLYEAR
407 ** Given a pointer into a time zone string, scan until a character that is not
408 ** a valid character in a zone name is found. Return a pointer to that
413 getzname(const char *strp
)
417 while ((c
= *strp
) != '\0' && !isdigit(c
) && c
!= ',' && c
!= '-' &&
424 ** Given a pointer into a time zone string, extract a number from that string.
425 ** Check that the number is within a specified range; if it is not, return
427 ** Otherwise, return a pointer to the first character not part of the number.
431 getnum(const char *strp
, int * CPP_CONST nump
, const int min
, const int max
)
436 if (strp
== NULL
|| !isdigit(*strp
))
439 while ((c
= *strp
) != '\0' && isdigit(c
))
441 num
= num
* 10 + (c
- '0');
453 ** Given a pointer into a time zone string, extract a number of seconds,
454 ** in hh[:mm[:ss]] form, from the string.
455 ** If any error occurs, return NULL.
456 ** Otherwise, return a pointer to the first character not part of the number
461 getsecs(const char *strp
, long * CPP_CONST secsp
)
465 strp
= getnum(strp
, &num
, 0, HOURSPERDAY
);
468 *secsp
= num
* SECSPERHOUR
;
472 strp
= getnum(strp
, &num
, 0, MINSPERHOUR
- 1);
475 *secsp
+= num
* SECSPERMIN
;
479 strp
= getnum(strp
, &num
, 0, SECSPERMIN
- 1);
489 ** Given a pointer into a time zone string, extract an offset, in
490 ** [+-]hh[:mm[:ss]] form, from the string.
491 ** If any error occurs, return NULL.
492 ** Otherwise, return a pointer to the first character not part of the time.
496 getoffset(const char *strp
, long * CPP_CONST offsetp
)
505 else if (isdigit(*strp
) || *strp
++ == '+')
508 return NULL
; /* illegal offset */
509 strp
= getsecs(strp
, offsetp
);
511 return NULL
; /* illegal time */
513 *offsetp
= -*offsetp
;
518 ** Given a pointer into a time zone string, extract a rule in the form
519 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
520 ** If a valid rule is not found, return NULL.
521 ** Otherwise, return a pointer to the first character not part of the rule.
525 getrule(const char *strp
, struct rule
* CPP_CONST rulep
)
532 rulep
->r_type
= JULIAN_DAY
;
534 strp
= getnum(strp
, &rulep
->r_day
, 1, DAYSPERNYEAR
);
536 else if (*strp
== 'M')
541 rulep
->r_type
= MONTH_NTH_DAY_OF_WEEK
;
543 strp
= getnum(strp
, &rulep
->r_mon
, 1, MONSPERYEAR
);
548 strp
= getnum(strp
, &rulep
->r_week
, 1, 5);
553 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERWEEK
- 1);
555 else if (isdigit(*strp
))
560 rulep
->r_type
= DAY_OF_YEAR
;
561 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERLYEAR
- 1);
564 return NULL
; /* invalid format */
573 strp
= getsecs(strp
, &rulep
->r_time
);
576 rulep
->r_time
= 2 * SECSPERHOUR
; /* default = 2:00:00 */
581 ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
582 ** year, a rule, and the offset from GMT at the time that rule takes effect,
583 ** calculate the Epoch-relative time that rule takes effect.
587 transtime(const time_t janfirst
, const int year
, const struct rule
* CPP_CONST rulep
, const long offset
)
592 int d
, m1
, yy0
, yy1
, yy2
, dow
;
594 leapyear
= isleap(year
);
595 switch (rulep
->r_type
)
600 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
602 ** In non-leap years, or if the day number is 59 or less, just
603 ** add SECSPERDAY times the day number-1 to the time of
604 ** January 1, midnight, to get the day.
606 value
= janfirst
+ (rulep
->r_day
- 1) * SECSPERDAY
;
607 if (leapyear
&& rulep
->r_day
>= 60)
614 ** Just add SECSPERDAY times the day number to the time of
615 ** January 1, midnight, to get the day.
617 value
= janfirst
+ rulep
->r_day
* SECSPERDAY
;
620 case MONTH_NTH_DAY_OF_WEEK
:
622 ** Mm.n.d - nth "dth day" of month m.
625 for (i
= 0; i
< rulep
->r_mon
- 1; ++i
)
626 value
+= mon_lengths
[leapyear
][i
] * SECSPERDAY
;
629 ** Use Zeller's Congruence to get day-of-week of first day of
632 m1
= (rulep
->r_mon
+ 9) % 12 + 1;
633 yy0
= (rulep
->r_mon
<= 2) ? (year
- 1) : year
;
636 dow
= ((26 * m1
- 2) / 10 +
637 1 + yy2
+ yy2
/ 4 + yy1
/ 4 - 2 * yy1
) % 7;
642 ** "dow" is the day-of-week of the first day of the month. Get
643 ** the day-of-month (zero-origin) of the first "dow" day of the
646 d
= rulep
->r_day
- dow
;
649 for (i
= 1; i
< rulep
->r_week
; ++i
)
651 if (d
+ DAYSPERWEEK
>=
652 mon_lengths
[leapyear
][rulep
->r_mon
- 1])
658 ** "d" is the day-of-month (zero-origin) of the day we want.
660 value
+= d
* SECSPERDAY
;
665 ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
666 ** question. To get the Epoch-relative time of the specified local
667 ** time on that day, add the transition time and the current offset
670 return value
+ rulep
->r_time
+ offset
;
674 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
679 tzparse(const char *name
, struct state
* CPP_CONST sp
, const int lastditch
)
681 const char * stdname
;
682 const char * dstname
=0;
688 unsigned char * typep
;
695 stdlen
= strlen(name
); /* length of standard zone name */
697 if (stdlen
>= sizeof sp
->chars
)
698 stdlen
= (sizeof sp
->chars
) - 1;
702 name
= getzname(name
);
703 stdlen
= name
- stdname
;
711 name
= getoffset(name
, &stdoffset
);
715 load_result
= tzload(TZDEFRULES
, sp
);
716 if (load_result
!= 0)
717 sp
->leapcnt
= 0; /* so, we're off a little */
721 name
= getzname(name
);
722 dstlen
= name
- dstname
; /* length of DST zone name */
725 if (*name
!= '\0' && *name
!= ',' && *name
!= ';')
727 name
= getoffset(name
, &dstoffset
);
732 dstoffset
= stdoffset
- SECSPERHOUR
;
733 if (*name
== ',' || *name
== ';')
743 if ((name
= getrule(name
, &start
)) == NULL
)
747 if ((name
= getrule(name
, &end
)) == NULL
)
751 sp
->typecnt
= 2; /* standard time and DST */
753 ** Two transitions per year, from EPOCH_YEAR to 2037.
755 sp
->timecnt
= 2 * (2037 - EPOCH_YEAR
+ 1);
756 if (sp
->timecnt
> TZ_MAX_TIMES
)
758 sp
->ttis
[0].tt_gmtoff
= -dstoffset
;
759 sp
->ttis
[0].tt_isdst
= 1;
760 sp
->ttis
[0].tt_abbrind
= stdlen
+ 1;
761 sp
->ttis
[1].tt_gmtoff
= -stdoffset
;
762 sp
->ttis
[1].tt_isdst
= 0;
763 sp
->ttis
[1].tt_abbrind
= 0;
767 for (year
= EPOCH_YEAR
; year
<= 2037; ++year
)
769 starttime
= transtime(janfirst
, year
, &start
,
771 endtime
= transtime(janfirst
, year
, &end
,
773 if (starttime
> endtime
)
776 *typep
++ = 1; /* DST ends */
778 *typep
++ = 0; /* DST begins */
783 *typep
++ = 0; /* DST begins */
785 *typep
++ = 1; /* DST ends */
788 year_lengths
[isleap(year
)] * SECSPERDAY
;
803 if (load_result
!= 0)
806 ** Compute the difference between the real and
807 ** prototype standard and summer time offsets
808 ** from GMT, and put the real standard and summer
809 ** time offsets into the rules in place of the
810 ** prototype offsets.
816 for (i
= 0; i
< sp
->typecnt
; ++i
)
818 if (sp
->ttis
[i
].tt_isdst
)
822 sp
->ttis
[i
].tt_gmtoff
+ dstoffset
;
823 if (sawdst
&& (oldfix
!= dstfix
))
825 sp
->ttis
[i
].tt_gmtoff
= -dstoffset
;
826 sp
->ttis
[i
].tt_abbrind
= stdlen
+ 1;
833 sp
->ttis
[i
].tt_gmtoff
+ stdoffset
;
834 if (sawstd
&& (oldfix
!= stdfix
))
836 sp
->ttis
[i
].tt_gmtoff
= -stdoffset
;
837 sp
->ttis
[i
].tt_abbrind
= 0;
842 ** Make sure we have both standard and summer time.
844 if (!sawdst
|| !sawstd
)
847 ** Now correct the transition times by shifting
848 ** them by the difference between the real and
849 ** prototype offsets. Note that this difference
850 ** can be different in standard and summer time;
851 ** the prototype probably has a 1-hour difference
852 ** between standard and summer time, but a different
853 ** difference can be specified in TZ.
855 isdst
= FALSE
; /* we start in standard time */
856 for (i
= 0; i
< sp
->timecnt
; ++i
)
858 const struct ttinfo
* ttisp
;
861 ** If summer time is in effect, and the
862 ** transition time was not specified as
863 ** standard time, add the summer time
864 ** offset to the transition time;
865 ** otherwise, add the standard time offset
866 ** to the transition time.
868 ttisp
= &sp
->ttis
[sp
->types
[i
]];
870 (isdst
&& !ttisp
->tt_ttisstd
) ?
872 isdst
= ttisp
->tt_isdst
;
879 sp
->typecnt
= 1; /* only standard time */
881 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
882 sp
->ttis
[0].tt_isdst
= 0;
883 sp
->ttis
[0].tt_abbrind
= 0;
885 sp
->charcnt
= stdlen
+ 1;
887 sp
->charcnt
+= dstlen
+ 1;
888 if (sp
->charcnt
> sizeof sp
->chars
)
891 (void) strncpy(cp
, stdname
, stdlen
);
896 (void) strncpy(cp
, dstname
, dstlen
);
897 *(cp
+ dstlen
) = '\0';
903 gmtload(struct state
* CPP_CONST sp
)
905 if (tzload(GMT
, sp
) != 0)
906 (void) tzparse(GMT
, sp
, TRUE
);
924 lclptr
= (struct state
*) malloc(sizeof *lclptr
);
927 settzname(); /* all we can do */
931 #endif /* defined ALL_STATE */
935 ** User wants it fast rather than right.
937 lclptr
->leapcnt
= 0; /* so, we're off a little */
939 lclptr
->ttis
[0].tt_gmtoff
= 0;
940 lclptr
->ttis
[0].tt_abbrind
= 0;
941 (void) strcpy(lclptr
->chars
, GMT
);
943 else if (tzload(name
, lclptr
) != 0)
944 if (name
[0] == ':' || tzparse(name
, lclptr
, FALSE
) != 0)
956 lclptr
= (struct state
*) malloc(sizeof *lclptr
);
959 settzname(); /* all we can do */
963 #endif /* defined ALL_STATE */
964 if (tzload((char *) NULL
, lclptr
) != 0)
970 ** The easy way to behave "as if no library function calls" localtime
971 ** is to not call it--so we drop its guts into "localsub", which can be
972 ** freely called. (And no, the PANS doesn't require the above behavior--
973 ** but it *is* desirable.)
975 ** The unused offset argument is for the benefit of mktime variants.
980 localsub(const time_t * CPP_CONST timep
, const long offset
, struct tm
* CPP_CONST tmp
)
982 const struct state
* sp
;
983 const struct ttinfo
* ttisp
;
985 const time_t t
= *timep
;
993 gmtsub(timep
, offset
, tmp
);
996 #endif /* defined ALL_STATE */
997 if (sp
->timecnt
== 0 || t
< sp
->ats
[0])
1000 while (sp
->ttis
[i
].tt_isdst
)
1001 if (++i
>= sp
->typecnt
)
1009 for (i
= 1; i
< sp
->timecnt
; ++i
)
1012 i
= sp
->types
[i
- 1];
1014 ttisp
= &sp
->ttis
[i
];
1016 ** To get (wrong) behavior that's compatible with System V Release 2.0
1017 ** you'd replace the statement below with
1018 ** t += ttisp->tt_gmtoff;
1019 ** timesub(&t, 0L, sp, tmp);
1021 timesub(&t
, ttisp
->tt_gmtoff
, sp
, tmp
);
1022 tmp
->tm_isdst
= ttisp
->tt_isdst
;
1023 _tzname
[tmp
->tm_isdst
] = (char *)&sp
->chars
[ttisp
->tt_abbrind
];
1024 tmp
->tm_zone
= (char *)&sp
->chars
[ttisp
->tt_abbrind
];
1028 localtime(const time_t * CPP_CONST timep
)
1030 static struct tm tm
;
1032 localsub(timep
, 0L, &tm
);
1037 ** gmtsub is to gmtime as localsub is to localtime.
1041 gmtsub(const time_t * CPP_CONST timep
, const long offset
, struct tm
* CPP_CONST tmp
)
1047 gmtptr
= (struct state
*) malloc(sizeof *gmtptr
);
1049 #endif /* defined ALL_STATE */
1052 timesub(timep
, offset
, gmtptr
, tmp
);
1054 ** Could get fancy here and deliver something such as
1055 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
1056 ** but this is no time for a treasure hunt.
1059 tmp
->tm_zone
= WILDABBR
;
1066 tmp
->TM_ZONE
= gmtptr
->chars
;
1067 #endif /* defined ALL_STATE */
1069 tmp
->tm_zone
= gmtptr
->chars
;
1070 #endif /* State Farm */
1075 gmtime(const time_t * CPP_CONST timep
)
1077 static struct tm tm
;
1079 gmtsub(timep
, 0L, &tm
);
1084 timesub(const time_t * CPP_CONST timep
, const long offset
, const struct state
* CPP_CONST sp
, struct tm
* CPP_CONST tmp
)
1086 const struct lsinfo
* lp
;
1099 i
= (sp
== NULL
) ? 0 : sp
->leapcnt
;
1100 #endif /* defined ALL_STATE */
1103 #endif /* State Farm */
1107 if (*timep
>= lp
->ls_trans
)
1109 if (*timep
== lp
->ls_trans
)
1110 hit
= ((i
== 0 && lp
->ls_corr
> 0) ||
1111 lp
->ls_corr
> sp
->lsis
[i
- 1].ls_corr
);
1116 days
= *timep
/ SECSPERDAY
;
1117 rem
= *timep
% SECSPERDAY
;
1119 if (*timep
== 0x80000000)
1122 ** A 3B1 muffs the division on the most negative number.
1128 rem
+= (offset
- corr
);
1134 while (rem
>= SECSPERDAY
)
1139 tmp
->tm_hour
= (int) (rem
/ SECSPERHOUR
);
1140 rem
= rem
% SECSPERHOUR
;
1141 tmp
->tm_min
= (int) (rem
/ SECSPERMIN
);
1142 tmp
->tm_sec
= (int) (rem
% SECSPERMIN
);
1145 ** A positive leap second requires a special
1146 ** representation. This uses "... ??:59:60".
1149 tmp
->tm_wday
= (int) ((EPOCH_WDAY
+ days
) % DAYSPERWEEK
);
1150 if (tmp
->tm_wday
< 0)
1151 tmp
->tm_wday
+= DAYSPERWEEK
;
1157 if (days
< (long) year_lengths
[yleap
])
1160 days
= days
- (long) year_lengths
[yleap
];
1166 days
= days
+ (long) year_lengths
[yleap
];
1168 tmp
->tm_year
= y
- TM_YEAR_BASE
;
1169 tmp
->tm_yday
= (int) days
;
1170 ip
= mon_lengths
[yleap
];
1171 for (tmp
->tm_mon
= 0; days
>= (long) ip
[tmp
->tm_mon
]; ++(tmp
->tm_mon
))
1172 days
= days
- (long) ip
[tmp
->tm_mon
];
1173 tmp
->tm_mday
= (int) (days
+ 1);
1175 tmp
->tm_gmtoff
= offset
;
1183 asctime(const struct tm
*timeptr
)
1185 static const char wday_name
[DAYSPERWEEK
][3] = {
1186 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1188 static const char mon_name
[MONSPERYEAR
][3] = {
1189 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1190 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1192 static char result
[26];
1194 (void) sprintf(result
, "%.3s %.3s%3d %02d:%02d:%02d %d\n",
1195 wday_name
[timeptr
->tm_wday
],
1196 mon_name
[timeptr
->tm_mon
],
1197 timeptr
->tm_mday
, timeptr
->tm_hour
,
1198 timeptr
->tm_min
, timeptr
->tm_sec
,
1199 TM_YEAR_BASE
+ timeptr
->tm_year
);
1204 ctime(const time_t * CPP_CONST timep
)
1206 return asctime(localtime(timep
));
1210 ** Adapted from code provided by Robert Elz, who writes:
1211 ** The "best" way to do mktime I think is based on an idea of Bob
1212 ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
1213 ** It does a binary search of the time_t space. Since time_t's are
1214 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
1215 ** would still be very reasonable).
1220 #endif /* !defined WRONG */
1223 normalize(int * CPP_CONST tensptr
, int * CPP_CONST unitsptr
, const int base
)
1225 if (*unitsptr
>= base
)
1227 *tensptr
+= *unitsptr
/ base
;
1230 else if (*unitsptr
< 0)
1236 *tensptr
-= 1 + (-*unitsptr
) / base
;
1237 *unitsptr
= base
- (-*unitsptr
) % base
;
1243 tmcomp(const struct tm
* CPP_CONST atmp
, const struct tm
* CPP_CONST btmp
)
1247 if ((result
= (atmp
->tm_year
- btmp
->tm_year
)) == 0 &&
1248 (result
= (atmp
->tm_mon
- btmp
->tm_mon
)) == 0 &&
1249 (result
= (atmp
->tm_mday
- btmp
->tm_mday
)) == 0 &&
1250 (result
= (atmp
->tm_hour
- btmp
->tm_hour
)) == 0 &&
1251 (result
= (atmp
->tm_min
- btmp
->tm_min
)) == 0)
1252 result
= atmp
->tm_sec
- btmp
->tm_sec
;
1257 time2(struct tm
*tmp
, void (*const funcp
)(const time_t * CPP_CONST
, const long, struct tm
*), const long offset
, int * CPP_CONST okayp
)
1259 const struct state
* sp
;
1266 struct tm yourtm
, mytm
;
1270 if (yourtm
.tm_sec
>= SECSPERMIN
+ 2 || yourtm
.tm_sec
< 0)
1271 normalize(&yourtm
.tm_min
, &yourtm
.tm_sec
, SECSPERMIN
);
1272 normalize(&yourtm
.tm_hour
, &yourtm
.tm_min
, MINSPERHOUR
);
1273 normalize(&yourtm
.tm_mday
, &yourtm
.tm_hour
, HOURSPERDAY
);
1274 normalize(&yourtm
.tm_year
, &yourtm
.tm_mon
, MONSPERYEAR
);
1275 while (yourtm
.tm_mday
<= 0)
1279 year_lengths
[isleap(yourtm
.tm_year
+ TM_YEAR_BASE
)];
1283 i
= mon_lengths
[isleap(yourtm
.tm_year
+
1284 TM_YEAR_BASE
)][yourtm
.tm_mon
];
1285 if (yourtm
.tm_mday
<= i
)
1287 yourtm
.tm_mday
-= i
;
1288 if (++yourtm
.tm_mon
>= MONSPERYEAR
)
1294 saved_seconds
= yourtm
.tm_sec
;
1297 ** Calculate the number of magnitude bits in a time_t
1298 ** (this works regardless of whether time_t is
1299 ** signed or unsigned, though lint complains if unsigned).
1301 for (bits
= 0, t
= 1; t
> 0; ++bits
, t
<<= 1)
1304 ** If time_t is signed, then 0 is the median value,
1305 ** if time_t is unsigned, then 1 << bits is median.
1308 t
= (time_t) ((1 << bits
) - 1);
1309 #else // TODO: FIXME: review which is correct
1310 t
= (time_t) 1 << bits
;
1311 #endif /*_MSVCRT_LIB_*/
1315 (*funcp
)(&t
, offset
, &mytm
);
1316 dir
= tmcomp(&mytm
, &yourtm
);
1324 t
-= (time_t) 1 << bits
;
1325 else t
+= (time_t) 1 << bits
;
1328 if (yourtm
.tm_isdst
< 0 || mytm
.tm_isdst
== yourtm
.tm_isdst
)
1331 ** Right time, wrong type.
1332 ** Hunt for right time, right type.
1333 ** It's okay to guess wrong since the guess
1336 sp
= (const struct state
*)
1337 ((funcp
== localsub
) ? lclptr
: gmtptr
);
1341 #endif /* defined ALL_STATE */
1342 for (i
= 0; i
< sp
->typecnt
; ++i
)
1344 if (sp
->ttis
[i
].tt_isdst
!= yourtm
.tm_isdst
)
1346 for (j
= 0; j
< sp
->typecnt
; ++j
)
1348 if (sp
->ttis
[j
].tt_isdst
== yourtm
.tm_isdst
)
1350 newt
= t
+ sp
->ttis
[j
].tt_gmtoff
-
1351 sp
->ttis
[i
].tt_gmtoff
;
1352 (*funcp
)(&newt
, offset
, &mytm
);
1353 if (tmcomp(&mytm
, &yourtm
) != 0)
1355 if (mytm
.tm_isdst
!= yourtm
.tm_isdst
)
1368 (*funcp
)(&t
, offset
, tmp
);
1374 time1(struct tm
* CPP_CONST tmp
, void (*const funcp
)(const time_t * CPP_CONST
, const long, struct tm
*), const long offset
)
1377 const struct state
* sp
;
1381 if (tmp
->tm_isdst
> 1)
1383 t
= time2(tmp
, funcp
, offset
, &okay
);
1384 if (okay
|| tmp
->tm_isdst
< 0)
1387 ** We're supposed to assume that somebody took a time of one type
1388 ** and did some math on it that yielded a "struct tm" that's bad.
1389 ** We try to divine the type they started from and adjust to the
1392 sp
= (const struct state
*) ((funcp
== localsub
) ? lclptr
: gmtptr
);
1396 #endif /* defined ALL_STATE */
1397 for (samei
= 0; samei
< sp
->typecnt
; ++samei
)
1399 if (sp
->ttis
[samei
].tt_isdst
!= tmp
->tm_isdst
)
1401 for (otheri
= 0; otheri
< sp
->typecnt
; ++otheri
)
1403 if (sp
->ttis
[otheri
].tt_isdst
== tmp
->tm_isdst
)
1405 tmp
->tm_sec
+= sp
->ttis
[otheri
].tt_gmtoff
-
1406 sp
->ttis
[samei
].tt_gmtoff
;
1407 tmp
->tm_isdst
= !tmp
->tm_isdst
;
1408 t
= time2(tmp
, funcp
, offset
, &okay
);
1411 tmp
->tm_sec
-= sp
->ttis
[otheri
].tt_gmtoff
-
1412 sp
->ttis
[samei
].tt_gmtoff
;
1413 tmp
->tm_isdst
= !tmp
->tm_isdst
;
1420 mktime(struct tm
* tmp
)
1422 return time1(tmp
, localsub
, 0L);