]>
git.saurik.com Git - apple/libc.git/blob - gen/ctime.c
d8b06566bf0b447fa263ff1d701c0a119ef1e5ee
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1987, 1989, 1993
24 * The Regents of the University of California. All rights reserved.
26 * This code is derived from software contributed to Berkeley by
27 * Arthur David Olson of the National Cancer Institute.
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
61 ** POSIX-style TZ environment variable handling from Guy Harris
67 #include <sys/param.h>
80 #define alloc_size_t size_t
81 #define qsort_size_t size_t
82 #define fread_size_t size_t
83 #define fwrite_size_t size_t
85 #else /* !defined __STDC__ */
89 typedef char * genericptr_t
;
90 typedef unsigned alloc_size_t
;
91 typedef int qsort_size_t
;
92 typedef int fread_size_t
;
93 typedef int fwrite_size_t
;
95 extern char * calloc();
96 extern char * malloc();
97 extern char * realloc();
98 extern char * getenv();
100 #endif /* !defined __STDC__ */
102 extern time_t time();
104 #define ACCESS_MODE O_RDONLY
105 #define OPEN_MODE O_RDONLY
109 ** Someone might make incorrect use of a time zone abbreviation:
110 ** 1. They might reference tzname[0] before calling tzset (explicitly
112 ** 2. They might reference tzname[1] before calling tzset (explicitly
114 ** 3. They might reference tzname[1] after setting to a time zone
115 ** in which Daylight Saving Time is never observed.
116 ** 4. They might reference tzname[0] after setting to a time zone
117 ** in which Standard Time is never observed.
118 ** 5. They might reference tm.TM_ZONE after calling offtime.
119 ** What's best to do in the above cases is open to debate;
120 ** for now, we just set things up so that in any of the five cases
121 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
122 ** string "tzname[0] used before set", and similarly for the other cases.
123 ** And another: initialize tzname[0] to "ERA", with an explanation in the
124 ** manual page of what this "time zone abbreviation" means (doing this so
125 ** that tzname[0] has the "normal" length of three characters).
128 #endif /* !defined WILDABBR */
133 #endif /* !defined TRUE */
135 static const char GMT
[] = "GMT";
137 struct ttinfo
{ /* time type information */
138 long tt_gmtoff
; /* GMT offset in seconds */
139 int tt_isdst
; /* used to set tm_isdst */
140 int tt_abbrind
; /* abbreviation list index */
141 int tt_ttisstd
; /* TRUE if transition is std time */
144 struct lsinfo
{ /* leap second information */
145 time_t ls_trans
; /* transition time */
146 long ls_corr
; /* correction to apply */
154 time_t ats
[TZ_MAX_TIMES
];
155 unsigned char types
[TZ_MAX_TIMES
];
156 struct ttinfo ttis
[TZ_MAX_TYPES
];
157 char chars
[(TZ_MAX_CHARS
+ 1 > sizeof GMT
) ?
158 TZ_MAX_CHARS
+ 1 : sizeof GMT
];
159 struct lsinfo lsis
[TZ_MAX_LEAPS
];
163 int r_type
; /* type of rule--see below */
164 int r_day
; /* day number of rule */
165 int r_week
; /* week number of rule */
166 int r_mon
; /* month number of rule */
167 long r_time
; /* transition time of rule */
170 #define JULIAN_DAY 0 /* Jn - Julian day */
171 #define DAY_OF_YEAR 1 /* n - day of year */
172 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
175 ** Prototypes for static functions.
178 static long detzcode
P((const char * codep
));
179 static const char * getzname
P((const char * strp
));
180 static const char * getnum
P((const char * strp
, int * nump
, int min
,
182 static const char * getsecs
P((const char * strp
, long * secsp
));
183 static const char * getoffset
P((const char * strp
, long * offsetp
));
184 static const char * getrule
P((const char * strp
, struct rule
* rulep
));
185 static void gmtload
P((struct state
* sp
));
186 static void gmtsub
P((const time_t * timep
, long offset
,
188 static void localsub
P((const time_t * timep
, long offset
,
190 static void normalize
P((int * tensptr
, int * unitsptr
, int base
));
191 static void settzname
P((void));
192 static time_t time1
P((struct tm
* tmp
, void (* funcp
)(),
194 static time_t time2
P((struct tm
*tmp
, void (* funcp
)(),
195 long offset
, int * okayp
));
196 static void timesub
P((const time_t * timep
, long offset
,
197 const struct state
* sp
, struct tm
* tmp
));
198 static int tmcomp
P((const struct tm
* atmp
,
199 const struct tm
* btmp
));
200 static time_t transtime
P((time_t janfirst
, int year
,
201 const struct rule
* rulep
, long offset
));
202 static int tzload
P((const char * name
, struct state
* sp
));
203 static int tzparse
P((const char * name
, struct state
* sp
,
207 static struct state
* lclptr
;
208 static struct state
* gmtptr
;
209 #endif /* defined ALL_STATE */
212 static struct state lclmem
;
213 static struct state gmtmem
;
214 #define lclptr (&lclmem)
215 #define gmtptr (&gmtmem)
216 #endif /* State Farm */
218 static int lcl_is_set
;
219 static int gmt_is_set
;
229 #endif /* defined USG_COMPAT */
233 #endif /* defined ALTZONE */
237 const char * const codep
;
239 register long result
;
243 for (i
= 0; i
< 4; ++i
)
244 result
= (result
<< 8) | (codep
[i
] & 0xff);
251 register const struct state
* const sp
= lclptr
;
254 tzname
[0] = WILDABBR
;
255 tzname
[1] = WILDABBR
;
259 #endif /* defined USG_COMPAT */
262 #endif /* defined ALTZONE */
265 tzname
[0] = tzname
[1] = GMT
;
268 #endif /* defined ALL_STATE */
269 for (i
= 0; i
< sp
->typecnt
; ++i
) {
270 register const struct ttinfo
* const ttisp
= &sp
->ttis
[i
];
272 tzname
[ttisp
->tt_isdst
] =
273 (char *) &sp
->chars
[ttisp
->tt_abbrind
];
277 if (i
== 0 || !ttisp
->tt_isdst
)
278 timezone
= -(ttisp
->tt_gmtoff
);
279 #endif /* defined USG_COMPAT */
281 if (i
== 0 || ttisp
->tt_isdst
)
282 altzone
= -(ttisp
->tt_gmtoff
);
283 #endif /* defined ALTZONE */
286 ** And to get the latest zone names into tzname. . .
288 for (i
= 0; i
< sp
->timecnt
; ++i
) {
289 register const struct ttinfo
* const ttisp
=
290 &sp
->ttis
[sp
->types
[i
]];
292 tzname
[ttisp
->tt_isdst
] =
293 (char *) &sp
->chars
[ttisp
->tt_abbrind
];
299 register const char * name
;
300 register struct state
* const sp
;
302 register const char * p
;
306 if (name
== NULL
&& (name
= TZDEFAULT
) == NULL
)
309 char fullname
[FILENAME_MAX
+ 1];
313 if (name
[0] != '/') {
314 if ((p
= TZDIR
) == NULL
)
316 if ((strlen(p
) + strlen(name
) + 1) >= sizeof fullname
)
318 (void) strcpy(fullname
, p
);
319 (void) strcat(fullname
, "/");
320 (void) strcat(fullname
, name
);
323 if ((fid
= open(name
, OPEN_MODE
)) == -1)
327 register const struct tzhead
* tzhp
;
328 char buf
[sizeof *sp
+ sizeof *tzhp
];
331 i
= read(fid
, buf
, sizeof buf
);
332 if (close(fid
) != 0 || i
< sizeof *tzhp
)
334 tzhp
= (struct tzhead
*) buf
;
335 ttisstdcnt
= (int) detzcode(tzhp
->tzh_ttisstdcnt
);
336 sp
->leapcnt
= (int) detzcode(tzhp
->tzh_leapcnt
);
337 sp
->timecnt
= (int) detzcode(tzhp
->tzh_timecnt
);
338 sp
->typecnt
= (int) detzcode(tzhp
->tzh_typecnt
);
339 sp
->charcnt
= (int) detzcode(tzhp
->tzh_charcnt
);
340 if (sp
->leapcnt
< 0 || sp
->leapcnt
> TZ_MAX_LEAPS
||
341 sp
->typecnt
<= 0 || sp
->typecnt
> TZ_MAX_TYPES
||
342 sp
->timecnt
< 0 || sp
->timecnt
> TZ_MAX_TIMES
||
343 sp
->charcnt
< 0 || sp
->charcnt
> TZ_MAX_CHARS
||
344 (ttisstdcnt
!= sp
->typecnt
&& ttisstdcnt
!= 0))
346 if (i
< sizeof *tzhp
+
347 sp
->timecnt
* (4 + sizeof (char)) +
348 sp
->typecnt
* (4 + 2 * sizeof (char)) +
349 sp
->charcnt
* sizeof (char) +
350 sp
->leapcnt
* 2 * 4 +
351 ttisstdcnt
* sizeof (char))
353 p
= buf
+ sizeof *tzhp
;
354 for (i
= 0; i
< sp
->timecnt
; ++i
) {
355 sp
->ats
[i
] = detzcode(p
);
358 for (i
= 0; i
< sp
->timecnt
; ++i
) {
359 sp
->types
[i
] = (unsigned char) *p
++;
360 if (sp
->types
[i
] >= sp
->typecnt
)
363 for (i
= 0; i
< sp
->typecnt
; ++i
) {
364 register struct ttinfo
* ttisp
;
366 ttisp
= &sp
->ttis
[i
];
367 ttisp
->tt_gmtoff
= detzcode(p
);
369 ttisp
->tt_isdst
= (unsigned char) *p
++;
370 if (ttisp
->tt_isdst
!= 0 && ttisp
->tt_isdst
!= 1)
372 ttisp
->tt_abbrind
= (unsigned char) *p
++;
373 if (ttisp
->tt_abbrind
< 0 ||
374 ttisp
->tt_abbrind
> sp
->charcnt
)
377 for (i
= 0; i
< sp
->charcnt
; ++i
)
379 sp
->chars
[i
] = '\0'; /* ensure '\0' at end */
380 for (i
= 0; i
< sp
->leapcnt
; ++i
) {
381 register struct lsinfo
* lsisp
;
383 lsisp
= &sp
->lsis
[i
];
384 lsisp
->ls_trans
= detzcode(p
);
386 lsisp
->ls_corr
= detzcode(p
);
389 for (i
= 0; i
< sp
->typecnt
; ++i
) {
390 register struct ttinfo
* ttisp
;
392 ttisp
= &sp
->ttis
[i
];
394 ttisp
->tt_ttisstd
= FALSE
;
396 ttisp
->tt_ttisstd
= *p
++;
397 if (ttisp
->tt_ttisstd
!= TRUE
&&
398 ttisp
->tt_ttisstd
!= FALSE
)
406 static const int mon_lengths
[2][MONSPERYEAR
] = {
407 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
408 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
411 static const int year_lengths
[2] = {
412 DAYSPERNYEAR
, DAYSPERLYEAR
416 ** Given a pointer into a time zone string, scan until a character that is not
417 ** a valid character in a zone name is found. Return a pointer to that
423 register const char * strp
;
427 while ((c
= *strp
) != '\0' && !isdigit(c
) && c
!= ',' && c
!= '-' &&
434 ** Given a pointer into a time zone string, extract a number from that string.
435 ** Check that the number is within a specified range; if it is not, return
437 ** Otherwise, return a pointer to the first character not part of the number.
441 getnum(strp
, nump
, min
, max
)
442 register const char * strp
;
450 if (strp
== NULL
|| !isdigit(*strp
))
453 while ((c
= *strp
) != '\0' && isdigit(c
)) {
454 num
= num
* 10 + (c
- '0');
456 return NULL
; /* illegal value */
460 return NULL
; /* illegal value */
466 ** Given a pointer into a time zone string, extract a number of seconds,
467 ** in hh[:mm[:ss]] form, from the string.
468 ** If any error occurs, return NULL.
469 ** Otherwise, return a pointer to the first character not part of the number
475 register const char * strp
;
480 strp
= getnum(strp
, &num
, 0, HOURSPERDAY
);
483 *secsp
= num
* SECSPERHOUR
;
486 strp
= getnum(strp
, &num
, 0, MINSPERHOUR
- 1);
489 *secsp
+= num
* SECSPERMIN
;
492 strp
= getnum(strp
, &num
, 0, SECSPERMIN
- 1);
502 ** Given a pointer into a time zone string, extract an offset, in
503 ** [+-]hh[:mm[:ss]] form, from the string.
504 ** If any error occurs, return NULL.
505 ** Otherwise, return a pointer to the first character not part of the time.
509 getoffset(strp
, offsetp
)
510 register const char * strp
;
511 long * const offsetp
;
518 } else if (isdigit(*strp
) || *strp
++ == '+')
520 else return NULL
; /* illegal offset */
521 strp
= getsecs(strp
, offsetp
);
523 return NULL
; /* illegal time */
525 *offsetp
= -*offsetp
;
530 ** Given a pointer into a time zone string, extract a rule in the form
531 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
532 ** If a valid rule is not found, return NULL.
533 ** Otherwise, return a pointer to the first character not part of the rule.
539 register struct rule
* const rulep
;
545 rulep
->r_type
= JULIAN_DAY
;
547 strp
= getnum(strp
, &rulep
->r_day
, 1, DAYSPERNYEAR
);
548 } else if (*strp
== 'M') {
552 rulep
->r_type
= MONTH_NTH_DAY_OF_WEEK
;
554 strp
= getnum(strp
, &rulep
->r_mon
, 1, MONSPERYEAR
);
559 strp
= getnum(strp
, &rulep
->r_week
, 1, 5);
564 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERWEEK
- 1);
565 } else if (isdigit(*strp
)) {
569 rulep
->r_type
= DAY_OF_YEAR
;
570 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERLYEAR
- 1);
571 } else return NULL
; /* invalid format */
579 strp
= getsecs(strp
, &rulep
->r_time
);
580 } else rulep
->r_time
= 2 * SECSPERHOUR
; /* default = 2:00:00 */
585 ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
586 ** year, a rule, and the offset from GMT at the time that rule takes effect,
587 ** calculate the Epoch-relative time that rule takes effect.
591 transtime(janfirst
, year
, rulep
, offset
)
592 const time_t janfirst
;
594 register const struct rule
* const rulep
;
597 register int leapyear
;
598 register time_t value
;
600 int d
, m1
, yy0
, yy1
, yy2
, dow
;
602 leapyear
= isleap(year
);
603 switch (rulep
->r_type
) {
607 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
609 ** In non-leap years, or if the day number is 59 or less, just
610 ** add SECSPERDAY times the day number-1 to the time of
611 ** January 1, midnight, to get the day.
613 value
= janfirst
+ (rulep
->r_day
- 1) * SECSPERDAY
;
614 if (leapyear
&& rulep
->r_day
>= 60)
621 ** Just add SECSPERDAY times the day number to the time of
622 ** January 1, midnight, to get the day.
624 value
= janfirst
+ rulep
->r_day
* SECSPERDAY
;
627 case MONTH_NTH_DAY_OF_WEEK
:
629 ** Mm.n.d - nth "dth day" of month m.
632 for (i
= 0; i
< rulep
->r_mon
- 1; ++i
)
633 value
+= mon_lengths
[leapyear
][i
] * SECSPERDAY
;
636 ** Use Zeller's Congruence to get day-of-week of first day of
639 m1
= (rulep
->r_mon
+ 9) % 12 + 1;
640 yy0
= (rulep
->r_mon
<= 2) ? (year
- 1) : year
;
643 dow
= ((26 * m1
- 2) / 10 +
644 1 + yy2
+ yy2
/ 4 + yy1
/ 4 - 2 * yy1
) % 7;
649 ** "dow" is the day-of-week of the first day of the month. Get
650 ** the day-of-month (zero-origin) of the first "dow" day of the
653 d
= rulep
->r_day
- dow
;
656 for (i
= 1; i
< rulep
->r_week
; ++i
) {
657 if (d
+ DAYSPERWEEK
>=
658 mon_lengths
[leapyear
][rulep
->r_mon
- 1])
664 ** "d" is the day-of-month (zero-origin) of the day we want.
666 value
+= d
* SECSPERDAY
;
671 ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
672 ** question. To get the Epoch-relative time of the specified local
673 ** time on that day, add the transition time and the current offset
676 return value
+ rulep
->r_time
+ offset
;
680 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
685 tzparse(name
, sp
, lastditch
)
687 register struct state
* const sp
;
690 const char * stdname
;
691 const char * dstname
;
696 register time_t * atp
;
697 register unsigned char * typep
;
699 register int load_result
;
703 stdlen
= strlen(name
); /* length of standard zone name */
705 if (stdlen
>= sizeof sp
->chars
)
706 stdlen
= (sizeof sp
->chars
) - 1;
708 name
= getzname(name
);
709 stdlen
= name
- stdname
;
716 name
= getoffset(name
, &stdoffset
);
720 load_result
= tzload(TZDEFRULES
, sp
);
721 if (load_result
!= 0)
722 sp
->leapcnt
= 0; /* so, we're off a little */
725 name
= getzname(name
);
726 dstlen
= name
- dstname
; /* length of DST zone name */
729 if (*name
!= '\0' && *name
!= ',' && *name
!= ';') {
730 name
= getoffset(name
, &dstoffset
);
733 } else dstoffset
= stdoffset
- SECSPERHOUR
;
734 if (*name
== ',' || *name
== ';') {
738 register time_t janfirst
;
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
) {
768 starttime
= transtime(janfirst
, year
, &start
,
770 endtime
= transtime(janfirst
, year
, &end
,
772 if (starttime
> endtime
) {
774 *typep
++ = 1; /* DST ends */
776 *typep
++ = 0; /* DST begins */
779 *typep
++ = 0; /* DST begins */
781 *typep
++ = 1; /* DST ends */
784 year_lengths
[isleap(year
)] * SECSPERDAY
;
797 if (load_result
!= 0)
800 ** Compute the difference between the real and
801 ** prototype standard and summer time offsets
802 ** from GMT, and put the real standard and summer
803 ** time offsets into the rules in place of the
804 ** prototype offsets.
810 for (i
= 0; i
< sp
->typecnt
; ++i
) {
811 if (sp
->ttis
[i
].tt_isdst
) {
814 sp
->ttis
[i
].tt_gmtoff
+ dstoffset
;
815 if (sawdst
&& (oldfix
!= dstfix
))
817 sp
->ttis
[i
].tt_gmtoff
= -dstoffset
;
818 sp
->ttis
[i
].tt_abbrind
= stdlen
+ 1;
823 sp
->ttis
[i
].tt_gmtoff
+ stdoffset
;
824 if (sawstd
&& (oldfix
!= stdfix
))
826 sp
->ttis
[i
].tt_gmtoff
= -stdoffset
;
827 sp
->ttis
[i
].tt_abbrind
= 0;
832 ** Make sure we have both standard and summer time.
834 if (!sawdst
|| !sawstd
)
837 ** Now correct the transition times by shifting
838 ** them by the difference between the real and
839 ** prototype offsets. Note that this difference
840 ** can be different in standard and summer time;
841 ** the prototype probably has a 1-hour difference
842 ** between standard and summer time, but a different
843 ** difference can be specified in TZ.
845 isdst
= FALSE
; /* we start in standard time */
846 for (i
= 0; i
< sp
->timecnt
; ++i
) {
847 register const struct ttinfo
* ttisp
;
850 ** If summer time is in effect, and the
851 ** transition time was not specified as
852 ** standard time, add the summer time
853 ** offset to the transition time;
854 ** otherwise, add the standard time offset
855 ** to the transition time.
857 ttisp
= &sp
->ttis
[sp
->types
[i
]];
859 (isdst
&& !ttisp
->tt_ttisstd
) ?
861 isdst
= ttisp
->tt_isdst
;
866 sp
->typecnt
= 1; /* only standard time */
868 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
869 sp
->ttis
[0].tt_isdst
= 0;
870 sp
->ttis
[0].tt_abbrind
= 0;
872 sp
->charcnt
= stdlen
+ 1;
874 sp
->charcnt
+= dstlen
+ 1;
875 if (sp
->charcnt
> sizeof sp
->chars
)
878 (void) strncpy(cp
, stdname
, stdlen
);
882 (void) strncpy(cp
, dstname
, dstlen
);
883 *(cp
+ dstlen
) = '\0';
890 struct state
* const sp
;
892 if (tzload(GMT
, sp
) != 0)
893 (void) tzparse(GMT
, sp
, TRUE
);
899 register const char * name
;
909 if (lclptr
== NULL
) {
910 lclptr
= (struct state
*) malloc(sizeof *lclptr
);
911 if (lclptr
== NULL
) {
912 settzname(); /* all we can do */
916 #endif /* defined ALL_STATE */
919 ** User wants it fast rather than right.
921 lclptr
->leapcnt
= 0; /* so, we're off a little */
923 lclptr
->ttis
[0].tt_gmtoff
= 0;
924 lclptr
->ttis
[0].tt_abbrind
= 0;
925 (void) strcpy(lclptr
->chars
, GMT
);
926 } else if (tzload(name
, lclptr
) != 0)
927 if (name
[0] == ':' || tzparse(name
, lclptr
, FALSE
) != 0)
928 (void) gmtload(lclptr
);
937 if (lclptr
== NULL
) {
938 lclptr
= (struct state
*) malloc(sizeof *lclptr
);
939 if (lclptr
== NULL
) {
940 settzname(); /* all we can do */
944 #endif /* defined ALL_STATE */
945 if (tzload((char *) NULL
, lclptr
) != 0)
951 ** The easy way to behave "as if no library function calls" localtime
952 ** is to not call it--so we drop its guts into "localsub", which can be
953 ** freely called. (And no, the PANS doesn't require the above behavior--
954 ** but it *is* desirable.)
956 ** The unused offset argument is for the benefit of mktime variants.
961 localsub(timep
, offset
, tmp
)
962 const time_t * const timep
;
964 struct tm
* const tmp
;
966 register struct state
* sp
;
967 register const struct ttinfo
* ttisp
;
969 const time_t t
= *timep
;
976 gmtsub(timep
, offset
, tmp
);
979 #endif /* defined ALL_STATE */
980 if (sp
->timecnt
== 0 || t
< sp
->ats
[0]) {
982 while (sp
->ttis
[i
].tt_isdst
)
983 if (++i
>= sp
->typecnt
) {
988 for (i
= 1; i
< sp
->timecnt
; ++i
)
991 i
= sp
->types
[i
- 1];
993 ttisp
= &sp
->ttis
[i
];
995 ** To get (wrong) behavior that's compatible with System V Release 2.0
996 ** you'd replace the statement below with
997 ** t += ttisp->tt_gmtoff;
998 ** timesub(&t, 0L, sp, tmp);
1000 timesub(&t
, ttisp
->tt_gmtoff
, sp
, tmp
);
1001 tmp
->tm_isdst
= ttisp
->tt_isdst
;
1002 tzname
[tmp
->tm_isdst
] = (char *) &sp
->chars
[ttisp
->tt_abbrind
];
1003 tmp
->tm_zone
= &sp
->chars
[ttisp
->tt_abbrind
];
1008 const time_t * const timep
;
1010 static struct tm tm
;
1012 localsub(timep
, 0L, &tm
);
1017 ** gmtsub is to gmtime as localsub is to localtime.
1021 gmtsub(timep
, offset
, tmp
)
1022 const time_t * const timep
;
1024 struct tm
* const tmp
;
1029 gmtptr
= (struct state
*) malloc(sizeof *gmtptr
);
1031 #endif /* defined ALL_STATE */
1034 timesub(timep
, offset
, gmtptr
, tmp
);
1036 ** Could get fancy here and deliver something such as
1037 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
1038 ** but this is no time for a treasure hunt.
1041 tmp
->tm_zone
= WILDABBR
;
1046 else tmp
->TM_ZONE
= gmtptr
->chars
;
1047 #endif /* defined ALL_STATE */
1049 tmp
->tm_zone
= gmtptr
->chars
;
1050 #endif /* State Farm */
1056 const time_t * const timep
;
1058 static struct tm tm
;
1060 gmtsub(timep
, 0L, &tm
);
1065 timesub(timep
, offset
, sp
, tmp
)
1066 const time_t * const timep
;
1068 register const struct state
* const sp
;
1069 register struct tm
* const tmp
;
1071 register const struct lsinfo
* lp
;
1076 register const int * ip
;
1084 i
= (sp
== NULL
) ? 0 : sp
->leapcnt
;
1085 #endif /* defined ALL_STATE */
1088 #endif /* State Farm */
1091 if (*timep
>= lp
->ls_trans
) {
1092 if (*timep
== lp
->ls_trans
)
1093 hit
= ((i
== 0 && lp
->ls_corr
> 0) ||
1094 lp
->ls_corr
> sp
->lsis
[i
- 1].ls_corr
);
1099 days
= *timep
/ SECSPERDAY
;
1100 rem
= *timep
% SECSPERDAY
;
1102 if (*timep
== 0x80000000) {
1104 ** A 3B1 muffs the division on the most negative number.
1110 rem
+= (offset
- corr
);
1115 while (rem
>= SECSPERDAY
) {
1119 tmp
->tm_hour
= (int) (rem
/ SECSPERHOUR
);
1120 rem
= rem
% SECSPERHOUR
;
1121 tmp
->tm_min
= (int) (rem
/ SECSPERMIN
);
1122 tmp
->tm_sec
= (int) (rem
% SECSPERMIN
);
1125 ** A positive leap second requires a special
1126 ** representation. This uses "... ??:59:60".
1129 tmp
->tm_wday
= (int) ((EPOCH_WDAY
+ days
) % DAYSPERWEEK
);
1130 if (tmp
->tm_wday
< 0)
1131 tmp
->tm_wday
+= DAYSPERWEEK
;
1136 if (days
< (long) year_lengths
[yleap
])
1139 days
= days
- (long) year_lengths
[yleap
];
1144 days
= days
+ (long) year_lengths
[yleap
];
1146 tmp
->tm_year
= y
- TM_YEAR_BASE
;
1147 tmp
->tm_yday
= (int) days
;
1148 ip
= mon_lengths
[yleap
];
1149 for (tmp
->tm_mon
= 0; days
>= (long) ip
[tmp
->tm_mon
]; ++(tmp
->tm_mon
))
1150 days
= days
- (long) ip
[tmp
->tm_mon
];
1151 tmp
->tm_mday
= (int) (days
+ 1);
1153 tmp
->tm_gmtoff
= offset
;
1162 register const struct tm
* timeptr
;
1164 static const char wday_name
[DAYSPERWEEK
][3] = {
1165 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1167 static const char mon_name
[MONSPERYEAR
][3] = {
1168 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1169 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1171 static char result
[26];
1173 (void) sprintf(result
, "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n",
1174 wday_name
[timeptr
->tm_wday
],
1175 mon_name
[timeptr
->tm_mon
],
1176 timeptr
->tm_mday
, timeptr
->tm_hour
,
1177 timeptr
->tm_min
, timeptr
->tm_sec
,
1178 TM_YEAR_BASE
+ timeptr
->tm_year
);
1184 const time_t * const timep
;
1186 return asctime(localtime(timep
));
1190 ** Adapted from code provided by Robert Elz, who writes:
1191 ** The "best" way to do mktime I think is based on an idea of Bob
1192 ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
1193 ** It does a binary search of the time_t space. Since time_t's are
1194 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
1195 ** would still be very reasonable).
1200 #endif /* !defined WRONG */
1203 normalize(tensptr
, unitsptr
, base
)
1204 int * const tensptr
;
1205 int * const unitsptr
;
1208 if (*unitsptr
>= base
) {
1209 *tensptr
+= *unitsptr
/ base
;
1211 } else if (*unitsptr
< 0) {
1212 *tensptr
-= 1 + (-(*unitsptr
+ 1)) / base
;
1213 *unitsptr
= base
- 1 - (-(*unitsptr
+ 1)) % base
;
1219 register const struct tm
* const atmp
;
1220 register const struct tm
* const btmp
;
1222 register int result
;
1224 if ((result
= (atmp
->tm_year
- btmp
->tm_year
)) == 0 &&
1225 (result
= (atmp
->tm_mon
- btmp
->tm_mon
)) == 0 &&
1226 (result
= (atmp
->tm_mday
- btmp
->tm_mday
)) == 0 &&
1227 (result
= (atmp
->tm_hour
- btmp
->tm_hour
)) == 0 &&
1228 (result
= (atmp
->tm_min
- btmp
->tm_min
)) == 0)
1229 result
= atmp
->tm_sec
- btmp
->tm_sec
;
1234 time2(tmp
, funcp
, offset
, okayp
)
1235 struct tm
* const tmp
;
1236 void (* const funcp
)();
1240 register const struct state
* sp
;
1244 register int saved_seconds
;
1247 struct tm yourtm
, mytm
;
1251 if (yourtm
.tm_sec
>= SECSPERMIN
+ 2 || yourtm
.tm_sec
< 0)
1252 normalize(&yourtm
.tm_min
, &yourtm
.tm_sec
, SECSPERMIN
);
1253 normalize(&yourtm
.tm_hour
, &yourtm
.tm_min
, MINSPERHOUR
);
1254 normalize(&yourtm
.tm_mday
, &yourtm
.tm_hour
, HOURSPERDAY
);
1255 normalize(&yourtm
.tm_year
, &yourtm
.tm_mon
, MONSPERYEAR
);
1256 while (yourtm
.tm_mday
<= 0) {
1259 year_lengths
[isleap(yourtm
.tm_year
+ TM_YEAR_BASE
)];
1261 while (yourtm
.tm_mday
> DAYSPERLYEAR
) {
1263 year_lengths
[isleap(yourtm
.tm_year
+ TM_YEAR_BASE
)];
1267 i
= mon_lengths
[isleap(yourtm
.tm_year
+
1268 TM_YEAR_BASE
)][yourtm
.tm_mon
];
1269 if (yourtm
.tm_mday
<= i
)
1271 yourtm
.tm_mday
-= i
;
1272 if (++yourtm
.tm_mon
>= MONSPERYEAR
) {
1277 saved_seconds
= yourtm
.tm_sec
;
1280 ** Calculate the number of magnitude bits in a time_t
1281 ** (this works regardless of whether time_t is
1282 ** signed or unsigned, though lint complains if unsigned).
1284 for (bits
= 0, t
= 1; t
> 0; ++bits
, t
<<= 1)
1287 ** If time_t is signed, then 0 is the median value,
1288 ** if time_t is unsigned, then 1 << bits is median.
1290 t
= (t
< 0) ? 0 : ((time_t) 1 << bits
);
1292 (*funcp
)(&t
, offset
, &mytm
);
1293 dir
= tmcomp(&mytm
, &yourtm
);
1300 t
-= (time_t) 1 << bits
;
1301 else t
+= (time_t) 1 << bits
;
1304 if (yourtm
.tm_isdst
< 0 || mytm
.tm_isdst
== yourtm
.tm_isdst
)
1307 ** Right time, wrong type.
1308 ** Hunt for right time, right type.
1309 ** It's okay to guess wrong since the guess
1312 sp
= (const struct state
*)
1313 ((funcp
== localsub
) ? lclptr
: gmtptr
);
1317 #endif /* defined ALL_STATE */
1318 for (i
= 0; i
< sp
->typecnt
; ++i
) {
1319 if (sp
->ttis
[i
].tt_isdst
!= yourtm
.tm_isdst
)
1321 for (j
= 0; j
< sp
->typecnt
; ++j
) {
1322 if (sp
->ttis
[j
].tt_isdst
== yourtm
.tm_isdst
)
1324 newt
= t
+ sp
->ttis
[j
].tt_gmtoff
-
1325 sp
->ttis
[i
].tt_gmtoff
;
1326 (*funcp
)(&newt
, offset
, &mytm
);
1327 if (tmcomp(&mytm
, &yourtm
) != 0)
1329 if (mytm
.tm_isdst
!= yourtm
.tm_isdst
)
1342 (*funcp
)(&t
, offset
, tmp
);
1348 time1(tmp
, funcp
, offset
)
1349 struct tm
* const tmp
;
1350 void (* const funcp
)();
1354 register const struct state
* sp
;
1355 register int samei
, otheri
;
1358 if (tmp
->tm_isdst
> 1)
1360 t
= time2(tmp
, funcp
, offset
, &okay
);
1361 if (okay
|| tmp
->tm_isdst
< 0)
1364 ** We're supposed to assume that somebody took a time of one type
1365 ** and did some math on it that yielded a "struct tm" that's bad.
1366 ** We try to divine the type they started from and adjust to the
1369 sp
= (const struct state
*) ((funcp
== localsub
) ? lclptr
: gmtptr
);
1373 #endif /* defined ALL_STATE */
1374 for (samei
= 0; samei
< sp
->typecnt
; ++samei
) {
1375 if (sp
->ttis
[samei
].tt_isdst
!= tmp
->tm_isdst
)
1377 for (otheri
= 0; otheri
< sp
->typecnt
; ++otheri
) {
1378 if (sp
->ttis
[otheri
].tt_isdst
== tmp
->tm_isdst
)
1380 tmp
->tm_sec
+= sp
->ttis
[otheri
].tt_gmtoff
-
1381 sp
->ttis
[samei
].tt_gmtoff
;
1382 tmp
->tm_isdst
= !tmp
->tm_isdst
;
1383 t
= time2(tmp
, funcp
, offset
, &okay
);
1386 tmp
->tm_sec
-= sp
->ttis
[otheri
].tt_gmtoff
-
1387 sp
->ttis
[samei
].tt_gmtoff
;
1388 tmp
->tm_isdst
= !tmp
->tm_isdst
;
1396 struct tm
* const tmp
;
1398 return time1(tmp
, localsub
, 0L);