]>
git.saurik.com Git - apple/libc.git/blob - gen/ctime.c
0f5753c285b358e39cf757f5397e5db99c32fd41
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1987, 1989, 1993
27 * The Regents of the University of California. All rights reserved.
29 * This code is derived from software contributed to Berkeley by
30 * Arthur David Olson of the National Cancer Institute.
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
64 ** POSIX-style TZ environment variable handling from Guy Harris
70 #include <sys/param.h>
83 #define alloc_size_t size_t
84 #define qsort_size_t size_t
85 #define fread_size_t size_t
86 #define fwrite_size_t size_t
88 #else /* !defined __STDC__ */
92 typedef char * genericptr_t
;
93 typedef unsigned alloc_size_t
;
94 typedef int qsort_size_t
;
95 typedef int fread_size_t
;
96 typedef int fwrite_size_t
;
98 extern char * calloc();
99 extern char * malloc();
100 extern char * realloc();
101 extern char * getenv();
103 #endif /* !defined __STDC__ */
105 extern time_t time();
107 #define ACCESS_MODE O_RDONLY
108 #define OPEN_MODE O_RDONLY
112 ** Someone might make incorrect use of a time zone abbreviation:
113 ** 1. They might reference tzname[0] before calling tzset (explicitly
115 ** 2. They might reference tzname[1] before calling tzset (explicitly
117 ** 3. They might reference tzname[1] after setting to a time zone
118 ** in which Daylight Saving Time is never observed.
119 ** 4. They might reference tzname[0] after setting to a time zone
120 ** in which Standard Time is never observed.
121 ** 5. They might reference tm.TM_ZONE after calling offtime.
122 ** What's best to do in the above cases is open to debate;
123 ** for now, we just set things up so that in any of the five cases
124 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
125 ** string "tzname[0] used before set", and similarly for the other cases.
126 ** And another: initialize tzname[0] to "ERA", with an explanation in the
127 ** manual page of what this "time zone abbreviation" means (doing this so
128 ** that tzname[0] has the "normal" length of three characters).
131 #endif /* !defined WILDABBR */
136 #endif /* !defined TRUE */
138 static const char GMT
[] = "GMT";
140 struct ttinfo
{ /* time type information */
141 long tt_gmtoff
; /* GMT offset in seconds */
142 int tt_isdst
; /* used to set tm_isdst */
143 int tt_abbrind
; /* abbreviation list index */
144 int tt_ttisstd
; /* TRUE if transition is std time */
147 struct lsinfo
{ /* leap second information */
148 time_t ls_trans
; /* transition time */
149 long ls_corr
; /* correction to apply */
157 time_t ats
[TZ_MAX_TIMES
];
158 unsigned char types
[TZ_MAX_TIMES
];
159 struct ttinfo ttis
[TZ_MAX_TYPES
];
160 char chars
[(TZ_MAX_CHARS
+ 1 > sizeof GMT
) ?
161 TZ_MAX_CHARS
+ 1 : sizeof GMT
];
162 struct lsinfo lsis
[TZ_MAX_LEAPS
];
166 int r_type
; /* type of rule--see below */
167 int r_day
; /* day number of rule */
168 int r_week
; /* week number of rule */
169 int r_mon
; /* month number of rule */
170 long r_time
; /* transition time of rule */
173 #define JULIAN_DAY 0 /* Jn - Julian day */
174 #define DAY_OF_YEAR 1 /* n - day of year */
175 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
178 ** Prototypes for static functions.
181 static long detzcode
P((const char * codep
));
182 static const char * getzname
P((const char * strp
));
183 static const char * getnum
P((const char * strp
, int * nump
, int min
,
185 static const char * getsecs
P((const char * strp
, long * secsp
));
186 static const char * getoffset
P((const char * strp
, long * offsetp
));
187 static const char * getrule
P((const char * strp
, struct rule
* rulep
));
188 static void gmtload
P((struct state
* sp
));
189 static void gmtsub
P((const time_t * timep
, long offset
,
191 static void localsub
P((const time_t * timep
, long offset
,
193 static void normalize
P((int * tensptr
, int * unitsptr
, int base
));
194 static void settzname
P((void));
195 static time_t time1
P((struct tm
* tmp
, void (* funcp
)(),
197 static time_t time2
P((struct tm
*tmp
, void (* funcp
)(),
198 long offset
, int * okayp
));
199 static void timesub
P((const time_t * timep
, long offset
,
200 const struct state
* sp
, struct tm
* tmp
));
201 static int tmcomp
P((const struct tm
* atmp
,
202 const struct tm
* btmp
));
203 static time_t transtime
P((time_t janfirst
, int year
,
204 const struct rule
* rulep
, long offset
));
205 static int tzload
P((const char * name
, struct state
* sp
));
206 static int tzparse
P((const char * name
, struct state
* sp
,
210 static struct state
* lclptr
;
211 static struct state
* gmtptr
;
212 #endif /* defined ALL_STATE */
215 static struct state lclmem
;
216 static struct state gmtmem
;
217 #define lclptr (&lclmem)
218 #define gmtptr (&gmtmem)
219 #endif /* State Farm */
221 static int lcl_is_set
;
222 static int gmt_is_set
;
232 #endif /* defined USG_COMPAT */
236 #endif /* defined ALTZONE */
240 const char * const codep
;
242 register long result
;
246 for (i
= 0; i
< 4; ++i
)
247 result
= (result
<< 8) | (codep
[i
] & 0xff);
254 register const struct state
* const sp
= lclptr
;
257 tzname
[0] = WILDABBR
;
258 tzname
[1] = WILDABBR
;
262 #endif /* defined USG_COMPAT */
265 #endif /* defined ALTZONE */
268 tzname
[0] = tzname
[1] = GMT
;
271 #endif /* defined ALL_STATE */
272 for (i
= 0; i
< sp
->typecnt
; ++i
) {
273 register const struct ttinfo
* const ttisp
= &sp
->ttis
[i
];
275 tzname
[ttisp
->tt_isdst
] =
276 (char *) &sp
->chars
[ttisp
->tt_abbrind
];
280 if (i
== 0 || !ttisp
->tt_isdst
)
281 timezone
= -(ttisp
->tt_gmtoff
);
282 #endif /* defined USG_COMPAT */
284 if (i
== 0 || ttisp
->tt_isdst
)
285 altzone
= -(ttisp
->tt_gmtoff
);
286 #endif /* defined ALTZONE */
289 ** And to get the latest zone names into tzname. . .
291 for (i
= 0; i
< sp
->timecnt
; ++i
) {
292 register const struct ttinfo
* const ttisp
=
293 &sp
->ttis
[sp
->types
[i
]];
295 tzname
[ttisp
->tt_isdst
] =
296 (char *) &sp
->chars
[ttisp
->tt_abbrind
];
302 register const char * name
;
303 register struct state
* const sp
;
305 register const char * p
;
309 if (name
== NULL
&& (name
= TZDEFAULT
) == NULL
)
312 char fullname
[FILENAME_MAX
+ 1];
316 if (name
[0] != '/') {
317 if ((p
= TZDIR
) == NULL
)
319 if ((strlen(p
) + strlen(name
) + 1) >= sizeof fullname
)
321 (void) strcpy(fullname
, p
);
322 (void) strcat(fullname
, "/");
323 (void) strcat(fullname
, name
);
326 if ((fid
= open(name
, OPEN_MODE
)) == -1)
330 register const struct tzhead
* tzhp
;
331 char buf
[sizeof *sp
+ sizeof *tzhp
];
334 i
= read(fid
, buf
, sizeof buf
);
335 if (close(fid
) != 0 || i
< sizeof *tzhp
)
337 tzhp
= (struct tzhead
*) buf
;
338 ttisstdcnt
= (int) detzcode(tzhp
->tzh_ttisstdcnt
);
339 sp
->leapcnt
= (int) detzcode(tzhp
->tzh_leapcnt
);
340 sp
->timecnt
= (int) detzcode(tzhp
->tzh_timecnt
);
341 sp
->typecnt
= (int) detzcode(tzhp
->tzh_typecnt
);
342 sp
->charcnt
= (int) detzcode(tzhp
->tzh_charcnt
);
343 if (sp
->leapcnt
< 0 || sp
->leapcnt
> TZ_MAX_LEAPS
||
344 sp
->typecnt
<= 0 || sp
->typecnt
> TZ_MAX_TYPES
||
345 sp
->timecnt
< 0 || sp
->timecnt
> TZ_MAX_TIMES
||
346 sp
->charcnt
< 0 || sp
->charcnt
> TZ_MAX_CHARS
||
347 (ttisstdcnt
!= sp
->typecnt
&& ttisstdcnt
!= 0))
349 if (i
< sizeof *tzhp
+
350 sp
->timecnt
* (4 + sizeof (char)) +
351 sp
->typecnt
* (4 + 2 * sizeof (char)) +
352 sp
->charcnt
* sizeof (char) +
353 sp
->leapcnt
* 2 * 4 +
354 ttisstdcnt
* sizeof (char))
356 p
= buf
+ sizeof *tzhp
;
357 for (i
= 0; i
< sp
->timecnt
; ++i
) {
358 sp
->ats
[i
] = detzcode(p
);
361 for (i
= 0; i
< sp
->timecnt
; ++i
) {
362 sp
->types
[i
] = (unsigned char) *p
++;
363 if (sp
->types
[i
] >= sp
->typecnt
)
366 for (i
= 0; i
< sp
->typecnt
; ++i
) {
367 register struct ttinfo
* ttisp
;
369 ttisp
= &sp
->ttis
[i
];
370 ttisp
->tt_gmtoff
= detzcode(p
);
372 ttisp
->tt_isdst
= (unsigned char) *p
++;
373 if (ttisp
->tt_isdst
!= 0 && ttisp
->tt_isdst
!= 1)
375 ttisp
->tt_abbrind
= (unsigned char) *p
++;
376 if (ttisp
->tt_abbrind
< 0 ||
377 ttisp
->tt_abbrind
> sp
->charcnt
)
380 for (i
= 0; i
< sp
->charcnt
; ++i
)
382 sp
->chars
[i
] = '\0'; /* ensure '\0' at end */
383 for (i
= 0; i
< sp
->leapcnt
; ++i
) {
384 register struct lsinfo
* lsisp
;
386 lsisp
= &sp
->lsis
[i
];
387 lsisp
->ls_trans
= detzcode(p
);
389 lsisp
->ls_corr
= detzcode(p
);
392 for (i
= 0; i
< sp
->typecnt
; ++i
) {
393 register struct ttinfo
* ttisp
;
395 ttisp
= &sp
->ttis
[i
];
397 ttisp
->tt_ttisstd
= FALSE
;
399 ttisp
->tt_ttisstd
= *p
++;
400 if (ttisp
->tt_ttisstd
!= TRUE
&&
401 ttisp
->tt_ttisstd
!= FALSE
)
409 static const int mon_lengths
[2][MONSPERYEAR
] = {
410 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
411 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
414 static const int year_lengths
[2] = {
415 DAYSPERNYEAR
, DAYSPERLYEAR
419 ** Given a pointer into a time zone string, scan until a character that is not
420 ** a valid character in a zone name is found. Return a pointer to that
426 register const char * strp
;
430 while ((c
= *strp
) != '\0' && !isdigit(c
) && c
!= ',' && c
!= '-' &&
437 ** Given a pointer into a time zone string, extract a number from that string.
438 ** Check that the number is within a specified range; if it is not, return
440 ** Otherwise, return a pointer to the first character not part of the number.
444 getnum(strp
, nump
, min
, max
)
445 register const char * strp
;
453 if (strp
== NULL
|| !isdigit(*strp
))
456 while ((c
= *strp
) != '\0' && isdigit(c
)) {
457 num
= num
* 10 + (c
- '0');
459 return NULL
; /* illegal value */
463 return NULL
; /* illegal value */
469 ** Given a pointer into a time zone string, extract a number of seconds,
470 ** in hh[:mm[:ss]] form, from the string.
471 ** If any error occurs, return NULL.
472 ** Otherwise, return a pointer to the first character not part of the number
478 register const char * strp
;
483 strp
= getnum(strp
, &num
, 0, HOURSPERDAY
);
486 *secsp
= num
* SECSPERHOUR
;
489 strp
= getnum(strp
, &num
, 0, MINSPERHOUR
- 1);
492 *secsp
+= num
* SECSPERMIN
;
495 strp
= getnum(strp
, &num
, 0, SECSPERMIN
- 1);
505 ** Given a pointer into a time zone string, extract an offset, in
506 ** [+-]hh[:mm[:ss]] form, from the string.
507 ** If any error occurs, return NULL.
508 ** Otherwise, return a pointer to the first character not part of the time.
512 getoffset(strp
, offsetp
)
513 register const char * strp
;
514 long * const offsetp
;
521 } else if (isdigit(*strp
) || *strp
++ == '+')
523 else return NULL
; /* illegal offset */
524 strp
= getsecs(strp
, offsetp
);
526 return NULL
; /* illegal time */
528 *offsetp
= -*offsetp
;
533 ** Given a pointer into a time zone string, extract a rule in the form
534 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
535 ** If a valid rule is not found, return NULL.
536 ** Otherwise, return a pointer to the first character not part of the rule.
542 register struct rule
* const rulep
;
548 rulep
->r_type
= JULIAN_DAY
;
550 strp
= getnum(strp
, &rulep
->r_day
, 1, DAYSPERNYEAR
);
551 } else if (*strp
== 'M') {
555 rulep
->r_type
= MONTH_NTH_DAY_OF_WEEK
;
557 strp
= getnum(strp
, &rulep
->r_mon
, 1, MONSPERYEAR
);
562 strp
= getnum(strp
, &rulep
->r_week
, 1, 5);
567 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERWEEK
- 1);
568 } else if (isdigit(*strp
)) {
572 rulep
->r_type
= DAY_OF_YEAR
;
573 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERLYEAR
- 1);
574 } else return NULL
; /* invalid format */
582 strp
= getsecs(strp
, &rulep
->r_time
);
583 } else rulep
->r_time
= 2 * SECSPERHOUR
; /* default = 2:00:00 */
588 ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
589 ** year, a rule, and the offset from GMT at the time that rule takes effect,
590 ** calculate the Epoch-relative time that rule takes effect.
594 transtime(janfirst
, year
, rulep
, offset
)
595 const time_t janfirst
;
597 register const struct rule
* const rulep
;
600 register int leapyear
;
601 register time_t value
;
603 int d
, m1
, yy0
, yy1
, yy2
, dow
;
605 leapyear
= isleap(year
);
606 switch (rulep
->r_type
) {
610 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
612 ** In non-leap years, or if the day number is 59 or less, just
613 ** add SECSPERDAY times the day number-1 to the time of
614 ** January 1, midnight, to get the day.
616 value
= janfirst
+ (rulep
->r_day
- 1) * SECSPERDAY
;
617 if (leapyear
&& rulep
->r_day
>= 60)
624 ** Just add SECSPERDAY times the day number to the time of
625 ** January 1, midnight, to get the day.
627 value
= janfirst
+ rulep
->r_day
* SECSPERDAY
;
630 case MONTH_NTH_DAY_OF_WEEK
:
632 ** Mm.n.d - nth "dth day" of month m.
635 for (i
= 0; i
< rulep
->r_mon
- 1; ++i
)
636 value
+= mon_lengths
[leapyear
][i
] * SECSPERDAY
;
639 ** Use Zeller's Congruence to get day-of-week of first day of
642 m1
= (rulep
->r_mon
+ 9) % 12 + 1;
643 yy0
= (rulep
->r_mon
<= 2) ? (year
- 1) : year
;
646 dow
= ((26 * m1
- 2) / 10 +
647 1 + yy2
+ yy2
/ 4 + yy1
/ 4 - 2 * yy1
) % 7;
652 ** "dow" is the day-of-week of the first day of the month. Get
653 ** the day-of-month (zero-origin) of the first "dow" day of the
656 d
= rulep
->r_day
- dow
;
659 for (i
= 1; i
< rulep
->r_week
; ++i
) {
660 if (d
+ DAYSPERWEEK
>=
661 mon_lengths
[leapyear
][rulep
->r_mon
- 1])
667 ** "d" is the day-of-month (zero-origin) of the day we want.
669 value
+= d
* SECSPERDAY
;
674 ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
675 ** question. To get the Epoch-relative time of the specified local
676 ** time on that day, add the transition time and the current offset
679 return value
+ rulep
->r_time
+ offset
;
683 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
688 tzparse(name
, sp
, lastditch
)
690 register struct state
* const sp
;
693 const char * stdname
;
694 const char * dstname
;
699 register time_t * atp
;
700 register unsigned char * typep
;
702 register int load_result
;
706 stdlen
= strlen(name
); /* length of standard zone name */
708 if (stdlen
>= sizeof sp
->chars
)
709 stdlen
= (sizeof sp
->chars
) - 1;
711 name
= getzname(name
);
712 stdlen
= name
- stdname
;
719 name
= getoffset(name
, &stdoffset
);
723 load_result
= tzload(TZDEFRULES
, sp
);
724 if (load_result
!= 0)
725 sp
->leapcnt
= 0; /* so, we're off a little */
728 name
= getzname(name
);
729 dstlen
= name
- dstname
; /* length of DST zone name */
732 if (*name
!= '\0' && *name
!= ',' && *name
!= ';') {
733 name
= getoffset(name
, &dstoffset
);
736 } else dstoffset
= stdoffset
- SECSPERHOUR
;
737 if (*name
== ',' || *name
== ';') {
741 register time_t janfirst
;
746 if ((name
= getrule(name
, &start
)) == NULL
)
750 if ((name
= getrule(name
, &end
)) == NULL
)
754 sp
->typecnt
= 2; /* standard time and DST */
756 ** Two transitions per year, from EPOCH_YEAR to 2037.
758 sp
->timecnt
= 2 * (2037 - EPOCH_YEAR
+ 1);
759 if (sp
->timecnt
> TZ_MAX_TIMES
)
761 sp
->ttis
[0].tt_gmtoff
= -dstoffset
;
762 sp
->ttis
[0].tt_isdst
= 1;
763 sp
->ttis
[0].tt_abbrind
= stdlen
+ 1;
764 sp
->ttis
[1].tt_gmtoff
= -stdoffset
;
765 sp
->ttis
[1].tt_isdst
= 0;
766 sp
->ttis
[1].tt_abbrind
= 0;
770 for (year
= EPOCH_YEAR
; year
<= 2037; ++year
) {
771 starttime
= transtime(janfirst
, year
, &start
,
773 endtime
= transtime(janfirst
, year
, &end
,
775 if (starttime
> endtime
) {
777 *typep
++ = 1; /* DST ends */
779 *typep
++ = 0; /* DST begins */
782 *typep
++ = 0; /* DST begins */
784 *typep
++ = 1; /* DST ends */
787 year_lengths
[isleap(year
)] * SECSPERDAY
;
800 if (load_result
!= 0)
803 ** Compute the difference between the real and
804 ** prototype standard and summer time offsets
805 ** from GMT, and put the real standard and summer
806 ** time offsets into the rules in place of the
807 ** prototype offsets.
813 for (i
= 0; i
< sp
->typecnt
; ++i
) {
814 if (sp
->ttis
[i
].tt_isdst
) {
817 sp
->ttis
[i
].tt_gmtoff
+ dstoffset
;
818 if (sawdst
&& (oldfix
!= dstfix
))
820 sp
->ttis
[i
].tt_gmtoff
= -dstoffset
;
821 sp
->ttis
[i
].tt_abbrind
= stdlen
+ 1;
826 sp
->ttis
[i
].tt_gmtoff
+ stdoffset
;
827 if (sawstd
&& (oldfix
!= stdfix
))
829 sp
->ttis
[i
].tt_gmtoff
= -stdoffset
;
830 sp
->ttis
[i
].tt_abbrind
= 0;
835 ** Make sure we have both standard and summer time.
837 if (!sawdst
|| !sawstd
)
840 ** Now correct the transition times by shifting
841 ** them by the difference between the real and
842 ** prototype offsets. Note that this difference
843 ** can be different in standard and summer time;
844 ** the prototype probably has a 1-hour difference
845 ** between standard and summer time, but a different
846 ** difference can be specified in TZ.
848 isdst
= FALSE
; /* we start in standard time */
849 for (i
= 0; i
< sp
->timecnt
; ++i
) {
850 register const struct ttinfo
* ttisp
;
853 ** If summer time is in effect, and the
854 ** transition time was not specified as
855 ** standard time, add the summer time
856 ** offset to the transition time;
857 ** otherwise, add the standard time offset
858 ** to the transition time.
860 ttisp
= &sp
->ttis
[sp
->types
[i
]];
862 (isdst
&& !ttisp
->tt_ttisstd
) ?
864 isdst
= ttisp
->tt_isdst
;
869 sp
->typecnt
= 1; /* only standard time */
871 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
872 sp
->ttis
[0].tt_isdst
= 0;
873 sp
->ttis
[0].tt_abbrind
= 0;
875 sp
->charcnt
= stdlen
+ 1;
877 sp
->charcnt
+= dstlen
+ 1;
878 if (sp
->charcnt
> sizeof sp
->chars
)
881 (void) strncpy(cp
, stdname
, stdlen
);
885 (void) strncpy(cp
, dstname
, dstlen
);
886 *(cp
+ dstlen
) = '\0';
893 struct state
* const sp
;
895 if (tzload(GMT
, sp
) != 0)
896 (void) tzparse(GMT
, sp
, TRUE
);
902 register const char * name
;
912 if (lclptr
== NULL
) {
913 lclptr
= (struct state
*) malloc(sizeof *lclptr
);
914 if (lclptr
== NULL
) {
915 settzname(); /* all we can do */
919 #endif /* defined ALL_STATE */
922 ** User wants it fast rather than right.
924 lclptr
->leapcnt
= 0; /* so, we're off a little */
926 lclptr
->ttis
[0].tt_gmtoff
= 0;
927 lclptr
->ttis
[0].tt_abbrind
= 0;
928 (void) strcpy(lclptr
->chars
, GMT
);
929 } else if (tzload(name
, lclptr
) != 0)
930 if (name
[0] == ':' || tzparse(name
, lclptr
, FALSE
) != 0)
931 (void) gmtload(lclptr
);
940 if (lclptr
== NULL
) {
941 lclptr
= (struct state
*) malloc(sizeof *lclptr
);
942 if (lclptr
== NULL
) {
943 settzname(); /* all we can do */
947 #endif /* defined ALL_STATE */
948 if (tzload((char *) NULL
, lclptr
) != 0)
954 ** The easy way to behave "as if no library function calls" localtime
955 ** is to not call it--so we drop its guts into "localsub", which can be
956 ** freely called. (And no, the PANS doesn't require the above behavior--
957 ** but it *is* desirable.)
959 ** The unused offset argument is for the benefit of mktime variants.
964 localsub(timep
, offset
, tmp
)
965 const time_t * const timep
;
967 struct tm
* const tmp
;
969 register struct state
* sp
;
970 register const struct ttinfo
* ttisp
;
972 const time_t t
= *timep
;
979 gmtsub(timep
, offset
, tmp
);
982 #endif /* defined ALL_STATE */
983 if (sp
->timecnt
== 0 || t
< sp
->ats
[0]) {
985 while (sp
->ttis
[i
].tt_isdst
)
986 if (++i
>= sp
->typecnt
) {
991 for (i
= 1; i
< sp
->timecnt
; ++i
)
994 i
= sp
->types
[i
- 1];
996 ttisp
= &sp
->ttis
[i
];
998 ** To get (wrong) behavior that's compatible with System V Release 2.0
999 ** you'd replace the statement below with
1000 ** t += ttisp->tt_gmtoff;
1001 ** timesub(&t, 0L, sp, tmp);
1003 timesub(&t
, ttisp
->tt_gmtoff
, sp
, tmp
);
1004 tmp
->tm_isdst
= ttisp
->tt_isdst
;
1005 tzname
[tmp
->tm_isdst
] = (char *) &sp
->chars
[ttisp
->tt_abbrind
];
1006 tmp
->tm_zone
= &sp
->chars
[ttisp
->tt_abbrind
];
1011 const time_t * const timep
;
1013 static struct tm tm
;
1015 localsub(timep
, 0L, &tm
);
1020 ** gmtsub is to gmtime as localsub is to localtime.
1024 gmtsub(timep
, offset
, tmp
)
1025 const time_t * const timep
;
1027 struct tm
* const tmp
;
1032 gmtptr
= (struct state
*) malloc(sizeof *gmtptr
);
1034 #endif /* defined ALL_STATE */
1037 timesub(timep
, offset
, gmtptr
, tmp
);
1039 ** Could get fancy here and deliver something such as
1040 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
1041 ** but this is no time for a treasure hunt.
1044 tmp
->tm_zone
= WILDABBR
;
1049 else tmp
->TM_ZONE
= gmtptr
->chars
;
1050 #endif /* defined ALL_STATE */
1052 tmp
->tm_zone
= gmtptr
->chars
;
1053 #endif /* State Farm */
1059 const time_t * const timep
;
1061 static struct tm tm
;
1063 gmtsub(timep
, 0L, &tm
);
1068 timesub(timep
, offset
, sp
, tmp
)
1069 const time_t * const timep
;
1071 register const struct state
* const sp
;
1072 register struct tm
* const tmp
;
1074 register const struct lsinfo
* lp
;
1079 register const int * ip
;
1087 i
= (sp
== NULL
) ? 0 : sp
->leapcnt
;
1088 #endif /* defined ALL_STATE */
1091 #endif /* State Farm */
1094 if (*timep
>= lp
->ls_trans
) {
1095 if (*timep
== lp
->ls_trans
)
1096 hit
= ((i
== 0 && lp
->ls_corr
> 0) ||
1097 lp
->ls_corr
> sp
->lsis
[i
- 1].ls_corr
);
1102 days
= *timep
/ SECSPERDAY
;
1103 rem
= *timep
% SECSPERDAY
;
1105 if (*timep
== 0x80000000) {
1107 ** A 3B1 muffs the division on the most negative number.
1113 rem
+= (offset
- corr
);
1118 while (rem
>= SECSPERDAY
) {
1122 tmp
->tm_hour
= (int) (rem
/ SECSPERHOUR
);
1123 rem
= rem
% SECSPERHOUR
;
1124 tmp
->tm_min
= (int) (rem
/ SECSPERMIN
);
1125 tmp
->tm_sec
= (int) (rem
% SECSPERMIN
);
1128 ** A positive leap second requires a special
1129 ** representation. This uses "... ??:59:60".
1132 tmp
->tm_wday
= (int) ((EPOCH_WDAY
+ days
) % DAYSPERWEEK
);
1133 if (tmp
->tm_wday
< 0)
1134 tmp
->tm_wday
+= DAYSPERWEEK
;
1139 if (days
< (long) year_lengths
[yleap
])
1142 days
= days
- (long) year_lengths
[yleap
];
1147 days
= days
+ (long) year_lengths
[yleap
];
1149 tmp
->tm_year
= y
- TM_YEAR_BASE
;
1150 tmp
->tm_yday
= (int) days
;
1151 ip
= mon_lengths
[yleap
];
1152 for (tmp
->tm_mon
= 0; days
>= (long) ip
[tmp
->tm_mon
]; ++(tmp
->tm_mon
))
1153 days
= days
- (long) ip
[tmp
->tm_mon
];
1154 tmp
->tm_mday
= (int) (days
+ 1);
1156 tmp
->tm_gmtoff
= offset
;
1165 register const struct tm
* timeptr
;
1167 static const char wday_name
[DAYSPERWEEK
][3] = {
1168 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1170 static const char mon_name
[MONSPERYEAR
][3] = {
1171 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1172 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1174 static char result
[26];
1176 (void) sprintf(result
, "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n",
1177 wday_name
[timeptr
->tm_wday
],
1178 mon_name
[timeptr
->tm_mon
],
1179 timeptr
->tm_mday
, timeptr
->tm_hour
,
1180 timeptr
->tm_min
, timeptr
->tm_sec
,
1181 TM_YEAR_BASE
+ timeptr
->tm_year
);
1187 const time_t * const timep
;
1189 return asctime(localtime(timep
));
1193 ** Adapted from code provided by Robert Elz, who writes:
1194 ** The "best" way to do mktime I think is based on an idea of Bob
1195 ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
1196 ** It does a binary search of the time_t space. Since time_t's are
1197 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
1198 ** would still be very reasonable).
1203 #endif /* !defined WRONG */
1206 normalize(tensptr
, unitsptr
, base
)
1207 int * const tensptr
;
1208 int * const unitsptr
;
1211 if (*unitsptr
>= base
) {
1212 *tensptr
+= *unitsptr
/ base
;
1214 } else if (*unitsptr
< 0) {
1215 *tensptr
-= 1 + (-(*unitsptr
+ 1)) / base
;
1216 *unitsptr
= base
- 1 - (-(*unitsptr
+ 1)) % base
;
1222 register const struct tm
* const atmp
;
1223 register const struct tm
* const btmp
;
1225 register int result
;
1227 if ((result
= (atmp
->tm_year
- btmp
->tm_year
)) == 0 &&
1228 (result
= (atmp
->tm_mon
- btmp
->tm_mon
)) == 0 &&
1229 (result
= (atmp
->tm_mday
- btmp
->tm_mday
)) == 0 &&
1230 (result
= (atmp
->tm_hour
- btmp
->tm_hour
)) == 0 &&
1231 (result
= (atmp
->tm_min
- btmp
->tm_min
)) == 0)
1232 result
= atmp
->tm_sec
- btmp
->tm_sec
;
1237 time2(tmp
, funcp
, offset
, okayp
)
1238 struct tm
* const tmp
;
1239 void (* const funcp
)();
1243 register const struct state
* sp
;
1247 register int saved_seconds
;
1250 struct tm yourtm
, mytm
;
1254 if (yourtm
.tm_sec
>= SECSPERMIN
+ 2 || yourtm
.tm_sec
< 0)
1255 normalize(&yourtm
.tm_min
, &yourtm
.tm_sec
, SECSPERMIN
);
1256 normalize(&yourtm
.tm_hour
, &yourtm
.tm_min
, MINSPERHOUR
);
1257 normalize(&yourtm
.tm_mday
, &yourtm
.tm_hour
, HOURSPERDAY
);
1258 normalize(&yourtm
.tm_year
, &yourtm
.tm_mon
, MONSPERYEAR
);
1259 while (yourtm
.tm_mday
<= 0) {
1262 year_lengths
[isleap(yourtm
.tm_year
+ TM_YEAR_BASE
)];
1264 while (yourtm
.tm_mday
> DAYSPERLYEAR
) {
1266 year_lengths
[isleap(yourtm
.tm_year
+ TM_YEAR_BASE
)];
1270 i
= mon_lengths
[isleap(yourtm
.tm_year
+
1271 TM_YEAR_BASE
)][yourtm
.tm_mon
];
1272 if (yourtm
.tm_mday
<= i
)
1274 yourtm
.tm_mday
-= i
;
1275 if (++yourtm
.tm_mon
>= MONSPERYEAR
) {
1280 saved_seconds
= yourtm
.tm_sec
;
1283 ** Calculate the number of magnitude bits in a time_t
1284 ** (this works regardless of whether time_t is
1285 ** signed or unsigned, though lint complains if unsigned).
1287 for (bits
= 0, t
= 1; t
> 0; ++bits
, t
<<= 1)
1290 ** If time_t is signed, then 0 is the median value,
1291 ** if time_t is unsigned, then 1 << bits is median.
1293 t
= (t
< 0) ? 0 : ((time_t) 1 << bits
);
1295 (*funcp
)(&t
, offset
, &mytm
);
1296 dir
= tmcomp(&mytm
, &yourtm
);
1303 t
-= (time_t) 1 << bits
;
1304 else t
+= (time_t) 1 << bits
;
1307 if (yourtm
.tm_isdst
< 0 || mytm
.tm_isdst
== yourtm
.tm_isdst
)
1310 ** Right time, wrong type.
1311 ** Hunt for right time, right type.
1312 ** It's okay to guess wrong since the guess
1315 sp
= (const struct state
*)
1316 ((funcp
== localsub
) ? lclptr
: gmtptr
);
1320 #endif /* defined ALL_STATE */
1321 for (i
= 0; i
< sp
->typecnt
; ++i
) {
1322 if (sp
->ttis
[i
].tt_isdst
!= yourtm
.tm_isdst
)
1324 for (j
= 0; j
< sp
->typecnt
; ++j
) {
1325 if (sp
->ttis
[j
].tt_isdst
== yourtm
.tm_isdst
)
1327 newt
= t
+ sp
->ttis
[j
].tt_gmtoff
-
1328 sp
->ttis
[i
].tt_gmtoff
;
1329 (*funcp
)(&newt
, offset
, &mytm
);
1330 if (tmcomp(&mytm
, &yourtm
) != 0)
1332 if (mytm
.tm_isdst
!= yourtm
.tm_isdst
)
1345 (*funcp
)(&t
, offset
, tmp
);
1351 time1(tmp
, funcp
, offset
)
1352 struct tm
* const tmp
;
1353 void (* const funcp
)();
1357 register const struct state
* sp
;
1358 register int samei
, otheri
;
1361 if (tmp
->tm_isdst
> 1)
1363 t
= time2(tmp
, funcp
, offset
, &okay
);
1364 if (okay
|| tmp
->tm_isdst
< 0)
1367 ** We're supposed to assume that somebody took a time of one type
1368 ** and did some math on it that yielded a "struct tm" that's bad.
1369 ** We try to divine the type they started from and adjust to the
1372 sp
= (const struct state
*) ((funcp
== localsub
) ? lclptr
: gmtptr
);
1376 #endif /* defined ALL_STATE */
1377 for (samei
= 0; samei
< sp
->typecnt
; ++samei
) {
1378 if (sp
->ttis
[samei
].tt_isdst
!= tmp
->tm_isdst
)
1380 for (otheri
= 0; otheri
< sp
->typecnt
; ++otheri
) {
1381 if (sp
->ttis
[otheri
].tt_isdst
== tmp
->tm_isdst
)
1383 tmp
->tm_sec
+= sp
->ttis
[otheri
].tt_gmtoff
-
1384 sp
->ttis
[samei
].tt_gmtoff
;
1385 tmp
->tm_isdst
= !tmp
->tm_isdst
;
1386 t
= time2(tmp
, funcp
, offset
, &okay
);
1389 tmp
->tm_sec
-= sp
->ttis
[otheri
].tt_gmtoff
-
1390 sp
->ttis
[samei
].tt_gmtoff
;
1391 tmp
->tm_isdst
= !tmp
->tm_isdst
;
1399 struct tm
* const tmp
;
1401 return time1(tmp
, localsub
, 0L);