2 ** This file is in the public domain, so clarified as of
3 ** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov).
5 ** $FreeBSD: src/lib/libc/stdtime/localtime.c,v 1.25.2.1 2001/03/05 11:37:21 obrien Exp $
10 static char elsieid
[] = "@(#)localtime.c 7.57";
11 #endif /* !defined NOID */
12 #endif /* !defined lint */
15 ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
16 ** POSIX-style TZ environment variable handling from Guy Harris
22 #include <sys/types.h>
29 #include "pthread_private.h"
33 ** SunOS 4.1.1 headers lack O_BINARY.
37 #define OPEN_MODE (O_RDONLY | O_BINARY)
38 #endif /* defined O_BINARY */
40 #define OPEN_MODE O_RDONLY
41 #endif /* !defined O_BINARY */
45 ** Someone might make incorrect use of a time zone abbreviation:
46 ** 1. They might reference tzname[0] before calling tzset (explicitly
48 ** 2. They might reference tzname[1] before calling tzset (explicitly
50 ** 3. They might reference tzname[1] after setting to a time zone
51 ** in which Daylight Saving Time is never observed.
52 ** 4. They might reference tzname[0] after setting to a time zone
53 ** in which Standard Time is never observed.
54 ** 5. They might reference tm.TM_ZONE after calling offtime.
55 ** What's best to do in the above cases is open to debate;
56 ** for now, we just set things up so that in any of the five cases
57 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
58 ** string "tzname[0] used before set", and similarly for the other cases.
59 ** And another: initialize tzname[0] to "ERA", with an explanation in the
60 ** manual page of what this "time zone abbreviation" means (doing this so
61 ** that tzname[0] has the "normal" length of three characters).
64 #endif /* !defined WILDABBR */
66 static char wildabbr
[] = "WILDABBR";
68 static const char gmt
[] = "GMT";
70 struct ttinfo
{ /* time type information */
71 long tt_gmtoff
; /* GMT offset in seconds */
72 int tt_isdst
; /* used to set tm_isdst */
73 int tt_abbrind
; /* abbreviation list index */
74 int tt_ttisstd
; /* TRUE if transition is std time */
75 int tt_ttisgmt
; /* TRUE if transition is GMT */
78 struct lsinfo
{ /* leap second information */
79 time_t ls_trans
; /* transition time */
80 long ls_corr
; /* correction to apply */
83 #define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
86 #define MY_TZNAME_MAX TZNAME_MAX
87 #endif /* defined TZNAME_MAX */
89 #define MY_TZNAME_MAX 255
90 #endif /* !defined TZNAME_MAX */
97 time_t ats
[TZ_MAX_TIMES
];
98 unsigned char types
[TZ_MAX_TIMES
];
99 struct ttinfo ttis
[TZ_MAX_TYPES
];
100 char chars
[BIGGEST(BIGGEST(TZ_MAX_CHARS
+ 1, sizeof gmt
),
101 (2 * (MY_TZNAME_MAX
+ 1)))];
102 struct lsinfo lsis
[TZ_MAX_LEAPS
];
106 int r_type
; /* type of rule--see below */
107 int r_day
; /* day number of rule */
108 int r_week
; /* week number of rule */
109 int r_mon
; /* month number of rule */
110 long r_time
; /* transition time of rule */
113 #define JULIAN_DAY 0 /* Jn - Julian day */
114 #define DAY_OF_YEAR 1 /* n - day of year */
115 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
118 ** Prototypes for static functions.
121 static long detzcode
P((const char * codep
));
122 static const char * getzname
P((const char * strp
));
123 static const char * getnum
P((const char * strp
, int * nump
, int min
,
125 static const char * getsecs
P((const char * strp
, long * secsp
));
126 static const char * getoffset
P((const char * strp
, long * offsetp
));
127 static const char * getrule
P((const char * strp
, struct rule
* rulep
));
128 static void gmtload
P((struct state
* sp
));
129 static void gmtsub
P((const time_t * timep
, long offset
,
131 static void localsub
P((const time_t * timep
, long offset
,
133 static int increment_overflow
P((int * number
, int delta
));
134 static int normalize_overflow
P((int * tensptr
, int * unitsptr
,
136 static void settzname
P((void));
137 static time_t time1
P((struct tm
* tmp
,
138 void(*funcp
) P((const time_t *,
141 static time_t time2
P((struct tm
*tmp
,
142 void(*funcp
) P((const time_t *,
144 long offset
, int * okayp
));
145 static void timesub
P((const time_t * timep
, long offset
,
146 const struct state
* sp
, struct tm
* tmp
));
147 static int tmcomp
P((const struct tm
* atmp
,
148 const struct tm
* btmp
));
149 static time_t transtime
P((time_t janfirst
, int year
,
150 const struct rule
* rulep
, long offset
));
151 static int tzload
P((const char * name
, struct state
* sp
));
152 static int tzparse
P((const char * name
, struct state
* sp
,
156 static struct state
* lclptr
;
157 static struct state
* gmtptr
;
158 #endif /* defined ALL_STATE */
161 static struct state lclmem
;
162 static struct state gmtmem
;
163 #define lclptr (&lclmem)
164 #define gmtptr (&gmtmem)
165 #endif /* State Farm */
167 #ifndef TZ_STRLEN_MAX
168 #define TZ_STRLEN_MAX 255
169 #endif /* !defined TZ_STRLEN_MAX */
171 static char lcl_TZname
[TZ_STRLEN_MAX
+ 1];
173 static struct pthread_mutex _lcl_mutexd
= PTHREAD_MUTEX_STATIC_INITIALIZER
;
174 static struct pthread_mutex _gmt_mutexd
= PTHREAD_MUTEX_STATIC_INITIALIZER
;
175 static pthread_mutex_t lcl_mutex
= &_lcl_mutexd
;
176 static pthread_mutex_t gmt_mutex
= &_gmt_mutexd
;
185 ** Section 4.12.3 of X3.159-1989 requires that
186 ** Except for the strftime function, these functions [asctime,
187 ** ctime, gmtime, localtime] return values in one of two static
188 ** objects: a broken-down time structure and an array of char.
189 ** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
197 #endif /* defined USG_COMPAT */
201 #endif /* defined ALTZONE */
205 const char * const codep
;
207 register long result
;
210 result
= (codep
[0] & 0x80) ? ~0L : 0L;
211 for (i
= 0; i
< 4; ++i
)
212 result
= (result
<< 8) | (codep
[i
] & 0xff);
219 register struct state
* sp
= lclptr
;
222 tzname
[0] = wildabbr
;
223 tzname
[1] = wildabbr
;
227 #endif /* defined USG_COMPAT */
230 #endif /* defined ALTZONE */
233 tzname
[0] = tzname
[1] = gmt
;
236 #endif /* defined ALL_STATE */
237 for (i
= 0; i
< sp
->typecnt
; ++i
) {
238 register const struct ttinfo
* const ttisp
= &sp
->ttis
[i
];
240 tzname
[ttisp
->tt_isdst
] =
241 &sp
->chars
[ttisp
->tt_abbrind
];
245 if (i
== 0 || !ttisp
->tt_isdst
)
246 timezone
= -(ttisp
->tt_gmtoff
);
247 #endif /* defined USG_COMPAT */
249 if (i
== 0 || ttisp
->tt_isdst
)
250 altzone
= -(ttisp
->tt_gmtoff
);
251 #endif /* defined ALTZONE */
254 ** And to get the latest zone names into tzname. . .
256 for (i
= 0; i
< sp
->timecnt
; ++i
) {
257 register const struct ttinfo
* const ttisp
=
261 tzname
[ttisp
->tt_isdst
] =
262 &sp
->chars
[ttisp
->tt_abbrind
];
268 register const char * name
;
269 register struct state
* const sp
;
271 register const char * p
;
274 static struct stat sb
;
277 /* XXX The following is from OpenBSD, and I'm not sure it is correct */
278 if (name
!= NULL
&& issetugid() != 0)
279 if ((name
[0] == ':' && name
[1] == '/') ||
280 name
[0] == '/' || strchr(name
, '.'))
282 if (name
== NULL
&& (name
= TZDEFAULT
) == NULL
)
285 register int doaccess
;
288 ** Section 4.9.1 of the C standard says that
289 ** "FILENAME_MAX expands to an integral constant expression
290 ** that is the size needed for an array of char large enough
291 ** to hold the longest file name string that the implementation
292 ** guarantees can be opened."
294 char fullname
[FILENAME_MAX
+ 1];
298 doaccess
= name
[0] == '/';
300 if ((p
= TZDIR
) == NULL
)
302 if ((strlen(p
) + 1 + strlen(name
) + 1) >= sizeof fullname
)
304 (void) strcpy(fullname
, p
);
305 (void) strcat(fullname
, "/");
306 (void) strcat(fullname
, name
);
308 ** Set doaccess if '.' (as in "../") shows up in name.
310 if (strchr(name
, '.') != NULL
)
314 if (lstat(name
, &newsb
) == -1)
316 if( (sb
.st_dev
== newsb
.st_dev
) && (sb
.st_ino
== newsb
.st_ino
) &&
317 (sb
.st_gen
== newsb
.st_gen
) &&
318 (memcmp(&sb
.st_ctimespec
, &newsb
.st_ctimespec
,
319 sizeof(struct timespec
)) == 0) ) {
322 memcpy(&sb
, &newsb
, sizeof(sb
));
323 if ((fid
= open(name
, OPEN_MODE
)) == -1)
325 if ((fstat(fid
, &stab
) < 0) || !S_ISREG(stab
.st_mode
))
329 struct tzhead
* tzhp
;
330 char buf
[sizeof *sp
+ sizeof *tzhp
];
334 i
= read(fid
, buf
, sizeof buf
);
338 p
+= (sizeof tzhp
->tzh_magic
) + (sizeof tzhp
->tzh_reserved
);
339 ttisstdcnt
= (int) detzcode(p
);
341 ttisgmtcnt
= (int) detzcode(p
);
343 sp
->leapcnt
= (int) detzcode(p
);
345 sp
->timecnt
= (int) detzcode(p
);
347 sp
->typecnt
= (int) detzcode(p
);
349 sp
->charcnt
= (int) detzcode(p
);
351 if (sp
->leapcnt
< 0 || sp
->leapcnt
> TZ_MAX_LEAPS
||
352 sp
->typecnt
<= 0 || sp
->typecnt
> TZ_MAX_TYPES
||
353 sp
->timecnt
< 0 || sp
->timecnt
> TZ_MAX_TIMES
||
354 sp
->charcnt
< 0 || sp
->charcnt
> TZ_MAX_CHARS
||
355 (ttisstdcnt
!= sp
->typecnt
&& ttisstdcnt
!= 0) ||
356 (ttisgmtcnt
!= sp
->typecnt
&& ttisgmtcnt
!= 0))
358 if (i
- (p
- buf
) < sp
->timecnt
* 4 + /* ats */
359 sp
->timecnt
+ /* types */
360 sp
->typecnt
* (4 + 2) + /* ttinfos */
361 sp
->charcnt
+ /* chars */
362 sp
->leapcnt
* (4 + 4) + /* lsinfos */
363 ttisstdcnt
+ /* ttisstds */
364 ttisgmtcnt
) /* ttisgmts */
366 for (i
= 0; i
< sp
->timecnt
; ++i
) {
367 sp
->ats
[i
] = detzcode(p
);
370 for (i
= 0; i
< sp
->timecnt
; ++i
) {
371 sp
->types
[i
] = (unsigned char) *p
++;
372 if (sp
->types
[i
] >= sp
->typecnt
)
375 for (i
= 0; i
< sp
->typecnt
; ++i
) {
376 register struct ttinfo
* ttisp
;
378 ttisp
= &sp
->ttis
[i
];
379 ttisp
->tt_gmtoff
= detzcode(p
);
381 ttisp
->tt_isdst
= (unsigned char) *p
++;
382 if (ttisp
->tt_isdst
!= 0 && ttisp
->tt_isdst
!= 1)
384 ttisp
->tt_abbrind
= (unsigned char) *p
++;
385 if (ttisp
->tt_abbrind
< 0 ||
386 ttisp
->tt_abbrind
> sp
->charcnt
)
389 for (i
= 0; i
< sp
->charcnt
; ++i
)
391 sp
->chars
[i
] = '\0'; /* ensure '\0' at end */
392 for (i
= 0; i
< sp
->leapcnt
; ++i
) {
393 register struct lsinfo
* lsisp
;
395 lsisp
= &sp
->lsis
[i
];
396 lsisp
->ls_trans
= detzcode(p
);
398 lsisp
->ls_corr
= detzcode(p
);
401 for (i
= 0; i
< sp
->typecnt
; ++i
) {
402 register struct ttinfo
* ttisp
;
404 ttisp
= &sp
->ttis
[i
];
406 ttisp
->tt_ttisstd
= FALSE
;
408 ttisp
->tt_ttisstd
= *p
++;
409 if (ttisp
->tt_ttisstd
!= TRUE
&&
410 ttisp
->tt_ttisstd
!= FALSE
)
414 for (i
= 0; i
< sp
->typecnt
; ++i
) {
415 register struct ttinfo
* ttisp
;
417 ttisp
= &sp
->ttis
[i
];
419 ttisp
->tt_ttisgmt
= FALSE
;
421 ttisp
->tt_ttisgmt
= *p
++;
422 if (ttisp
->tt_ttisgmt
!= TRUE
&&
423 ttisp
->tt_ttisgmt
!= FALSE
)
431 static const int mon_lengths
[2][MONSPERYEAR
] = {
432 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
433 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
436 static const int year_lengths
[2] = {
437 DAYSPERNYEAR
, DAYSPERLYEAR
441 ** Given a pointer into a time zone string, scan until a character that is not
442 ** a valid character in a zone name is found. Return a pointer to that
448 register const char * strp
;
452 while ((c
= *strp
) != '\0' && !is_digit(c
) && c
!= ',' && c
!= '-' &&
459 ** Given a pointer into a time zone string, extract a number from that string.
460 ** Check that the number is within a specified range; if it is not, return
462 ** Otherwise, return a pointer to the first character not part of the number.
466 getnum(strp
, nump
, min
, max
)
467 register const char * strp
;
475 if (strp
== NULL
|| !is_digit(c
= *strp
))
479 num
= num
* 10 + (c
- '0');
481 return NULL
; /* illegal value */
483 } while (is_digit(c
));
485 return NULL
; /* illegal value */
491 ** Given a pointer into a time zone string, extract a number of seconds,
492 ** in hh[:mm[:ss]] form, from the string.
493 ** If any error occurs, return NULL.
494 ** Otherwise, return a pointer to the first character not part of the number
500 register const char * strp
;
506 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
507 ** "M10.4.6/26", which does not conform to Posix,
508 ** but which specifies the equivalent of
509 ** ``02:00 on the first Sunday on or after 23 Oct''.
511 strp
= getnum(strp
, &num
, 0, HOURSPERDAY
* DAYSPERWEEK
- 1);
514 *secsp
= num
* (long) SECSPERHOUR
;
517 strp
= getnum(strp
, &num
, 0, MINSPERHOUR
- 1);
520 *secsp
+= num
* SECSPERMIN
;
523 /* `SECSPERMIN' allows for leap seconds. */
524 strp
= getnum(strp
, &num
, 0, SECSPERMIN
);
534 ** Given a pointer into a time zone string, extract an offset, in
535 ** [+-]hh[:mm[:ss]] form, from the string.
536 ** If any error occurs, return NULL.
537 ** Otherwise, return a pointer to the first character not part of the time.
541 getoffset(strp
, offsetp
)
542 register const char * strp
;
543 long * const offsetp
;
545 register int neg
= 0;
550 } else if (*strp
== '+')
552 strp
= getsecs(strp
, offsetp
);
554 return NULL
; /* illegal time */
556 *offsetp
= -*offsetp
;
561 ** Given a pointer into a time zone string, extract a rule in the form
562 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
563 ** If a valid rule is not found, return NULL.
564 ** Otherwise, return a pointer to the first character not part of the rule.
570 register struct rule
* const rulep
;
576 rulep
->r_type
= JULIAN_DAY
;
578 strp
= getnum(strp
, &rulep
->r_day
, 1, DAYSPERNYEAR
);
579 } else if (*strp
== 'M') {
583 rulep
->r_type
= MONTH_NTH_DAY_OF_WEEK
;
585 strp
= getnum(strp
, &rulep
->r_mon
, 1, MONSPERYEAR
);
590 strp
= getnum(strp
, &rulep
->r_week
, 1, 5);
595 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERWEEK
- 1);
596 } else if (is_digit(*strp
)) {
600 rulep
->r_type
= DAY_OF_YEAR
;
601 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERLYEAR
- 1);
602 } else return NULL
; /* invalid format */
610 strp
= getsecs(strp
, &rulep
->r_time
);
611 } else rulep
->r_time
= 2 * SECSPERHOUR
; /* default = 2:00:00 */
616 ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
617 ** year, a rule, and the offset from GMT at the time that rule takes effect,
618 ** calculate the Epoch-relative time that rule takes effect.
622 transtime(janfirst
, year
, rulep
, offset
)
623 const time_t janfirst
;
625 register const struct rule
* const rulep
;
628 register int leapyear
;
629 register time_t value
;
631 int d
, m1
, yy0
, yy1
, yy2
, dow
;
634 leapyear
= isleap(year
);
635 switch (rulep
->r_type
) {
639 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
641 ** In non-leap years, or if the day number is 59 or less, just
642 ** add SECSPERDAY times the day number-1 to the time of
643 ** January 1, midnight, to get the day.
645 value
= janfirst
+ (rulep
->r_day
- 1) * SECSPERDAY
;
646 if (leapyear
&& rulep
->r_day
>= 60)
653 ** Just add SECSPERDAY times the day number to the time of
654 ** January 1, midnight, to get the day.
656 value
= janfirst
+ rulep
->r_day
* SECSPERDAY
;
659 case MONTH_NTH_DAY_OF_WEEK
:
661 ** Mm.n.d - nth "dth day" of month m.
664 for (i
= 0; i
< rulep
->r_mon
- 1; ++i
)
665 value
+= mon_lengths
[leapyear
][i
] * SECSPERDAY
;
668 ** Use Zeller's Congruence to get day-of-week of first day of
671 m1
= (rulep
->r_mon
+ 9) % 12 + 1;
672 yy0
= (rulep
->r_mon
<= 2) ? (year
- 1) : year
;
675 dow
= ((26 * m1
- 2) / 10 +
676 1 + yy2
+ yy2
/ 4 + yy1
/ 4 - 2 * yy1
) % 7;
681 ** "dow" is the day-of-week of the first day of the month. Get
682 ** the day-of-month (zero-origin) of the first "dow" day of the
685 d
= rulep
->r_day
- dow
;
688 for (i
= 1; i
< rulep
->r_week
; ++i
) {
689 if (d
+ DAYSPERWEEK
>=
690 mon_lengths
[leapyear
][rulep
->r_mon
- 1])
696 ** "d" is the day-of-month (zero-origin) of the day we want.
698 value
+= d
* SECSPERDAY
;
703 ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
704 ** question. To get the Epoch-relative time of the specified local
705 ** time on that day, add the transition time and the current offset
708 return value
+ rulep
->r_time
+ offset
;
712 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
717 tzparse(name
, sp
, lastditch
)
719 register struct state
* const sp
;
722 const char * stdname
;
723 const char * dstname
;
728 register time_t * atp
;
729 register unsigned char * typep
;
731 register int load_result
;
736 stdlen
= strlen(name
); /* length of standard zone name */
738 if (stdlen
>= sizeof sp
->chars
)
739 stdlen
= (sizeof sp
->chars
) - 1;
742 name
= getzname(name
);
743 stdlen
= name
- stdname
;
747 return -1; /* was "stdoffset = 0;" */
749 name
= getoffset(name
, &stdoffset
);
754 load_result
= tzload(TZDEFRULES
, sp
);
755 if (load_result
!= 0)
756 sp
->leapcnt
= 0; /* so, we're off a little */
759 name
= getzname(name
);
760 dstlen
= name
- dstname
; /* length of DST zone name */
763 if (*name
!= '\0' && *name
!= ',' && *name
!= ';') {
764 name
= getoffset(name
, &dstoffset
);
767 } else dstoffset
= stdoffset
- SECSPERHOUR
;
768 if (*name
== ',' || *name
== ';') {
772 register time_t janfirst
;
777 if ((name
= getrule(name
, &start
)) == NULL
)
781 if ((name
= getrule(name
, &end
)) == NULL
)
785 sp
->typecnt
= 2; /* standard time and DST */
787 ** Two transitions per year, from EPOCH_YEAR to 2037.
789 sp
->timecnt
= 2 * (2037 - EPOCH_YEAR
+ 1);
790 if (sp
->timecnt
> TZ_MAX_TIMES
)
792 sp
->ttis
[0].tt_gmtoff
= -dstoffset
;
793 sp
->ttis
[0].tt_isdst
= 1;
794 sp
->ttis
[0].tt_abbrind
= stdlen
+ 1;
795 sp
->ttis
[1].tt_gmtoff
= -stdoffset
;
796 sp
->ttis
[1].tt_isdst
= 0;
797 sp
->ttis
[1].tt_abbrind
= 0;
801 for (year
= EPOCH_YEAR
; year
<= 2037; ++year
) {
802 starttime
= transtime(janfirst
, year
, &start
,
804 endtime
= transtime(janfirst
, year
, &end
,
806 if (starttime
> endtime
) {
808 *typep
++ = 1; /* DST ends */
810 *typep
++ = 0; /* DST begins */
813 *typep
++ = 0; /* DST begins */
815 *typep
++ = 1; /* DST ends */
817 janfirst
+= year_lengths
[isleap(year
)] *
821 register long theirstdoffset
;
822 register long theirdstoffset
;
823 register long theiroffset
;
830 if (load_result
!= 0)
833 ** Initial values of theirstdoffset and theirdstoffset.
836 for (i
= 0; i
< sp
->timecnt
; ++i
) {
838 if (!sp
->ttis
[j
].tt_isdst
) {
840 -sp
->ttis
[j
].tt_gmtoff
;
845 for (i
= 0; i
< sp
->timecnt
; ++i
) {
847 if (sp
->ttis
[j
].tt_isdst
) {
849 -sp
->ttis
[j
].tt_gmtoff
;
854 ** Initially we're assumed to be in standard time.
857 theiroffset
= theirstdoffset
;
859 ** Now juggle transition times and types
860 ** tracking offsets as you do.
862 for (i
= 0; i
< sp
->timecnt
; ++i
) {
864 sp
->types
[i
] = sp
->ttis
[j
].tt_isdst
;
865 if (sp
->ttis
[j
].tt_ttisgmt
) {
866 /* No adjustment to transition time */
869 ** If summer time is in effect, and the
870 ** transition time was not specified as
871 ** standard time, add the summer time
872 ** offset to the transition time;
873 ** otherwise, add the standard time
874 ** offset to the transition time.
877 ** Transitions from DST to DDST
878 ** will effectively disappear since
879 ** POSIX provides for only one DST
882 if (isdst
&& !sp
->ttis
[j
].tt_ttisstd
) {
883 sp
->ats
[i
] += dstoffset
-
886 sp
->ats
[i
] += stdoffset
-
890 theiroffset
= -sp
->ttis
[j
].tt_gmtoff
;
891 if (sp
->ttis
[j
].tt_isdst
)
892 theirdstoffset
= theiroffset
;
893 else theirstdoffset
= theiroffset
;
896 ** Finally, fill in ttis.
897 ** ttisstd and ttisgmt need not be handled.
899 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
900 sp
->ttis
[0].tt_isdst
= FALSE
;
901 sp
->ttis
[0].tt_abbrind
= 0;
902 sp
->ttis
[1].tt_gmtoff
= -dstoffset
;
903 sp
->ttis
[1].tt_isdst
= TRUE
;
904 sp
->ttis
[1].tt_abbrind
= stdlen
+ 1;
908 sp
->typecnt
= 1; /* only standard time */
910 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
911 sp
->ttis
[0].tt_isdst
= 0;
912 sp
->ttis
[0].tt_abbrind
= 0;
914 sp
->charcnt
= stdlen
+ 1;
916 sp
->charcnt
+= dstlen
+ 1;
917 if (sp
->charcnt
> sizeof sp
->chars
)
920 (void) strncpy(cp
, stdname
, stdlen
);
924 (void) strncpy(cp
, dstname
, dstlen
);
925 *(cp
+ dstlen
) = '\0';
932 struct state
* const sp
;
934 if (tzload(gmt
, sp
) != 0)
935 (void) tzparse(gmt
, sp
, TRUE
);
940 ** A non-static declaration of tzsetwall in a system header file
941 ** may cause a warning about this upcoming static declaration...
944 #endif /* !defined STD_INSPIRED */
947 tzsetwall_basic
P((void))
955 if (lclptr
== NULL
) {
956 lclptr
= (struct state
*) malloc(sizeof *lclptr
);
957 if (lclptr
== NULL
) {
958 settzname(); /* all we can do */
962 #endif /* defined ALL_STATE */
963 if (tzload((char *) NULL
, lclptr
) != 0)
972 pthread_mutex_lock(&lcl_mutex
);
974 pthread_mutex_unlock(&lcl_mutex
);
980 tzset_basic
P((void))
986 register const char * name
;
994 if (strlen(name
) < sizeof(lcl_TZname
))
995 (void) strcpy(lcl_TZname
, name
);
998 if (lclptr
== NULL
) {
999 lclptr
= (struct state
*) malloc(sizeof *lclptr
);
1000 if (lclptr
== NULL
) {
1001 settzname(); /* all we can do */
1005 #endif /* defined ALL_STATE */
1006 if (*name
== '\0') {
1008 ** User wants it fast rather than right.
1010 lclptr
->leapcnt
= 0; /* so, we're off a little */
1011 lclptr
->timecnt
= 0;
1012 lclptr
->ttis
[0].tt_gmtoff
= 0;
1013 lclptr
->ttis
[0].tt_abbrind
= 0;
1014 (void) strcpy(lclptr
->chars
, gmt
);
1015 } else if (tzload(name
, lclptr
) != 0)
1016 if (name
[0] == ':' || tzparse(name
, lclptr
, FALSE
) != 0)
1017 (void) gmtload(lclptr
);
1025 pthread_mutex_lock(&lcl_mutex
);
1027 pthread_mutex_unlock(&lcl_mutex
);
1032 ** The easy way to behave "as if no library function calls" localtime
1033 ** is to not call it--so we drop its guts into "localsub", which can be
1034 ** freely called. (And no, the PANS doesn't require the above behavior--
1035 ** but it *is* desirable.)
1037 ** The unused offset argument is for the benefit of mktime variants.
1042 localsub(timep
, offset
, tmp
)
1043 const time_t * const timep
;
1045 struct tm
* const tmp
;
1047 register struct state
* sp
;
1048 register const struct ttinfo
* ttisp
;
1050 const time_t t
= *timep
;
1055 gmtsub(timep
, offset
, tmp
);
1058 #endif /* defined ALL_STATE */
1059 if (sp
->timecnt
== 0 || t
< sp
->ats
[0]) {
1061 while (sp
->ttis
[i
].tt_isdst
)
1062 if (++i
>= sp
->typecnt
) {
1067 for (i
= 1; i
< sp
->timecnt
; ++i
)
1070 i
= sp
->types
[i
- 1];
1072 ttisp
= &sp
->ttis
[i
];
1074 ** To get (wrong) behavior that's compatible with System V Release 2.0
1075 ** you'd replace the statement below with
1076 ** t += ttisp->tt_gmtoff;
1077 ** timesub(&t, 0L, sp, tmp);
1079 timesub(&t
, ttisp
->tt_gmtoff
, sp
, tmp
);
1080 tmp
->tm_isdst
= ttisp
->tt_isdst
;
1081 tzname
[tmp
->tm_isdst
] = &sp
->chars
[ttisp
->tt_abbrind
];
1083 tmp
->TM_ZONE
= &sp
->chars
[ttisp
->tt_abbrind
];
1084 #endif /* defined TM_ZONE */
1088 localtime_r(timep
, p_tm
)
1089 const time_t * const timep
;
1093 pthread_mutex_lock(&lcl_mutex
);
1096 localsub(timep
, 0L, p_tm
);
1098 pthread_mutex_unlock(&lcl_mutex
);
1105 const time_t * const timep
;
1108 static struct pthread_mutex _localtime_mutex
= PTHREAD_MUTEX_STATIC_INITIALIZER
;
1109 static pthread_mutex_t localtime_mutex
= &_localtime_mutex
;
1110 static pthread_key_t localtime_key
= -1;
1113 pthread_mutex_lock(&localtime_mutex
);
1114 if (localtime_key
< 0) {
1115 if (pthread_key_create(&localtime_key
, free
) < 0) {
1116 pthread_mutex_unlock(&localtime_mutex
);
1120 pthread_mutex_unlock(&localtime_mutex
);
1121 p_tm
= pthread_getspecific(localtime_key
);
1123 if ((p_tm
= (struct tm
*)malloc(sizeof(struct tm
))) == NULL
)
1125 pthread_setspecific(localtime_key
, p_tm
);
1127 pthread_mutex_lock(&lcl_mutex
);
1129 localsub(timep
, 0L, p_tm
);
1130 pthread_mutex_unlock(&lcl_mutex
);
1134 localsub(timep
, 0L, &tm
);
1140 ** gmtsub is to gmtime as localsub is to localtime.
1144 gmtsub(timep
, offset
, tmp
)
1145 const time_t * const timep
;
1147 struct tm
* const tmp
;
1150 pthread_mutex_lock(&gmt_mutex
);
1153 if( gmtptr
== NULL
)
1154 gmtptr
= (struct state
*) malloc(sizeof *gmtptr
);
1156 #endif /* defined ALL_STATE */
1159 pthread_mutex_unlock(&gmt_mutex
);
1161 timesub(timep
, offset
, gmtptr
, tmp
);
1164 ** Could get fancy here and deliver something such as
1165 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
1166 ** but this is no time for a treasure hunt.
1169 tmp
->TM_ZONE
= wildabbr
;
1174 else tmp
->TM_ZONE
= gmtptr
->chars
;
1175 #endif /* defined ALL_STATE */
1177 tmp
->TM_ZONE
= gmtptr
->chars
;
1178 #endif /* State Farm */
1180 #endif /* defined TM_ZONE */
1185 const time_t * const timep
;
1188 static struct pthread_mutex _gmtime_mutex
= PTHREAD_MUTEX_STATIC_INITIALIZER
;
1189 static pthread_mutex_t gmtime_mutex
= &_gmtime_mutex
;
1190 static pthread_key_t gmtime_key
= -1;
1193 pthread_mutex_lock(&gmtime_mutex
);
1194 if (gmtime_key
< 0) {
1195 if (pthread_key_create(&gmtime_key
, free
) < 0) {
1196 pthread_mutex_unlock(&gmtime_mutex
);
1200 pthread_mutex_unlock(&gmtime_mutex
);
1202 * Changed to follow draft 4 pthreads standard, which
1203 * is what BSD currently has.
1205 if ((p_tm
= pthread_getspecific(gmtime_key
)) == NULL
) {
1206 if ((p_tm
= (struct tm
*)malloc(sizeof(struct tm
))) == NULL
) {
1209 pthread_setspecific(gmtime_key
, p_tm
);
1211 gmtsub(timep
, 0L, p_tm
);
1214 gmtsub(timep
, 0L, &tm
);
1220 gmtime_r(const time_t * timep
, struct tm
* tm
)
1222 gmtsub(timep
, 0L, tm
);
1229 offtime(timep
, offset
)
1230 const time_t * const timep
;
1233 gmtsub(timep
, offset
, &tm
);
1237 #endif /* defined STD_INSPIRED */
1240 timesub(timep
, offset
, sp
, tmp
)
1241 const time_t * const timep
;
1243 register const struct state
* const sp
;
1244 register struct tm
* const tmp
;
1246 register const struct lsinfo
* lp
;
1251 register const int * ip
;
1259 i
= (sp
== NULL
) ? 0 : sp
->leapcnt
;
1260 #endif /* defined ALL_STATE */
1263 #endif /* State Farm */
1266 if (*timep
>= lp
->ls_trans
) {
1267 if (*timep
== lp
->ls_trans
) {
1268 hit
= ((i
== 0 && lp
->ls_corr
> 0) ||
1269 lp
->ls_corr
> sp
->lsis
[i
- 1].ls_corr
);
1272 sp
->lsis
[i
].ls_trans
==
1273 sp
->lsis
[i
- 1].ls_trans
+ 1 &&
1274 sp
->lsis
[i
].ls_corr
==
1275 sp
->lsis
[i
- 1].ls_corr
+ 1) {
1284 days
= *timep
/ SECSPERDAY
;
1285 rem
= *timep
% SECSPERDAY
;
1287 if (*timep
== 0x80000000) {
1289 ** A 3B1 muffs the division on the most negative number.
1294 #endif /* defined mc68k */
1295 rem
+= (offset
- corr
);
1300 while (rem
>= SECSPERDAY
) {
1304 tmp
->tm_hour
= (int) (rem
/ SECSPERHOUR
);
1305 rem
= rem
% SECSPERHOUR
;
1306 tmp
->tm_min
= (int) (rem
/ SECSPERMIN
);
1308 ** A positive leap second requires a special
1309 ** representation. This uses "... ??:59:60" et seq.
1311 tmp
->tm_sec
= (int) (rem
% SECSPERMIN
) + hit
;
1312 tmp
->tm_wday
= (int) ((EPOCH_WDAY
+ days
) % DAYSPERWEEK
);
1313 if (tmp
->tm_wday
< 0)
1314 tmp
->tm_wday
+= DAYSPERWEEK
;
1316 #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
1317 while (days
< 0 || days
>= (long) year_lengths
[yleap
= isleap(y
)]) {
1320 newy
= y
+ days
/ DAYSPERNYEAR
;
1323 days
-= (newy
- y
) * DAYSPERNYEAR
+
1324 LEAPS_THRU_END_OF(newy
- 1) -
1325 LEAPS_THRU_END_OF(y
- 1);
1328 tmp
->tm_year
= y
- TM_YEAR_BASE
;
1329 tmp
->tm_yday
= (int) days
;
1330 ip
= mon_lengths
[yleap
];
1331 for (tmp
->tm_mon
= 0; days
>= (long) ip
[tmp
->tm_mon
]; ++(tmp
->tm_mon
))
1332 days
= days
- (long) ip
[tmp
->tm_mon
];
1333 tmp
->tm_mday
= (int) (days
+ 1);
1336 tmp
->TM_GMTOFF
= offset
;
1337 #endif /* defined TM_GMTOFF */
1342 const time_t * const timep
;
1345 ** Section 4.12.3.2 of X3.159-1989 requires that
1346 ** The ctime funciton converts the calendar time pointed to by timer
1347 ** to local time in the form of a string. It is equivalent to
1348 ** asctime(localtime(timer))
1350 return asctime(localtime(timep
));
1355 const time_t * const timep
;
1359 return asctime_r(localtime_r(timep
, &tm
), buf
);
1363 ** Adapted from code provided by Robert Elz, who writes:
1364 ** The "best" way to do mktime I think is based on an idea of Bob
1365 ** Kridle's (so its said...) from a long time ago.
1366 ** [kridle@xinet.com as of 1996-01-16.]
1367 ** It does a binary search of the time_t space. Since time_t's are
1368 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
1369 ** would still be very reasonable).
1374 #endif /* !defined WRONG */
1377 ** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
1381 increment_overflow(number
, delta
)
1389 return (*number
< number0
) != (delta
< 0);
1393 normalize_overflow(tensptr
, unitsptr
, base
)
1394 int * const tensptr
;
1395 int * const unitsptr
;
1398 register int tensdelta
;
1400 tensdelta
= (*unitsptr
>= 0) ?
1401 (*unitsptr
/ base
) :
1402 (-1 - (-1 - *unitsptr
) / base
);
1403 *unitsptr
-= tensdelta
* base
;
1404 return increment_overflow(tensptr
, tensdelta
);
1409 register const struct tm
* const atmp
;
1410 register const struct tm
* const btmp
;
1412 register int result
;
1414 if ((result
= (atmp
->tm_year
- btmp
->tm_year
)) == 0 &&
1415 (result
= (atmp
->tm_mon
- btmp
->tm_mon
)) == 0 &&
1416 (result
= (atmp
->tm_mday
- btmp
->tm_mday
)) == 0 &&
1417 (result
= (atmp
->tm_hour
- btmp
->tm_hour
)) == 0 &&
1418 (result
= (atmp
->tm_min
- btmp
->tm_min
)) == 0)
1419 result
= atmp
->tm_sec
- btmp
->tm_sec
;
1424 time2(tmp
, funcp
, offset
, okayp
)
1425 struct tm
* const tmp
;
1426 void (* const funcp
) P((const time_t*, long, struct tm
*));
1430 register const struct state
* sp
;
1434 register int saved_seconds
;
1437 struct tm yourtm
, mytm
;
1441 if (normalize_overflow(&yourtm
.tm_hour
, &yourtm
.tm_min
, MINSPERHOUR
))
1443 if (normalize_overflow(&yourtm
.tm_mday
, &yourtm
.tm_hour
, HOURSPERDAY
))
1445 if (normalize_overflow(&yourtm
.tm_year
, &yourtm
.tm_mon
, MONSPERYEAR
))
1448 ** Turn yourtm.tm_year into an actual year number for now.
1449 ** It is converted back to an offset from TM_YEAR_BASE later.
1451 if (increment_overflow(&yourtm
.tm_year
, TM_YEAR_BASE
))
1453 while (yourtm
.tm_mday
<= 0) {
1454 if (increment_overflow(&yourtm
.tm_year
, -1))
1456 i
= yourtm
.tm_year
+ (1 < yourtm
.tm_mon
);
1457 yourtm
.tm_mday
+= year_lengths
[isleap(i
)];
1459 while (yourtm
.tm_mday
> DAYSPERLYEAR
) {
1460 i
= yourtm
.tm_year
+ (1 < yourtm
.tm_mon
);
1461 yourtm
.tm_mday
-= year_lengths
[isleap(i
)];
1462 if (increment_overflow(&yourtm
.tm_year
, 1))
1466 i
= mon_lengths
[isleap(yourtm
.tm_year
)][yourtm
.tm_mon
];
1467 if (yourtm
.tm_mday
<= i
)
1469 yourtm
.tm_mday
-= i
;
1470 if (++yourtm
.tm_mon
>= MONSPERYEAR
) {
1472 if (increment_overflow(&yourtm
.tm_year
, 1))
1476 if (increment_overflow(&yourtm
.tm_year
, -TM_YEAR_BASE
))
1478 if (yourtm
.tm_year
+ TM_YEAR_BASE
< EPOCH_YEAR
) {
1480 ** We can't set tm_sec to 0, because that might push the
1481 ** time below the minimum representable time.
1482 ** Set tm_sec to 59 instead.
1483 ** This assumes that the minimum representable time is
1484 ** not in the same minute that a leap second was deleted from,
1485 ** which is a safer assumption than using 58 would be.
1487 if (increment_overflow(&yourtm
.tm_sec
, 1 - SECSPERMIN
))
1489 saved_seconds
= yourtm
.tm_sec
;
1490 yourtm
.tm_sec
= SECSPERMIN
- 1;
1492 saved_seconds
= yourtm
.tm_sec
;
1496 ** Divide the search space in half
1497 ** (this works whether time_t is signed or unsigned).
1499 bits
= TYPE_BIT(time_t) - 1;
1501 ** If time_t is signed, then 0 is just above the median,
1502 ** assuming two's complement arithmetic.
1503 ** If time_t is unsigned, then (1 << bits) is just above the median.
1505 t
= TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits
);
1507 (*funcp
)(&t
, offset
, &mytm
);
1508 dir
= tmcomp(&mytm
, &yourtm
);
1513 --t
; /* may be needed if new t is minimal */
1515 t
-= ((time_t) 1) << bits
;
1516 else t
+= ((time_t) 1) << bits
;
1519 if (yourtm
.tm_isdst
< 0 || mytm
.tm_isdst
== yourtm
.tm_isdst
)
1522 ** Right time, wrong type.
1523 ** Hunt for right time, right type.
1524 ** It's okay to guess wrong since the guess
1528 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
1530 sp
= (const struct state
*)
1531 (((void *) funcp
== (void *) localsub
) ?
1536 #endif /* defined ALL_STATE */
1537 for (i
= sp
->typecnt
- 1; i
>= 0; --i
) {
1538 if (sp
->ttis
[i
].tt_isdst
!= yourtm
.tm_isdst
)
1540 for (j
= sp
->typecnt
- 1; j
>= 0; --j
) {
1541 if (sp
->ttis
[j
].tt_isdst
== yourtm
.tm_isdst
)
1543 newt
= t
+ sp
->ttis
[j
].tt_gmtoff
-
1544 sp
->ttis
[i
].tt_gmtoff
;
1545 (*funcp
)(&newt
, offset
, &mytm
);
1546 if (tmcomp(&mytm
, &yourtm
) != 0)
1548 if (mytm
.tm_isdst
!= yourtm
.tm_isdst
)
1560 newt
= t
+ saved_seconds
;
1561 if ((newt
< t
) != (saved_seconds
< 0))
1564 (*funcp
)(&t
, offset
, tmp
);
1570 time1(tmp
, funcp
, offset
)
1571 struct tm
* const tmp
;
1572 void (* const funcp
) P((const time_t *, long, struct tm
*));
1576 register const struct state
* sp
;
1577 register int samei
, otheri
;
1580 if (tmp
->tm_isdst
> 1)
1582 t
= time2(tmp
, funcp
, offset
, &okay
);
1585 ** PCTS code courtesy Grant Sullivan (grant@osf.org).
1589 if (tmp
->tm_isdst
< 0)
1590 tmp
->tm_isdst
= 0; /* reset to std and try again */
1591 #endif /* defined PCTS */
1593 if (okay
|| tmp
->tm_isdst
< 0)
1595 #endif /* !defined PCTS */
1597 ** We're supposed to assume that somebody took a time of one type
1598 ** and did some math on it that yielded a "struct tm" that's bad.
1599 ** We try to divine the type they started from and adjust to the
1603 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
1605 sp
= (const struct state
*) (((void *) funcp
== (void *) localsub
) ?
1610 #endif /* defined ALL_STATE */
1611 for (samei
= sp
->typecnt
- 1; samei
>= 0; --samei
) {
1612 if (sp
->ttis
[samei
].tt_isdst
!= tmp
->tm_isdst
)
1614 for (otheri
= sp
->typecnt
- 1; otheri
>= 0; --otheri
) {
1615 if (sp
->ttis
[otheri
].tt_isdst
== tmp
->tm_isdst
)
1617 tmp
->tm_sec
+= sp
->ttis
[otheri
].tt_gmtoff
-
1618 sp
->ttis
[samei
].tt_gmtoff
;
1619 tmp
->tm_isdst
= !tmp
->tm_isdst
;
1620 t
= time2(tmp
, funcp
, offset
, &okay
);
1623 tmp
->tm_sec
-= sp
->ttis
[otheri
].tt_gmtoff
-
1624 sp
->ttis
[samei
].tt_gmtoff
;
1625 tmp
->tm_isdst
= !tmp
->tm_isdst
;
1633 struct tm
* const tmp
;
1635 time_t mktime_return_value
;
1637 pthread_mutex_lock(&lcl_mutex
);
1640 mktime_return_value
= time1(tmp
, localsub
, 0L);
1642 pthread_mutex_unlock(&lcl_mutex
);
1644 return(mktime_return_value
);
1651 struct tm
* const tmp
;
1653 tmp
->tm_isdst
= -1; /* in case it wasn't initialized */
1659 struct tm
* const tmp
;
1662 return time1(tmp
, gmtsub
, 0L);
1666 timeoff(tmp
, offset
)
1667 struct tm
* const tmp
;
1671 return time1(tmp
, gmtsub
, offset
);
1674 #endif /* defined STD_INSPIRED */
1679 ** The following is supplied for compatibility with
1680 ** previous versions of the CMUCS runtime library.
1685 struct tm
* const tmp
;
1687 const time_t t
= mktime(tmp
);
1694 #endif /* defined CMUCS */
1697 ** XXX--is the below the right way to conditionalize??
1703 ** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
1704 ** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which
1705 ** is not the case if we are accounting for leap seconds.
1706 ** So, we provide the following conversion routines for use
1707 ** when exchanging timestamps with POSIX conforming systems.
1714 register struct state
* sp
;
1715 register struct lsinfo
* lp
;
1722 if (*timep
>= lp
->ls_trans
)
1733 return t
- leapcorr(&t
);
1745 ** For a positive leap second hit, the result
1746 ** is not unique. For a negative leap second
1747 ** hit, the corresponding time doesn't exist,
1748 ** so we return an adjacent second.
1750 x
= t
+ leapcorr(&t
);
1751 y
= x
- leapcorr(&x
);
1755 y
= x
- leapcorr(&x
);
1762 y
= x
- leapcorr(&x
);
1770 #endif /* defined STD_INSPIRED */