1 /* $NetBSD: localtime.c,v 1.54 2011/01/15 15:42:10 christos Exp $ */
4 ** This file is in the public domain, so clarified as of
5 ** 1996-06-05 by Arthur David Olson.
9 #if defined(LIBC_SCCS) && !defined(lint)
11 static char elsieid
[] = "@(#)localtime.c 8.9";
13 __RCSID("$NetBSD: localtime.c,v 1.54 2011/01/15 15:42:10 christos Exp $");
15 #endif /* LIBC_SCCS and not lint */
18 ** Leap second handling from Bradley White.
19 ** POSIX-style TZ environment variable handling from Guy Harris.
24 #include "namespace.h"
28 #include "reentrant.h"
30 #if defined(__weak_alias)
31 __weak_alias(ctime_r
,_ctime_r
)
32 __weak_alias(ctime_rz
,_ctime_rz
)
33 __weak_alias(daylight
,_daylight
)
34 __weak_alias(mktime_z
,_mktime_z
)
35 __weak_alias(localtime_r
,_localtime_r
)
36 __weak_alias(localtime_rz
,_localtime_rz
)
37 __weak_alias(posix2time
,_posix2time
)
38 __weak_alias(posix2time_z
,_posix2time_z
)
39 __weak_alias(tzname
,_tzname
)
42 #include "float.h" /* for FLT_MAX and DBL_MAX */
44 #ifndef TZ_ABBR_MAX_LEN
45 #define TZ_ABBR_MAX_LEN 16
46 #endif /* !defined TZ_ABBR_MAX_LEN */
48 #ifndef TZ_ABBR_CHAR_SET
49 #define TZ_ABBR_CHAR_SET \
50 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
51 #endif /* !defined TZ_ABBR_CHAR_SET */
53 #ifndef TZ_ABBR_ERR_CHAR
54 #define TZ_ABBR_ERR_CHAR '_'
55 #endif /* !defined TZ_ABBR_ERR_CHAR */
58 ** SunOS 4.1.1 headers lack O_BINARY.
62 #define OPEN_MODE (O_RDONLY | O_BINARY)
63 #endif /* defined O_BINARY */
65 #define OPEN_MODE O_RDONLY
66 #endif /* !defined O_BINARY */
70 ** Someone might make incorrect use of a time zone abbreviation:
71 ** 1. They might reference tzname[0] before calling tzset (explicitly
73 ** 2. They might reference tzname[1] before calling tzset (explicitly
75 ** 3. They might reference tzname[1] after setting to a time zone
76 ** in which Daylight Saving Time is never observed.
77 ** 4. They might reference tzname[0] after setting to a time zone
78 ** in which Standard Time is never observed.
79 ** 5. They might reference tm.TM_ZONE after calling offtime.
80 ** What's best to do in the above cases is open to debate;
81 ** for now, we just set things up so that in any of the five cases
82 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
83 ** string "tzname[0] used before set", and similarly for the other cases.
84 ** And another: initialize tzname[0] to "ERA", with an explanation in the
85 ** manual page of what this "time zone abbreviation" means (doing this so
86 ** that tzname[0] has the "normal" length of three characters).
89 #endif /* !defined WILDABBR */
91 static const char wildabbr
[] = WILDABBR
;
93 static char gmt
[] = "GMT";
96 ** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
97 ** We default to US rules as of 1999-08-17.
98 ** POSIX 1003.1 section 8.1.1 says that the default DST rules are
99 ** implementation dependent; for historical reasons, US rules are a
102 #ifndef TZDEFRULESTRING
103 #define TZDEFRULESTRING ",M4.1.0,M10.5.0"
104 #endif /* !defined TZDEFDST */
106 struct ttinfo
{ /* time type information */
107 long tt_gmtoff
; /* UTC offset in seconds */
108 int tt_isdst
; /* used to set tm_isdst */
109 int tt_abbrind
; /* abbreviation list index */
110 int tt_ttisstd
; /* TRUE if transition is std time */
111 int tt_ttisgmt
; /* TRUE if transition is UTC */
114 struct lsinfo
{ /* leap second information */
115 time_t ls_trans
; /* transition time */
116 long ls_corr
; /* correction to apply */
119 #define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
122 #define MY_TZNAME_MAX TZNAME_MAX
123 #endif /* defined TZNAME_MAX */
125 #define MY_TZNAME_MAX 255
126 #endif /* !defined TZNAME_MAX */
135 time_t ats
[TZ_MAX_TIMES
];
136 unsigned char types
[TZ_MAX_TIMES
];
137 struct ttinfo ttis
[TZ_MAX_TYPES
];
138 char chars
[/*CONSTCOND*/BIGGEST(BIGGEST(TZ_MAX_CHARS
+ 1, sizeof gmt
),
139 (2 * (MY_TZNAME_MAX
+ 1)))];
140 struct lsinfo lsis
[TZ_MAX_LEAPS
];
144 int r_type
; /* type of rule--see below */
145 int r_day
; /* day number of rule */
146 int r_week
; /* week number of rule */
147 int r_mon
; /* month number of rule */
148 long r_time
; /* transition time of rule */
151 #define JULIAN_DAY 0 /* Jn - Julian day */
152 #define DAY_OF_YEAR 1 /* n - day of year */
153 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
155 typedef struct tm
*(*subfun_t
)(const timezone_t sp
, const time_t *timep
,
156 long offset
, struct tm
*tmp
);
159 ** Prototypes for static functions.
162 static long detzcode(const char * codep
);
163 static time_t detzcode64(const char * codep
);
164 static int differ_by_repeat(time_t t1
, time_t t0
);
165 static const char * getzname(const char * strp
);
166 static const char * getqzname(const char * strp
, const int delim
);
167 static const char * getnum(const char * strp
, int * nump
, int min
,
169 static const char * getsecs(const char * strp
, long * secsp
);
170 static const char * getoffset(const char * strp
, long * offsetp
);
171 static const char * getrule(const char * strp
, struct rule
* rulep
);
172 static void gmtload(timezone_t sp
);
173 static struct tm
* gmtsub(const timezone_t sp
, const time_t *timep
,
174 long offset
, struct tm
* tmp
);
175 static struct tm
* localsub(const timezone_t sp
, const time_t *timep
,
176 long offset
, struct tm
*tmp
);
177 static int increment_overflow(int * number
, int delta
);
178 static int leaps_thru_end_of(int y
);
179 static int long_increment_overflow(long * number
, int delta
);
180 static int long_normalize_overflow(long * tensptr
,
181 int * unitsptr
, int base
);
182 static int normalize_overflow(int * tensptr
, int * unitsptr
,
184 static void settzname(void);
185 static time_t time1(const timezone_t sp
, struct tm
* const tmp
,
186 subfun_t funcp
, long offset
);
187 static time_t time2(const timezone_t sp
, struct tm
* const tmp
,
189 const long offset
, int *const okayp
);
190 static time_t time2sub(const timezone_t sp
, struct tm
* consttmp
,
191 subfun_t funcp
, const long offset
,
192 int *const okayp
, const int do_norm_secs
);
193 static struct tm
* timesub(const timezone_t sp
, const time_t * timep
,
194 long offset
, struct tm
* tmp
);
195 static int tmcomp(const struct tm
* atmp
,
196 const struct tm
* btmp
);
197 static time_t transtime(time_t janfirst
, int year
,
198 const struct rule
* rulep
, long offset
);
199 static int typesequiv(const timezone_t sp
, int a
, int b
);
200 static int tzload(timezone_t sp
, const char * name
,
202 static int tzparse(timezone_t sp
, const char * name
,
204 static void tzset_unlocked(void);
205 static void tzsetwall_unlocked(void);
206 static long leapcorr(const timezone_t sp
, time_t * timep
);
208 static timezone_t lclptr
;
209 static timezone_t gmtptr
;
211 #ifndef TZ_STRLEN_MAX
212 #define TZ_STRLEN_MAX 255
213 #endif /* !defined TZ_STRLEN_MAX */
215 static char lcl_TZname
[TZ_STRLEN_MAX
+ 1];
216 static int lcl_is_set
;
217 static int gmt_is_set
;
219 #if !defined(__LIBC12_SOURCE__)
221 __aconst
char * tzname
[2] = {
222 (__aconst
char *)__UNCONST(wildabbr
),
223 (__aconst
char *)__UNCONST(wildabbr
)
228 extern __aconst
char * tzname
[2];
233 static rwlock_t lcl_lock
= RWLOCK_INITIALIZER
;
237 ** Section 4.12.3 of X3.159-1989 requires that
238 ** Except for the strftime function, these functions [asctime,
239 ** ctime, gmtime, localtime] return values in one of two static
240 ** objects: a broken-down time structure and an array of char.
241 ** Thanks to Paul Eggert for noting this.
247 #if !defined(__LIBC12_SOURCE__)
252 extern long timezone
__RENAME(__timezone13
);
254 #endif /* defined USG_COMPAT */
258 #endif /* defined ALTZONE */
261 detzcode(const char *const codep
)
266 result
= (codep
[0] & 0x80) ? ~0L : 0;
267 for (i
= 0; i
< 4; ++i
)
268 result
= (result
<< 8) | (codep
[i
] & 0xff);
273 detzcode64(const char *const codep
)
278 result
= (codep
[0] & 0x80) ? -1 : 0;
279 for (i
= 0; i
< 8; ++i
)
280 result
= result
* 256 + (codep
[i
] & 0xff);
285 tzgetname(const timezone_t sp
, int isdst
)
288 for (i
= 0; i
< sp
->timecnt
; ++i
) {
289 const struct ttinfo
*const ttisp
= &sp
->ttis
[sp
->types
[i
]];
291 if (ttisp
->tt_isdst
== isdst
)
292 return &sp
->chars
[ttisp
->tt_abbrind
];
298 settzname_z(timezone_t sp
)
303 ** Scrub the abbreviations.
304 ** First, replace bogus characters.
306 for (i
= 0; i
< sp
->charcnt
; ++i
)
307 if (strchr(TZ_ABBR_CHAR_SET
, sp
->chars
[i
]) == NULL
)
308 sp
->chars
[i
] = TZ_ABBR_ERR_CHAR
;
310 ** Second, truncate long abbreviations.
312 for (i
= 0; i
< sp
->typecnt
; ++i
) {
313 const struct ttinfo
* const ttisp
= &sp
->ttis
[i
];
314 char * cp
= &sp
->chars
[ttisp
->tt_abbrind
];
316 if (strlen(cp
) > TZ_ABBR_MAX_LEN
&&
317 strcmp(cp
, GRANDPARENTED
) != 0)
318 *(cp
+ TZ_ABBR_MAX_LEN
) = '\0';
325 timezone_t
const sp
= lclptr
;
328 tzname
[0] = (__aconst
char *)__UNCONST(wildabbr
);
329 tzname
[1] = (__aconst
char *)__UNCONST(wildabbr
);
333 #endif /* defined USG_COMPAT */
336 #endif /* defined ALTZONE */
338 tzname
[0] = tzname
[1] = (__aconst
char *)__UNCONST(gmt
);
341 for (i
= 0; i
< sp
->typecnt
; ++i
) {
342 const struct ttinfo
* const ttisp
= &sp
->ttis
[i
];
344 tzname
[ttisp
->tt_isdst
] =
345 &sp
->chars
[ttisp
->tt_abbrind
];
349 if (i
== 0 || !ttisp
->tt_isdst
)
350 timezone
= -(ttisp
->tt_gmtoff
);
351 #endif /* defined USG_COMPAT */
353 if (i
== 0 || ttisp
->tt_isdst
)
354 altzone
= -(ttisp
->tt_gmtoff
);
355 #endif /* defined ALTZONE */
358 ** And to get the latest zone names into tzname. . .
360 for (i
= 0; i
< sp
->timecnt
; ++i
) {
361 register const struct ttinfo
* const ttisp
=
365 tzname
[ttisp
->tt_isdst
] =
366 &sp
->chars
[ttisp
->tt_abbrind
];
372 differ_by_repeat(const time_t t1
, const time_t t0
)
375 if (TYPE_INTEGRAL(time_t) &&
376 TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS
)
378 return (int_fast64_t)t1
- (int_fast64_t)t0
== SECSPERREPEAT
;
382 tzload(timezone_t sp
, const char *name
, const int doextend
)
390 struct tzhead tzhead
;
391 char buf
[2 * sizeof(struct tzhead
) +
396 sp
->goback
= sp
->goahead
= FALSE
;
397 if (name
== NULL
&& (name
= TZDEFAULT
) == NULL
)
402 ** Section 4.9.1 of the C standard says that
403 ** "FILENAME_MAX expands to an integral constant expression
404 ** that is the size needed for an array of char large enough
405 ** to hold the longest file name string that the implementation
406 ** guarantees can be opened."
408 char fullname
[FILENAME_MAX
+ 1];
412 doaccess
= name
[0] == '/';
414 if ((p
= TZDIR
) == NULL
)
416 if ((strlen(p
) + strlen(name
) + 1) >= sizeof fullname
)
418 (void) strcpy(fullname
, p
); /* XXX strcpy is safe */
419 (void) strcat(fullname
, "/"); /* XXX strcat is safe */
420 (void) strcat(fullname
, name
); /* XXX strcat is safe */
422 ** Set doaccess if '.' (as in "../") shows up in name.
424 if (strchr(name
, '.') != NULL
)
428 if (doaccess
&& access(name
, R_OK
) != 0)
431 * XXX potential security problem here if user of a set-id
432 * program has set TZ (which is passed in as name) here,
433 * and uses a race condition trick to defeat the access(2)
436 if ((fid
= open(name
, OPEN_MODE
)) == -1)
439 nread
= read(fid
, u
.buf
, sizeof u
.buf
);
440 if (close(fid
) < 0 || nread
<= 0)
442 for (stored
= 4; stored
<= 8; stored
*= 2) {
446 ttisstdcnt
= (int) detzcode(u
.tzhead
.tzh_ttisstdcnt
);
447 ttisgmtcnt
= (int) detzcode(u
.tzhead
.tzh_ttisgmtcnt
);
448 sp
->leapcnt
= (int) detzcode(u
.tzhead
.tzh_leapcnt
);
449 sp
->timecnt
= (int) detzcode(u
.tzhead
.tzh_timecnt
);
450 sp
->typecnt
= (int) detzcode(u
.tzhead
.tzh_typecnt
);
451 sp
->charcnt
= (int) detzcode(u
.tzhead
.tzh_charcnt
);
452 p
= u
.tzhead
.tzh_charcnt
+ sizeof u
.tzhead
.tzh_charcnt
;
453 if (sp
->leapcnt
< 0 || sp
->leapcnt
> TZ_MAX_LEAPS
||
454 sp
->typecnt
<= 0 || sp
->typecnt
> TZ_MAX_TYPES
||
455 sp
->timecnt
< 0 || sp
->timecnt
> TZ_MAX_TIMES
||
456 sp
->charcnt
< 0 || sp
->charcnt
> TZ_MAX_CHARS
||
457 (ttisstdcnt
!= sp
->typecnt
&& ttisstdcnt
!= 0) ||
458 (ttisgmtcnt
!= sp
->typecnt
&& ttisgmtcnt
!= 0))
460 if (nread
- (p
- u
.buf
) <
461 sp
->timecnt
* stored
+ /* ats */
462 sp
->timecnt
+ /* types */
463 sp
->typecnt
* 6 + /* ttinfos */
464 sp
->charcnt
+ /* chars */
465 sp
->leapcnt
* (stored
+ 4) + /* lsinfos */
466 ttisstdcnt
+ /* ttisstds */
467 ttisgmtcnt
) /* ttisgmts */
469 for (i
= 0; i
< sp
->timecnt
; ++i
) {
470 sp
->ats
[i
] = (stored
== 4) ?
471 detzcode(p
) : detzcode64(p
);
474 for (i
= 0; i
< sp
->timecnt
; ++i
) {
475 sp
->types
[i
] = (unsigned char) *p
++;
476 if (sp
->types
[i
] >= sp
->typecnt
)
479 for (i
= 0; i
< sp
->typecnt
; ++i
) {
480 struct ttinfo
* ttisp
;
482 ttisp
= &sp
->ttis
[i
];
483 ttisp
->tt_gmtoff
= detzcode(p
);
485 ttisp
->tt_isdst
= (unsigned char) *p
++;
486 if (ttisp
->tt_isdst
!= 0 && ttisp
->tt_isdst
!= 1)
488 ttisp
->tt_abbrind
= (unsigned char) *p
++;
489 if (ttisp
->tt_abbrind
< 0 ||
490 ttisp
->tt_abbrind
> sp
->charcnt
)
493 for (i
= 0; i
< sp
->charcnt
; ++i
)
495 sp
->chars
[i
] = '\0'; /* ensure '\0' at end */
496 for (i
= 0; i
< sp
->leapcnt
; ++i
) {
497 struct lsinfo
* lsisp
;
499 lsisp
= &sp
->lsis
[i
];
500 lsisp
->ls_trans
= (stored
== 4) ?
501 detzcode(p
) : detzcode64(p
);
503 lsisp
->ls_corr
= detzcode(p
);
506 for (i
= 0; i
< sp
->typecnt
; ++i
) {
507 struct ttinfo
* ttisp
;
509 ttisp
= &sp
->ttis
[i
];
511 ttisp
->tt_ttisstd
= FALSE
;
513 ttisp
->tt_ttisstd
= *p
++;
514 if (ttisp
->tt_ttisstd
!= TRUE
&&
515 ttisp
->tt_ttisstd
!= FALSE
)
519 for (i
= 0; i
< sp
->typecnt
; ++i
) {
520 struct ttinfo
* ttisp
;
522 ttisp
= &sp
->ttis
[i
];
524 ttisp
->tt_ttisgmt
= FALSE
;
526 ttisp
->tt_ttisgmt
= *p
++;
527 if (ttisp
->tt_ttisgmt
!= TRUE
&&
528 ttisp
->tt_ttisgmt
!= FALSE
)
533 ** Out-of-sort ats should mean we're running on a
534 ** signed time_t system but using a data file with
535 ** unsigned values (or vice versa).
537 for (i
= 0; i
< sp
->timecnt
- 2; ++i
)
538 if (sp
->ats
[i
] > sp
->ats
[i
+ 1]) {
541 if (TYPE_SIGNED(time_t)) {
543 ** Ignore the end (easy).
548 ** Ignore the beginning (harder).
552 for (j
= 0; j
+ i
< sp
->timecnt
; ++j
) {
553 sp
->ats
[j
] = sp
->ats
[j
+ i
];
554 sp
->types
[j
] = sp
->types
[j
+ i
];
561 ** If this is an old file, we're done.
563 if (u
.tzhead
.tzh_version
[0] == '\0')
566 for (i
= 0; i
< nread
; ++i
)
569 ** If this is a narrow integer time_t system, we're done.
571 if (stored
>= (int) sizeof(time_t)
573 && TYPE_INTEGRAL(time_t))
576 if (doextend
&& nread
> 2 &&
577 u
.buf
[0] == '\n' && u
.buf
[nread
- 1] == '\n' &&
578 sp
->typecnt
+ 2 <= TZ_MAX_TYPES
) {
582 u
.buf
[nread
- 1] = '\0';
583 result
= tzparse(&ts
, &u
.buf
[1], FALSE
);
584 if (result
== 0 && ts
.typecnt
== 2 &&
585 sp
->charcnt
+ ts
.charcnt
<= TZ_MAX_CHARS
) {
586 for (i
= 0; i
< 2; ++i
)
587 ts
.ttis
[i
].tt_abbrind
+=
589 for (i
= 0; i
< ts
.charcnt
; ++i
)
590 sp
->chars
[sp
->charcnt
++] =
593 while (i
< ts
.timecnt
&&
595 sp
->ats
[sp
->timecnt
- 1])
597 while (i
< ts
.timecnt
&&
598 sp
->timecnt
< TZ_MAX_TIMES
) {
599 sp
->ats
[sp
->timecnt
] =
601 sp
->types
[sp
->timecnt
] =
607 sp
->ttis
[sp
->typecnt
++] = ts
.ttis
[0];
608 sp
->ttis
[sp
->typecnt
++] = ts
.ttis
[1];
611 if (sp
->timecnt
> 1) {
612 for (i
= 1; i
< sp
->timecnt
; ++i
)
613 if (typesequiv(sp
, sp
->types
[i
], sp
->types
[0]) &&
614 differ_by_repeat(sp
->ats
[i
], sp
->ats
[0])) {
618 for (i
= sp
->timecnt
- 2; i
>= 0; --i
)
619 if (typesequiv(sp
, sp
->types
[sp
->timecnt
- 1],
621 differ_by_repeat(sp
->ats
[sp
->timecnt
- 1],
631 typesequiv(const timezone_t sp
, const int a
, const int b
)
636 a
< 0 || a
>= sp
->typecnt
||
637 b
< 0 || b
>= sp
->typecnt
)
640 const struct ttinfo
* ap
= &sp
->ttis
[a
];
641 const struct ttinfo
* bp
= &sp
->ttis
[b
];
642 result
= ap
->tt_gmtoff
== bp
->tt_gmtoff
&&
643 ap
->tt_isdst
== bp
->tt_isdst
&&
644 ap
->tt_ttisstd
== bp
->tt_ttisstd
&&
645 ap
->tt_ttisgmt
== bp
->tt_ttisgmt
&&
646 strcmp(&sp
->chars
[ap
->tt_abbrind
],
647 &sp
->chars
[bp
->tt_abbrind
]) == 0;
652 static const int mon_lengths
[2][MONSPERYEAR
] = {
653 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
654 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
657 static const int year_lengths
[2] = {
658 DAYSPERNYEAR
, DAYSPERLYEAR
662 ** Given a pointer into a time zone string, scan until a character that is not
663 ** a valid character in a zone name is found. Return a pointer to that
673 while ((c
= *strp
) != '\0' && !is_digit(c
) && c
!= ',' && c
!= '-' &&
680 ** Given a pointer into an extended time zone string, scan until the ending
681 ** delimiter of the zone name is located. Return a pointer to the delimiter.
683 ** As with getzname above, the legal character set is actually quite
684 ** restricted, with other characters producing undefined results.
685 ** We don't do any checking here; checking is done later in common-case code.
689 getqzname(const char *strp
, const int delim
)
693 while ((c
= *strp
) != '\0' && c
!= delim
)
699 ** Given a pointer into a time zone string, extract a number from that string.
700 ** Check that the number is within a specified range; if it is not, return
702 ** Otherwise, return a pointer to the first character not part of the number.
706 getnum(strp
, nump
, min
, max
)
715 if (strp
== NULL
|| !is_digit(c
= *strp
)) {
721 num
= num
* 10 + (c
- '0');
724 return NULL
; /* illegal value */
727 } while (is_digit(c
));
730 return NULL
; /* illegal value */
737 ** Given a pointer into a time zone string, extract a number of seconds,
738 ** in hh[:mm[:ss]] form, from the string.
739 ** If any error occurs, return NULL.
740 ** Otherwise, return a pointer to the first character not part of the number
745 getsecs(const char *strp
, long *const secsp
)
750 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
751 ** "M10.4.6/26", which does not conform to Posix,
752 ** but which specifies the equivalent of
753 ** ``02:00 on the first Sunday on or after 23 Oct''.
755 strp
= getnum(strp
, &num
, 0, HOURSPERDAY
* DAYSPERWEEK
- 1);
758 *secsp
= num
* (long) SECSPERHOUR
;
761 strp
= getnum(strp
, &num
, 0, MINSPERHOUR
- 1);
764 *secsp
+= num
* SECSPERMIN
;
767 /* `SECSPERMIN' allows for leap seconds. */
768 strp
= getnum(strp
, &num
, 0, SECSPERMIN
);
778 ** Given a pointer into a time zone string, extract an offset, in
779 ** [+-]hh[:mm[:ss]] form, from the string.
780 ** If any error occurs, return NULL.
781 ** Otherwise, return a pointer to the first character not part of the time.
785 getoffset(const char *strp
, long *const offsetp
)
792 } else if (*strp
== '+')
794 strp
= getsecs(strp
, offsetp
);
796 return NULL
; /* illegal time */
798 *offsetp
= -*offsetp
;
803 ** Given a pointer into a time zone string, extract a rule in the form
804 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
805 ** If a valid rule is not found, return NULL.
806 ** Otherwise, return a pointer to the first character not part of the rule.
810 getrule(const char *strp
, struct rule
*const rulep
)
816 rulep
->r_type
= JULIAN_DAY
;
818 strp
= getnum(strp
, &rulep
->r_day
, 1, DAYSPERNYEAR
);
819 } else if (*strp
== 'M') {
823 rulep
->r_type
= MONTH_NTH_DAY_OF_WEEK
;
825 strp
= getnum(strp
, &rulep
->r_mon
, 1, MONSPERYEAR
);
830 strp
= getnum(strp
, &rulep
->r_week
, 1, 5);
835 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERWEEK
- 1);
836 } else if (is_digit(*strp
)) {
840 rulep
->r_type
= DAY_OF_YEAR
;
841 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERLYEAR
- 1);
842 } else return NULL
; /* invalid format */
850 strp
= getsecs(strp
, &rulep
->r_time
);
851 } else rulep
->r_time
= 2 * SECSPERHOUR
; /* default = 2:00:00 */
856 ** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
857 ** year, a rule, and the offset from UTC at the time that rule takes effect,
858 ** calculate the Epoch-relative time that rule takes effect.
862 transtime(const time_t janfirst
, const int year
, const struct rule
*const rulep
,
868 int d
, m1
, yy0
, yy1
, yy2
, dow
;
871 leapyear
= isleap(year
);
872 switch (rulep
->r_type
) {
876 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
878 ** In non-leap years, or if the day number is 59 or less, just
879 ** add SECSPERDAY times the day number-1 to the time of
880 ** January 1, midnight, to get the day.
882 value
= janfirst
+ (rulep
->r_day
- 1) * SECSPERDAY
;
883 if (leapyear
&& rulep
->r_day
>= 60)
890 ** Just add SECSPERDAY times the day number to the time of
891 ** January 1, midnight, to get the day.
893 value
= janfirst
+ rulep
->r_day
* SECSPERDAY
;
896 case MONTH_NTH_DAY_OF_WEEK
:
898 ** Mm.n.d - nth "dth day" of month m.
901 for (i
= 0; i
< rulep
->r_mon
- 1; ++i
)
902 value
+= mon_lengths
[leapyear
][i
] * SECSPERDAY
;
905 ** Use Zeller's Congruence to get day-of-week of first day of
908 m1
= (rulep
->r_mon
+ 9) % 12 + 1;
909 yy0
= (rulep
->r_mon
<= 2) ? (year
- 1) : year
;
912 dow
= ((26 * m1
- 2) / 10 +
913 1 + yy2
+ yy2
/ 4 + yy1
/ 4 - 2 * yy1
) % 7;
918 ** "dow" is the day-of-week of the first day of the month. Get
919 ** the day-of-month (zero-origin) of the first "dow" day of the
922 d
= rulep
->r_day
- dow
;
925 for (i
= 1; i
< rulep
->r_week
; ++i
) {
926 if (d
+ DAYSPERWEEK
>=
927 mon_lengths
[leapyear
][rulep
->r_mon
- 1])
933 ** "d" is the day-of-month (zero-origin) of the day we want.
935 value
+= d
* SECSPERDAY
;
940 ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
941 ** question. To get the Epoch-relative time of the specified local
942 ** time on that day, add the transition time and the current offset
945 return value
+ rulep
->r_time
+ offset
;
949 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
954 tzparse(timezone_t sp
, const char *name
, const int lastditch
)
956 const char * stdname
;
957 const char * dstname
;
963 unsigned char * typep
;
970 stdlen
= strlen(name
); /* length of standard zone name */
972 if (stdlen
>= sizeof sp
->chars
)
973 stdlen
= (sizeof sp
->chars
) - 1;
979 name
= getqzname(name
, '>');
982 stdlen
= name
- stdname
;
985 name
= getzname(name
);
986 stdlen
= name
- stdname
;
990 name
= getoffset(name
, &stdoffset
);
994 load_result
= tzload(sp
, TZDEFRULES
, FALSE
);
995 if (load_result
!= 0)
996 sp
->leapcnt
= 0; /* so, we're off a little */
1000 name
= getqzname(name
, '>');
1003 dstlen
= name
- dstname
;
1007 name
= getzname(name
);
1008 dstlen
= name
- dstname
; /* length of DST zone name */
1010 if (*name
!= '\0' && *name
!= ',' && *name
!= ';') {
1011 name
= getoffset(name
, &dstoffset
);
1014 } else dstoffset
= stdoffset
- SECSPERHOUR
;
1015 if (*name
== '\0' && load_result
!= 0)
1016 name
= TZDEFRULESTRING
;
1017 if (*name
== ',' || *name
== ';') {
1026 if ((name
= getrule(name
, &start
)) == NULL
)
1030 if ((name
= getrule(name
, &end
)) == NULL
)
1034 sp
->typecnt
= 2; /* standard time and DST */
1036 ** Two transitions per year, from EPOCH_YEAR forward.
1038 sp
->ttis
[0].tt_gmtoff
= -dstoffset
;
1039 sp
->ttis
[0].tt_isdst
= 1;
1040 sp
->ttis
[0].tt_abbrind
= stdlen
+ 1;
1041 sp
->ttis
[1].tt_gmtoff
= -stdoffset
;
1042 sp
->ttis
[1].tt_isdst
= 0;
1043 sp
->ttis
[1].tt_abbrind
= 0;
1048 for (year
= EPOCH_YEAR
;
1049 sp
->timecnt
+ 2 <= TZ_MAX_TIMES
;
1053 starttime
= transtime(janfirst
, year
, &start
,
1055 endtime
= transtime(janfirst
, year
, &end
,
1057 if (starttime
> endtime
) {
1059 *typep
++ = 1; /* DST ends */
1061 *typep
++ = 0; /* DST begins */
1064 *typep
++ = 0; /* DST begins */
1066 *typep
++ = 1; /* DST ends */
1069 newfirst
= janfirst
;
1070 newfirst
+= year_lengths
[isleap(year
)] *
1072 if (newfirst
<= janfirst
)
1074 janfirst
= newfirst
;
1077 long theirstdoffset
;
1078 long theirdstoffset
;
1087 ** Initial values of theirstdoffset
1090 for (i
= 0; i
< sp
->timecnt
; ++i
) {
1092 if (!sp
->ttis
[j
].tt_isdst
) {
1094 -sp
->ttis
[j
].tt_gmtoff
;
1099 for (i
= 0; i
< sp
->timecnt
; ++i
) {
1101 if (sp
->ttis
[j
].tt_isdst
) {
1103 -sp
->ttis
[j
].tt_gmtoff
;
1108 ** Initially we're assumed to be in standard time.
1111 theiroffset
= theirstdoffset
;
1113 ** Now juggle transition times and types
1114 ** tracking offsets as you do.
1116 for (i
= 0; i
< sp
->timecnt
; ++i
) {
1118 sp
->types
[i
] = sp
->ttis
[j
].tt_isdst
;
1119 if (sp
->ttis
[j
].tt_ttisgmt
) {
1120 /* No adjustment to transition time */
1123 ** If summer time is in effect, and the
1124 ** transition time was not specified as
1125 ** standard time, add the summer time
1126 ** offset to the transition time;
1127 ** otherwise, add the standard time
1128 ** offset to the transition time.
1131 ** Transitions from DST to DDST
1132 ** will effectively disappear since
1133 ** POSIX provides for only one DST
1136 if (isdst
&& !sp
->ttis
[j
].tt_ttisstd
) {
1137 sp
->ats
[i
] += dstoffset
-
1140 sp
->ats
[i
] += stdoffset
-
1144 theiroffset
= -sp
->ttis
[j
].tt_gmtoff
;
1145 if (!sp
->ttis
[j
].tt_isdst
)
1146 theirstdoffset
= theiroffset
;
1147 else theirdstoffset
= theiroffset
;
1150 ** Finally, fill in ttis.
1151 ** ttisstd and ttisgmt need not be handled.
1153 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
1154 sp
->ttis
[0].tt_isdst
= FALSE
;
1155 sp
->ttis
[0].tt_abbrind
= 0;
1156 sp
->ttis
[1].tt_gmtoff
= -dstoffset
;
1157 sp
->ttis
[1].tt_isdst
= TRUE
;
1158 sp
->ttis
[1].tt_abbrind
= stdlen
+ 1;
1163 sp
->typecnt
= 1; /* only standard time */
1165 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
1166 sp
->ttis
[0].tt_isdst
= 0;
1167 sp
->ttis
[0].tt_abbrind
= 0;
1169 sp
->charcnt
= stdlen
+ 1;
1171 sp
->charcnt
+= dstlen
+ 1;
1172 if ((size_t) sp
->charcnt
> sizeof sp
->chars
)
1175 (void) strncpy(cp
, stdname
, stdlen
);
1179 (void) strncpy(cp
, dstname
, dstlen
);
1180 *(cp
+ dstlen
) = '\0';
1186 gmtload(timezone_t sp
)
1188 if (tzload(sp
, gmt
, TRUE
) != 0)
1189 (void) tzparse(sp
, gmt
, TRUE
);
1193 tzalloc(const char *name
)
1195 timezone_t sp
= calloc(1, sizeof *sp
);
1198 if (tzload(sp
, name
, TRUE
) != 0) {
1207 tzfree(const timezone_t sp
)
1213 tzsetwall_unlocked(void)
1219 if (lclptr
== NULL
) {
1220 int saveerrno
= errno
;
1221 lclptr
= calloc(1, sizeof *lclptr
);
1223 if (lclptr
== NULL
) {
1224 settzname(); /* all we can do */
1228 if (tzload(lclptr
, NULL
, TRUE
) != 0)
1233 #ifndef STD_INSPIRED
1235 ** A non-static declaration of tzsetwall in a system header file
1236 ** may cause a warning about this upcoming static declaration...
1239 #endif /* !defined STD_INSPIRED */
1243 rwlock_wrlock(&lcl_lock
);
1244 tzsetwall_unlocked();
1245 rwlock_unlock(&lcl_lock
);
1248 #ifndef STD_INSPIRED
1250 ** A non-static declaration of tzsetwall in a system header file
1251 ** may cause a warning about this upcoming static declaration...
1254 #endif /* !defined STD_INSPIRED */
1256 tzset_unlocked(void)
1262 name
= getenv("TZ");
1265 tzsetwall_unlocked();
1269 if (lcl_is_set
> 0 && strcmp(lcl_TZname
, name
) == 0)
1271 lcl_is_set
= strlen(name
) < sizeof lcl_TZname
;
1273 (void)strlcpy(lcl_TZname
, name
, sizeof(lcl_TZname
));
1275 if (lclptr
== NULL
) {
1277 lclptr
= calloc(1, sizeof *lclptr
);
1279 if (lclptr
== NULL
) {
1280 settzname(); /* all we can do */
1284 if (*name
== '\0') {
1286 ** User wants it fast rather than right.
1288 lclptr
->leapcnt
= 0; /* so, we're off a little */
1289 lclptr
->timecnt
= 0;
1290 lclptr
->typecnt
= 0;
1291 lclptr
->ttis
[0].tt_isdst
= 0;
1292 lclptr
->ttis
[0].tt_gmtoff
= 0;
1293 lclptr
->ttis
[0].tt_abbrind
= 0;
1294 (void) strlcpy(lclptr
->chars
, gmt
, sizeof(lclptr
->chars
));
1295 } else if (tzload(lclptr
, name
, TRUE
) != 0)
1296 if (name
[0] == ':' || tzparse(lclptr
, name
, FALSE
) != 0)
1297 (void) gmtload(lclptr
);
1304 rwlock_wrlock(&lcl_lock
);
1306 rwlock_unlock(&lcl_lock
);
1310 ** The easy way to behave "as if no library function calls" localtime
1311 ** is to not call it--so we drop its guts into "localsub", which can be
1312 ** freely called. (And no, the PANS doesn't require the above behavior--
1313 ** but it *is* desirable.)
1315 ** The unused offset argument is for the benefit of mktime variants.
1320 localsub(const timezone_t sp
, const time_t * const timep
, const long offset
,
1321 struct tm
*const tmp
)
1323 const struct ttinfo
* ttisp
;
1326 const time_t t
= *timep
;
1328 if ((sp
->goback
&& t
< sp
->ats
[0]) ||
1329 (sp
->goahead
&& t
> sp
->ats
[sp
->timecnt
- 1])) {
1333 int_fast64_t icycles
;
1336 seconds
= sp
->ats
[0] - t
;
1337 else seconds
= t
- sp
->ats
[sp
->timecnt
- 1];
1339 tcycles
= seconds
/ YEARSPERREPEAT
/ AVGSECSPERYEAR
;
1342 if (tcycles
- icycles
>= 1 || icycles
- tcycles
>= 1)
1344 seconds
= (time_t) icycles
;
1345 seconds
*= YEARSPERREPEAT
;
1346 seconds
*= AVGSECSPERYEAR
;
1349 else newt
-= seconds
;
1350 if (newt
< sp
->ats
[0] ||
1351 newt
> sp
->ats
[sp
->timecnt
- 1])
1352 return NULL
; /* "cannot happen" */
1353 result
= localsub(sp
, &newt
, offset
, tmp
);
1354 if (result
== tmp
) {
1357 newy
= tmp
->tm_year
;
1359 newy
-= (time_t)icycles
* YEARSPERREPEAT
;
1360 else newy
+= (time_t)icycles
* YEARSPERREPEAT
;
1361 tmp
->tm_year
= (int)newy
;
1362 if (tmp
->tm_year
!= newy
)
1367 if (sp
->timecnt
== 0 || t
< sp
->ats
[0]) {
1369 while (sp
->ttis
[i
].tt_isdst
)
1370 if (++i
>= sp
->typecnt
) {
1376 int hi
= sp
->timecnt
;
1379 int mid
= (lo
+ hi
) / 2;
1381 if (t
< sp
->ats
[mid
])
1385 i
= (int) sp
->types
[lo
- 1];
1387 ttisp
= &sp
->ttis
[i
];
1389 ** To get (wrong) behavior that's compatible with System V Release 2.0
1390 ** you'd replace the statement below with
1391 ** t += ttisp->tt_gmtoff;
1392 ** timesub(&t, 0L, sp, tmp);
1394 result
= timesub(sp
, &t
, ttisp
->tt_gmtoff
, tmp
);
1395 tmp
->tm_isdst
= ttisp
->tt_isdst
;
1396 tzname
[tmp
->tm_isdst
] = &sp
->chars
[ttisp
->tt_abbrind
];
1398 tmp
->TM_ZONE
= &sp
->chars
[ttisp
->tt_abbrind
];
1399 #endif /* defined TM_ZONE */
1404 ** Re-entrant version of localtime.
1408 localtime_r(const time_t * __restrict timep
, struct tm
*tmp
)
1410 rwlock_rdlock(&lcl_lock
);
1412 tmp
= localtime_rz(lclptr
, timep
, tmp
);
1413 rwlock_unlock(&lcl_lock
);
1418 localtime(const time_t *const timep
)
1420 return localtime_r(timep
, &tm
);
1424 localtime_rz(const timezone_t sp
, const time_t * __restrict timep
, struct tm
*tmp
)
1427 tmp
= gmtsub(NULL
, timep
, 0L, tmp
);
1429 tmp
= localsub(sp
, timep
, 0L, tmp
);
1436 ** gmtsub is to gmtime as localsub is to localtime.
1440 gmtsub(const timezone_t sp
, const time_t * const timep
, const long offset
,
1441 struct tm
*const tmp
)
1445 static mutex_t gmt_mutex
= MUTEX_INITIALIZER
;
1448 mutex_lock(&gmt_mutex
);
1453 gmtptr
= calloc(1, sizeof *gmtptr
);
1458 mutex_unlock(&gmt_mutex
);
1459 result
= timesub(gmtptr
, timep
, offset
, tmp
);
1462 ** Could get fancy here and deliver something such as
1463 ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
1464 ** but this is no time for a treasure hunt.
1467 tmp
->TM_ZONE
= (__aconst
char *)__UNCONST(wildabbr
);
1470 tmp
->TM_ZONE
= (__aconst
char *)__UNCONST(gmt
);
1471 else tmp
->TM_ZONE
= gmtptr
->chars
;
1473 #endif /* defined TM_ZONE */
1478 gmtime(const time_t *const timep
)
1480 return gmtsub(NULL
, timep
, 0L, &tm
);
1484 ** Re-entrant version of gmtime.
1488 gmtime_r(const time_t * const timep
, struct tm
*tmp
)
1490 return gmtsub(NULL
, timep
, 0L, tmp
);
1496 offtime(const time_t *const timep
, long offset
)
1498 return gmtsub(NULL
, timep
, offset
, &tm
);
1502 offtime_r(const time_t *timep
, long offset
, struct tm
*tmp
)
1504 return gmtsub(NULL
, timep
, offset
, tmp
);
1507 #endif /* defined STD_INSPIRED */
1510 ** Return the number of leap years through the end of the given year
1511 ** where, to make the math easy, the answer for year zero is defined as zero.
1515 leaps_thru_end_of(const int y
)
1517 return (y
>= 0) ? (y
/ 4 - y
/ 100 + y
/ 400) :
1518 -(leaps_thru_end_of(-(y
+ 1)) + 1);
1522 timesub(const timezone_t sp
, const time_t *const timep
, const long offset
,
1523 struct tm
*const tmp
)
1525 const struct lsinfo
* lp
;
1527 int idays
; /* unsigned would be so 2003 */
1537 i
= (sp
== NULL
) ? 0 : sp
->leapcnt
;
1540 if (*timep
>= lp
->ls_trans
) {
1541 if (*timep
== lp
->ls_trans
) {
1542 hit
= ((i
== 0 && lp
->ls_corr
> 0) ||
1543 lp
->ls_corr
> sp
->lsis
[i
- 1].ls_corr
);
1546 sp
->lsis
[i
].ls_trans
==
1547 sp
->lsis
[i
- 1].ls_trans
+ 1 &&
1548 sp
->lsis
[i
].ls_corr
==
1549 sp
->lsis
[i
- 1].ls_corr
+ 1) {
1559 tdays
= *timep
/ SECSPERDAY
;
1560 rem
= (long) (*timep
- tdays
* SECSPERDAY
);
1561 while (tdays
< 0 || tdays
>= year_lengths
[isleap(y
)]) {
1567 tdelta
= tdays
/ DAYSPERLYEAR
;
1568 idelta
= (int) tdelta
;
1569 if (tdelta
- idelta
>= 1 || idelta
- tdelta
>= 1)
1572 idelta
= (tdays
< 0) ? -1 : 1;
1574 if (increment_overflow(&newy
, idelta
))
1576 leapdays
= leaps_thru_end_of(newy
- 1) -
1577 leaps_thru_end_of(y
- 1);
1578 tdays
-= ((time_t) newy
- y
) * DAYSPERNYEAR
;
1585 seconds
= tdays
* SECSPERDAY
+ 0.5;
1586 tdays
= seconds
/ SECSPERDAY
;
1587 rem
+= (long) (seconds
- tdays
* SECSPERDAY
);
1590 ** Given the range, we can now fearlessly cast...
1592 idays
= (int) tdays
;
1593 rem
+= offset
- corr
;
1598 while (rem
>= SECSPERDAY
) {
1603 if (increment_overflow(&y
, -1))
1605 idays
+= year_lengths
[isleap(y
)];
1607 while (idays
>= year_lengths
[isleap(y
)]) {
1608 idays
-= year_lengths
[isleap(y
)];
1609 if (increment_overflow(&y
, 1))
1613 if (increment_overflow(&tmp
->tm_year
, -TM_YEAR_BASE
))
1615 tmp
->tm_yday
= idays
;
1617 ** The "extra" mods below avoid overflow problems.
1619 tmp
->tm_wday
= EPOCH_WDAY
+
1620 ((y
- EPOCH_YEAR
) % DAYSPERWEEK
) *
1621 (DAYSPERNYEAR
% DAYSPERWEEK
) +
1622 leaps_thru_end_of(y
- 1) -
1623 leaps_thru_end_of(EPOCH_YEAR
- 1) +
1625 tmp
->tm_wday
%= DAYSPERWEEK
;
1626 if (tmp
->tm_wday
< 0)
1627 tmp
->tm_wday
+= DAYSPERWEEK
;
1628 tmp
->tm_hour
= (int) (rem
/ SECSPERHOUR
);
1630 tmp
->tm_min
= (int) (rem
/ SECSPERMIN
);
1632 ** A positive leap second requires a special
1633 ** representation. This uses "... ??:59:60" et seq.
1635 tmp
->tm_sec
= (int) (rem
% SECSPERMIN
) + hit
;
1636 ip
= mon_lengths
[isleap(y
)];
1637 for (tmp
->tm_mon
= 0; idays
>= ip
[tmp
->tm_mon
]; ++(tmp
->tm_mon
))
1638 idays
-= ip
[tmp
->tm_mon
];
1639 tmp
->tm_mday
= (int) (idays
+ 1);
1642 tmp
->TM_GMTOFF
= offset
;
1643 #endif /* defined TM_GMTOFF */
1648 ctime(const time_t *const timep
)
1651 ** Section 4.12.3.2 of X3.159-1989 requires that
1652 ** The ctime function converts the calendar time pointed to by timer
1653 ** to local time in the form of a string. It is equivalent to
1654 ** asctime(localtime(timer))
1656 struct tm
*rtm
= localtime(timep
);
1659 return asctime(rtm
);
1663 ctime_r(const time_t *const timep
, char *buf
)
1665 struct tm mytm
, *rtm
;
1667 rtm
= localtime_r(timep
, &mytm
);
1670 return asctime_r(rtm
, buf
);
1674 ctime_rz(const timezone_t sp
, const time_t * timep
, char *buf
)
1676 struct tm mytm
, *rtm
;
1678 rtm
= localtime_rz(sp
, timep
, &mytm
);
1681 return asctime_r(rtm
, buf
);
1685 ** Adapted from code provided by Robert Elz, who writes:
1686 ** The "best" way to do mktime I think is based on an idea of Bob
1687 ** Kridle's (so its said...) from a long time ago.
1688 ** It does a binary search of the time_t space. Since time_t's are
1689 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
1690 ** would still be very reasonable).
1694 #define WRONG ((time_t)-1)
1695 #endif /* !defined WRONG */
1698 ** Simplified normalize logic courtesy Paul Eggert.
1702 increment_overflow(int *number
, int delta
)
1707 if (delta
< 0 ? number0
< INT_MIN
- delta
: INT_MAX
- delta
< number0
)
1714 long_increment_overflow(long *number
, int delta
)
1719 if (delta
< 0 ? number0
< LONG_MIN
- delta
: LONG_MAX
- delta
< number0
)
1726 normalize_overflow(int *const tensptr
, int *const unitsptr
, const int base
)
1730 tensdelta
= (*unitsptr
>= 0) ?
1731 (*unitsptr
/ base
) :
1732 (-1 - (-1 - *unitsptr
) / base
);
1733 *unitsptr
-= tensdelta
* base
;
1734 return increment_overflow(tensptr
, tensdelta
);
1738 long_normalize_overflow(long *const tensptr
, int *const unitsptr
,
1743 tensdelta
= (*unitsptr
>= 0) ?
1744 (*unitsptr
/ base
) :
1745 (-1 - (-1 - *unitsptr
) / base
);
1746 *unitsptr
-= tensdelta
* base
;
1747 return long_increment_overflow(tensptr
, tensdelta
);
1751 tmcomp(const struct tm
*const atmp
, const struct tm
*const btmp
)
1755 if ((result
= (atmp
->tm_year
- btmp
->tm_year
)) == 0 &&
1756 (result
= (atmp
->tm_mon
- btmp
->tm_mon
)) == 0 &&
1757 (result
= (atmp
->tm_mday
- btmp
->tm_mday
)) == 0 &&
1758 (result
= (atmp
->tm_hour
- btmp
->tm_hour
)) == 0 &&
1759 (result
= (atmp
->tm_min
- btmp
->tm_min
)) == 0)
1760 result
= atmp
->tm_sec
- btmp
->tm_sec
;
1765 time2sub(const timezone_t sp
, struct tm
*const tmp
, subfun_t funcp
,
1766 const long offset
, int *const okayp
, const int do_norm_secs
)
1777 struct tm yourtm
, mytm
;
1782 if (normalize_overflow(&yourtm
.tm_min
, &yourtm
.tm_sec
,
1786 if (normalize_overflow(&yourtm
.tm_hour
, &yourtm
.tm_min
, MINSPERHOUR
))
1788 if (normalize_overflow(&yourtm
.tm_mday
, &yourtm
.tm_hour
, HOURSPERDAY
))
1791 if (long_normalize_overflow(&y
, &yourtm
.tm_mon
, MONSPERYEAR
))
1794 ** Turn y into an actual year number for now.
1795 ** It is converted back to an offset from TM_YEAR_BASE later.
1797 if (long_increment_overflow(&y
, TM_YEAR_BASE
))
1799 while (yourtm
.tm_mday
<= 0) {
1800 if (long_increment_overflow(&y
, -1))
1802 li
= y
+ (1 < yourtm
.tm_mon
);
1803 yourtm
.tm_mday
+= year_lengths
[isleap(li
)];
1805 while (yourtm
.tm_mday
> DAYSPERLYEAR
) {
1806 li
= y
+ (1 < yourtm
.tm_mon
);
1807 yourtm
.tm_mday
-= year_lengths
[isleap(li
)];
1808 if (long_increment_overflow(&y
, 1))
1812 i
= mon_lengths
[isleap(y
)][yourtm
.tm_mon
];
1813 if (yourtm
.tm_mday
<= i
)
1815 yourtm
.tm_mday
-= i
;
1816 if (++yourtm
.tm_mon
>= MONSPERYEAR
) {
1818 if (long_increment_overflow(&y
, 1))
1822 if (long_increment_overflow(&y
, -TM_YEAR_BASE
))
1825 if (yourtm
.tm_year
!= y
)
1827 if (yourtm
.tm_sec
>= 0 && yourtm
.tm_sec
< SECSPERMIN
)
1829 else if (y
+ TM_YEAR_BASE
< EPOCH_YEAR
) {
1831 ** We can't set tm_sec to 0, because that might push the
1832 ** time below the minimum representable time.
1833 ** Set tm_sec to 59 instead.
1834 ** This assumes that the minimum representable time is
1835 ** not in the same minute that a leap second was deleted from,
1836 ** which is a safer assumption than using 58 would be.
1838 if (increment_overflow(&yourtm
.tm_sec
, 1 - SECSPERMIN
))
1840 saved_seconds
= yourtm
.tm_sec
;
1841 yourtm
.tm_sec
= SECSPERMIN
- 1;
1843 saved_seconds
= yourtm
.tm_sec
;
1847 ** Do a binary search (this works whatever time_t's type is).
1849 /* LINTED constant */
1850 if (!TYPE_SIGNED(time_t)) {
1853 /* LINTED constant */
1854 } else if (!TYPE_INTEGRAL(time_t)) {
1856 if (sizeof(time_t) > sizeof(float))
1857 /* LINTED assumed double */
1858 hi
= (time_t) DBL_MAX
;
1859 /* LINTED assumed float */
1860 else hi
= (time_t) FLT_MAX
;
1864 for (i
= 0; i
< (int) TYPE_BIT(time_t) - 1; ++i
)
1869 t
= lo
/ 2 + hi
/ 2;
1874 if ((*funcp
)(sp
, &t
, offset
, &mytm
) == NULL
) {
1876 ** Assume that t is too extreme to be represented in
1877 ** a struct tm; arrange things so that it is less
1878 ** extreme on the next pass.
1880 dir
= (t
> 0) ? 1 : -1;
1881 } else dir
= tmcomp(&mytm
, &yourtm
);
1888 } else if (t
== hi
) {
1901 if (yourtm
.tm_isdst
< 0 || mytm
.tm_isdst
== yourtm
.tm_isdst
)
1904 ** Right time, wrong type.
1905 ** Hunt for right time, right type.
1906 ** It's okay to guess wrong since the guess
1911 for (i
= sp
->typecnt
- 1; i
>= 0; --i
) {
1912 if (sp
->ttis
[i
].tt_isdst
!= yourtm
.tm_isdst
)
1914 for (j
= sp
->typecnt
- 1; j
>= 0; --j
) {
1915 if (sp
->ttis
[j
].tt_isdst
== yourtm
.tm_isdst
)
1917 newt
= t
+ sp
->ttis
[j
].tt_gmtoff
-
1918 sp
->ttis
[i
].tt_gmtoff
;
1919 if ((*funcp
)(sp
, &newt
, offset
, &mytm
) == NULL
)
1921 if (tmcomp(&mytm
, &yourtm
) != 0)
1923 if (mytm
.tm_isdst
!= yourtm
.tm_isdst
)
1935 newt
= t
+ saved_seconds
;
1936 if ((newt
< t
) != (saved_seconds
< 0))
1939 if ((*funcp
)(sp
, &t
, offset
, tmp
)) {
1947 time2(const timezone_t sp
, struct tm
*const tmp
, subfun_t funcp
,
1948 const long offset
, int *const okayp
)
1953 ** First try without normalization of seconds
1954 ** (in case tm_sec contains a value associated with a leap second).
1955 ** If that fails, try with normalization of seconds.
1957 t
= time2sub(sp
, tmp
, funcp
, offset
, okayp
, FALSE
);
1958 return *okayp
? t
: time2sub(sp
, tmp
, funcp
, offset
, okayp
, TRUE
);
1962 time1(const timezone_t sp
, struct tm
*const tmp
, subfun_t funcp
,
1967 int sameind
, otherind
;
1970 int seen
[TZ_MAX_TYPES
];
1971 int types
[TZ_MAX_TYPES
];
1974 if (tmp
->tm_isdst
> 1)
1976 t
= time2(sp
, tmp
, funcp
, offset
, &okay
);
1979 ** PCTS code courtesy Grant Sullivan.
1983 if (tmp
->tm_isdst
< 0)
1984 tmp
->tm_isdst
= 0; /* reset to std and try again */
1985 #endif /* defined PCTS */
1987 if (okay
|| tmp
->tm_isdst
< 0)
1989 #endif /* !defined PCTS */
1991 ** We're supposed to assume that somebody took a time of one type
1992 ** and did some math on it that yielded a "struct tm" that's bad.
1993 ** We try to divine the type they started from and adjust to the
1998 for (i
= 0; i
< sp
->typecnt
; ++i
)
2001 for (i
= sp
->timecnt
- 1; i
>= 0; --i
)
2002 if (!seen
[sp
->types
[i
]]) {
2003 seen
[sp
->types
[i
]] = TRUE
;
2004 types
[nseen
++] = sp
->types
[i
];
2006 for (sameind
= 0; sameind
< nseen
; ++sameind
) {
2007 samei
= types
[sameind
];
2008 if (sp
->ttis
[samei
].tt_isdst
!= tmp
->tm_isdst
)
2010 for (otherind
= 0; otherind
< nseen
; ++otherind
) {
2011 otheri
= types
[otherind
];
2012 if (sp
->ttis
[otheri
].tt_isdst
== tmp
->tm_isdst
)
2014 tmp
->tm_sec
+= (int)(sp
->ttis
[otheri
].tt_gmtoff
-
2015 sp
->ttis
[samei
].tt_gmtoff
);
2016 tmp
->tm_isdst
= !tmp
->tm_isdst
;
2017 t
= time2(sp
, tmp
, funcp
, offset
, &okay
);
2020 tmp
->tm_sec
-= (int)(sp
->ttis
[otheri
].tt_gmtoff
-
2021 sp
->ttis
[samei
].tt_gmtoff
);
2022 tmp
->tm_isdst
= !tmp
->tm_isdst
;
2029 mktime_z(const timezone_t sp
, struct tm
*tmp
)
2033 t
= time1(NULL
, tmp
, gmtsub
, 0L);
2035 t
= time1(sp
, tmp
, localsub
, 0L);
2042 mktime(struct tm
* const tmp
)
2046 rwlock_wrlock(&lcl_lock
);
2048 result
= mktime_z(lclptr
, tmp
);
2049 rwlock_unlock(&lcl_lock
);
2056 timelocal_z(const timezone_t sp
, struct tm
*tmp
)
2059 tmp
->tm_isdst
= -1; /* in case it wasn't initialized */
2060 return mktime_z(sp
, tmp
);
2064 timelocal(struct tm
*const tmp
)
2066 tmp
->tm_isdst
= -1; /* in case it wasn't initialized */
2071 timegm(struct tm
*const tmp
)
2076 t
= time1(gmtptr
, tmp
, gmtsub
, 0L);
2083 timeoff(struct tm
*const tmp
, const long offset
)
2088 t
= time1(gmtptr
, tmp
, gmtsub
, offset
);
2094 #endif /* defined STD_INSPIRED */
2099 ** The following is supplied for compatibility with
2100 ** previous versions of the CMUCS runtime library.
2104 gtime(struct tm
*const tmp
)
2106 const time_t t
= mktime(tmp
);
2113 #endif /* defined CMUCS */
2116 ** XXX--is the below the right way to conditionalize??
2122 ** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
2123 ** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
2124 ** is not the case if we are accounting for leap seconds.
2125 ** So, we provide the following conversion routines for use
2126 ** when exchanging timestamps with POSIX conforming systems.
2130 leapcorr(const timezone_t sp
, time_t *timep
)
2138 if (*timep
>= lp
->ls_trans
)
2145 time2posix_z(const timezone_t sp
, time_t t
)
2147 return t
- leapcorr(sp
, &t
);
2151 time2posix(time_t t
)
2154 rwlock_wrlock(&lcl_lock
);
2156 result
= t
- leapcorr(lclptr
, &t
);
2157 rwlock_unlock(&lcl_lock
);
2162 posix2time_z(const timezone_t sp
, time_t t
)
2168 ** For a positive leap second hit, the result
2169 ** is not unique. For a negative leap second
2170 ** hit, the corresponding time doesn't exist,
2171 ** so we return an adjacent second.
2173 x
= t
+ leapcorr(sp
, &t
);
2174 y
= x
- leapcorr(sp
, &x
);
2178 y
= x
- leapcorr(sp
, &x
);
2186 y
= x
- leapcorr(sp
, &x
);
2198 posix2time(time_t t
)
2202 rwlock_wrlock(&lcl_lock
);
2204 result
= posix2time_z(lclptr
, t
);
2205 rwlock_unlock(&lcl_lock
);
2209 #endif /* defined STD_INSPIRED */