2 ** This file is in the public domain, so clarified as of
3 ** 1996-06-05 by Arthur David Olson.
6 #pragma clang diagnostic push
7 #pragma clang diagnostic ignored "-Wunreachable-code"
12 static char elsieid
[] __unused
= "@(#)localtime.c 8.14";
13 #endif /* !defined NOID */
14 #endif /* !defined lint */
15 __FBSDID("$FreeBSD: head/contrib/tzcode/stdtime/localtime.c 289027 2015-10-08 11:42:15Z rodrigc $");
18 ** Leap second handling from Bradley White.
19 ** POSIX-style TZ environment variable handling from Guy Harris.
24 #include "namespace.h"
25 #include <sys/types.h>
32 //#define NOTIFY_TZ_DEBUG
33 //#define NOTIFY_TZ_DEBUG_FILE "/var/log/localtime.debug"
34 //#define NOTIFY_TZ_LOG "/var/log/localtime.log"
35 /* force ALL_STATE if NOTIFY_TZ is set */
38 #endif /* ALL_STATE */
39 #include <mach/mach_init.h>
42 #endif /* NOTIFY_TZ */
44 #include "un-namespace.h"
47 #include "float.h" /* for FLT_MAX and DBL_MAX */
49 #ifndef TZ_ABBR_MAX_LEN
50 /* UNIX03 requires this to be the same as sysconf(_SC_TZNAME_MAX) */
51 #define TZ_ABBR_MAX_LEN 255
52 #endif /* !defined TZ_ABBR_MAX_LEN */
54 #ifndef TZ_ABBR_CHAR_SET
55 #define TZ_ABBR_CHAR_SET \
56 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
57 #endif /* !defined TZ_ABBR_CHAR_SET */
59 #ifndef TZ_ABBR_ERR_CHAR
60 #define TZ_ABBR_ERR_CHAR '_'
61 #endif /* !defined TZ_ABBR_ERR_CHAR */
63 #include "libc_private.h"
65 #define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x)
66 #define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x)
68 #define _RWLOCK_RDLOCK(x) \
70 if (__isthreaded) _pthread_rwlock_rdlock(x); \
73 #define _RWLOCK_WRLOCK(x) \
75 if (__isthreaded) _pthread_rwlock_wrlock(x); \
78 #define _RWLOCK_UNLOCK(x) \
80 if (__isthreaded) _pthread_rwlock_unlock(x); \
84 ** SunOS 4.1.1 headers lack O_BINARY.
88 #define OPEN_MODE (O_RDONLY | O_BINARY)
89 #endif /* defined O_BINARY */
91 #define OPEN_MODE O_RDONLY
92 #endif /* !defined O_BINARY */
96 ** Someone might make incorrect use of a time zone abbreviation:
97 ** 1. They might reference tzname[0] before calling tzset (explicitly
99 ** 2. They might reference tzname[1] before calling tzset (explicitly
101 ** 3. They might reference tzname[1] after setting to a time zone
102 ** in which Daylight Saving Time is never observed.
103 ** 4. They might reference tzname[0] after setting to a time zone
104 ** in which Standard Time is never observed.
105 ** 5. They might reference tm.TM_ZONE after calling offtime.
106 ** What's best to do in the above cases is open to debate;
107 ** for now, we just set things up so that in any of the five cases
108 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
109 ** string "tzname[0] used before set", and similarly for the other cases.
110 ** And another: initialize tzname[0] to "ERA", with an explanation in the
111 ** manual page of what this "time zone abbreviation" means (doing this so
112 ** that tzname[0] has the "normal" length of three characters).
115 #endif /* !defined WILDABBR */
117 __used
static const char wildabbr
[] = WILDABBR
;
120 * In June 2004 it was decided UTC was a more appropriate default time
124 __used
static const char gmt
[] = "UTC";
127 ** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
128 ** We default to US rules as of 1999-08-17.
129 ** POSIX 1003.1 section 8.1.1 says that the default DST rules are
130 ** implementation dependent; for historical reasons, US rules are a
133 #ifndef TZDEFRULESTRING
134 #define TZDEFRULESTRING ",M4.1.0,M10.5.0"
135 #endif /* !defined TZDEFDST */
137 struct ttinfo
{ /* time type information */
138 long tt_gmtoff
; /* UTC 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 */
142 int tt_ttisgmt
; /* TRUE if transition is UTC */
145 struct lsinfo
{ /* leap second information */
146 time_t ls_trans
; /* transition time */
147 long ls_corr
; /* correction to apply */
150 #define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
153 #define MY_TZNAME_MAX TZNAME_MAX
154 #endif /* defined TZNAME_MAX */
156 #define MY_TZNAME_MAX 255
157 #endif /* !defined TZNAME_MAX */
166 time_t ats
[TZ_MAX_TIMES
];
167 unsigned char types
[TZ_MAX_TIMES
];
168 struct ttinfo ttis
[TZ_MAX_TYPES
];
169 char chars
[BIGGEST(BIGGEST(TZ_MAX_CHARS
+ 1, sizeof gmt
),
170 (2 * (MY_TZNAME_MAX
+ 1)))];
171 struct lsinfo lsis
[TZ_MAX_LEAPS
];
175 int r_type
; /* type of rule--see below */
176 int r_day
; /* day number of rule */
177 int r_week
; /* week number of rule */
178 int r_mon
; /* month number of rule */
179 long r_time
; /* transition time of rule */
182 #define JULIAN_DAY 0 /* Jn - Julian day */
183 #define DAY_OF_YEAR 1 /* n - day of year */
184 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
192 #define NOTIFY_TZ_NAME "com.apple.system.timezone"
193 #endif /* NOTIFY_TZ */
196 ** Prototypes for static functions.
198 #define localsub _st_localsub
199 #define time1 _st_time1
200 #define tzset_basic _st_tzset_basic
203 struct tm
* localsub(const time_t * timep
, long offset
,
205 #else /* !__LP64__ */
206 void localsub(const time_t * timep
, long offset
,
208 #endif /* __LP64__ */
210 time_t time1(struct tm
* tmp
,
212 struct tm
*(*funcp
) (const time_t *,
214 #else /* !__LP64__ */
215 void(*funcp
) (const time_t *,
217 #endif /* __LP64__ */
221 void tzset_basic(int);
223 #if !BUILDING_VARIANT
224 static long detzcode(const char * codep
);
225 static time_t detzcode64(const char * codep
);
226 static int differ_by_repeat(time_t t1
, time_t t0
);
227 static const char * getzname(const char * strp
, char **name
, size_t *len
);
228 static const char * getqzname(const char * strp
, const int delim
)
230 static const char * getnum(const char * strp
, int * nump
, int min
,
232 static const char * getsecs(const char * strp
, long * secsp
);
233 static const char * getoffset(const char * strp
, long * offsetp
);
234 static const char * getrule(const char * strp
, struct rule
* rulep
);
236 static void gmtload(struct state
* sp
, char *path
);
237 #else /* ! NOTIFY_TZ */
238 static void gmtload(struct state
* sp
);
239 #endif /* NOTIFY_TZ */
241 static struct tm
* gmtsub(const time_t * timep
, long offset
,
243 #else /* !__LP64__ */
244 static void gmtsub(const time_t * timep
, long offset
,
246 #endif /* __LP64__ */
247 static int increment_overflow(int * number
, int delta
);
248 static int leaps_thru_end_of(int y
) ATTRIBUTE_PURE
;
249 static int long_increment_overflow(long * number
, int delta
);
250 static int long_normalize_overflow(long * tensptr
,
251 int * unitsptr
, int base
);
252 static int normalize_overflow(int * tensptr
, int * unitsptr
,
255 static void notify_check_tz(notify_tz_t
*p
);
256 static void notify_register_tz(char *file
, notify_tz_t
*p
);
257 #endif /* NOTIFY_TZ */
258 static void settzname(void);
259 static time_t time2(struct tm
*tmp
,
261 struct tm
*(*funcp
) (const time_t *,
263 #else /* !__LP64__ */
264 void(*funcp
) (const time_t *,
266 #endif /* __LP64__ */
267 long offset
, int * okayp
, int unix03
);
268 static time_t time2sub(struct tm
*tmp
,
270 struct tm
*(*funcp
) (const time_t *,
272 #else /* !__LP64__ */
273 void(*funcp
) (const time_t *,
275 #endif /* __LP64__ */
276 long offset
, int * okayp
, int do_norm_secs
,
279 static struct tm
* timesub(const time_t * timep
, long offset
,
280 const struct state
* sp
, struct tm
* tmp
);
281 #else /* !__LP64__ */
282 static void timesub(const time_t * timep
, long offset
,
283 const struct state
* sp
, struct tm
* tmp
);
284 #endif /* __LP64__ */
285 static int tmcomp(const struct tm
* atmp
,
286 const struct tm
* btmp
);
287 static time_t transtime(time_t janfirst
, int year
,
288 const struct rule
* rulep
, long offset
)
290 static int typesequiv(const struct state
* sp
, int a
, int b
);
292 static int tzload(const char * name
, struct state
* sp
, char *path
, int doextend
);
293 #else /* ! NOTIFY_TZ */
294 static int tzload(const char * name
, struct state
* sp
, int doextend
);
295 #endif /* NOTIFY_TZ */
296 static int tzparse(const char * name
, struct state
* sp
,
300 static struct state
* lclptr
;
301 static struct state
* gmtptr
;
302 #endif /* defined ALL_STATE */
305 static struct state lclmem
;
306 static struct state gmtmem
;
307 #define lclptr (&lclmem)
308 #define gmtptr (&gmtmem)
309 #endif /* State Farm */
311 #ifndef TZ_STRLEN_MAX
312 #define TZ_STRLEN_MAX 255
313 #endif /* !defined TZ_STRLEN_MAX */
315 static char lcl_TZname
[TZ_STRLEN_MAX
+ 1];
317 #define lcl_is_set (lcl_notify.is_set)
318 #define gmt_is_set (gmt_notify.is_set)
319 #else /* ! NOTIFY_TZ */
320 static int lcl_is_set
;
321 #endif /* NOTIFY_TZ */
322 static pthread_once_t gmt_once
= PTHREAD_ONCE_INIT
;
323 __private_extern__ pthread_rwlock_t lcl_rwlock
= PTHREAD_RWLOCK_INITIALIZER
;
324 static pthread_once_t gmtime_once
= PTHREAD_ONCE_INIT
;
325 static pthread_key_t gmtime_key
;
326 static int gmtime_key_error
;
327 static pthread_once_t localtime_once
= PTHREAD_ONCE_INIT
;
328 static pthread_key_t localtime_key
;
329 static int localtime_key_error
;
337 ** Section 4.12.3 of X3.159-1989 requires that
338 ** Except for the strftime function, these functions [asctime,
339 ** ctime, gmtime, localtime] return values in one of two static
340 ** objects: a broken-down time structure and an array of char.
341 ** Thanks to Paul Eggert for noting this.
350 __private_extern__
void _st_set_timezone(long);
351 #endif /* defined USG_COMPAT */
354 __private_extern__
long __darwin_altzone
= 0;
355 #define altzone __darwin_altzone
356 #endif /* defined ALTZONE */
359 #ifdef NOTIFY_TZ_DEBUG
360 #ifdef NOTIFY_TZ_DEBUG_FILE
361 #define NOTIFY_TZ_PRINTF(fmt, args...) \
363 FILE *_notify_tz_fp_; \
364 if((_notify_tz_fp_ = fopen(NOTIFY_TZ_DEBUG_FILE, "a")) != NULL) { \
365 fprintf(_notify_tz_fp_, "%d: " fmt, getpid(), ## args); \
366 fclose(_notify_tz_fp_); \
369 #else /* ! NOTIFY_TZ_DEBUG_FILE */
370 #define NOTIFY_TZ_PRINTF(args...) fprintf(stdout, ## args)
371 #endif /* NOTIFY_TZ_DEBUG_FILE */
372 #endif /* NOTIFY_TZ_DEBUG */
374 #define NOTIFY_LOG(fmt, args...) \
376 FILE *_notify_log_fp_; \
377 if((_notify_log_fp_ = fopen(NOTIFY_TZ_LOG, "a")) != NULL) { \
378 fprintf(_notify_log_fp_, "%d: " fmt, getpid(), ## args); \
379 fclose(_notify_log_fp_); \
382 #endif /* NOTIFY_TZ_LOG */
384 static notify_tz_t gmt_notify
= {-1, 0};
385 static notify_tz_t lcl_notify
= {-1, 0};
386 static const char notify_tz_name
[] = NOTIFY_TZ_NAME
;
387 #endif /* NOTIFY_TZ */
390 detzcode(const char *const codep
)
395 result
= (codep
[0] & 0x80) ? ~0L : 0;
396 for (i
= 0; i
< 4; ++i
)
397 result
= (result
<< 8) | (codep
[i
] & 0xff);
402 detzcode64(const char *const codep
)
404 register time_t result
;
407 result
= (codep
[0] & 0x80) ? (~(int_fast64_t) 0) : 0;
408 for (i
= 0; i
< 8; ++i
)
409 result
= result
* 256 + (codep
[i
] & 0xff);
416 struct state
* sp
= lclptr
;
418 unsigned char * types
;
421 #define NEED_DAYLIGHT 4
422 #define NEED_ALL (NEED_STD | NEED_DST | NEED_DAYLIGHT)
424 tzname
[0] = (char *)wildabbr
;
425 tzname
[1] = (char *)wildabbr
;
429 #endif /* defined USG_COMPAT */
432 #endif /* defined ALTZONE */
435 tzname
[0] = tzname
[1] = (char *)gmt
;
438 #endif /* defined ALL_STATE */
440 * PR-3765457: The original settzname went sequentially through the ttis
441 * array, rather than correctly indexing via the types array, to get
442 * the real order of the timezone changes. In addition, as a speed up,
443 * we start at the end of the changes, and work back, so that most of
444 * the time, we don't have to look through the entire array.
446 if (sp
->timecnt
== 0 && sp
->typecnt
== 1) {
448 * Unfortunately, there is an edge case when typecnt == 1 and
449 * timecnt == 0, which would cause the loop to never run. So
450 * in that case, we fudge things up so that it is as if
454 types
= (unsigned char *)""; /* we use the null as index */
461 for (; i
>= 0 && need
; --i
) {
462 const struct ttinfo
* const ttisp
= &sp
->ttis
[types
[i
]];
465 if ((need
& NEED_DAYLIGHT
) && ttisp
->tt_isdst
) {
466 need
&= ~NEED_DAYLIGHT
;
469 #endif /* defined USG_COMPAT */
470 if (ttisp
->tt_isdst
) {
471 if (need
& NEED_DST
) {
473 tzname
[1] = &sp
->chars
[ttisp
->tt_abbrind
];
475 altzone
= -(ttisp
->tt_gmtoff
);
476 #endif /* defined ALTZONE */
478 } else if (need
& NEED_STD
) {
480 tzname
[0] = &sp
->chars
[ttisp
->tt_abbrind
];
482 _st_set_timezone(-(ttisp
->tt_gmtoff
));
483 #endif /* defined USG_COMPAT */
485 #if defined(ALTZONE) || defined(USG_COMPAT)
487 #endif /* defined(ALTZONE) || defined(USG_COMPAT) */
490 altzone
= -(ttisp
->tt_gmtoff
);
491 #endif /* defined ALTZONE */
494 _st_set_timezone(-(ttisp
->tt_gmtoff
));
495 #endif /* defined USG_COMPAT */
496 #if defined(ALTZONE) || defined(USG_COMPAT)
498 #endif /* defined(ALTZONE) || defined(USG_COMPAT) */
501 ** Finally, scrub the abbreviations.
502 ** First, replace bogus characters.
504 for (i
= 0; i
< sp
->charcnt
; ++i
)
505 if (strchr(TZ_ABBR_CHAR_SET
, sp
->chars
[i
]) == NULL
)
506 sp
->chars
[i
] = TZ_ABBR_ERR_CHAR
;
508 ** Second, truncate long abbreviations.
510 for (i
= 0; i
< sp
->typecnt
; ++i
) {
511 register const struct ttinfo
* const ttisp
= &sp
->ttis
[i
];
512 register char * cp
= &sp
->chars
[ttisp
->tt_abbrind
];
514 if (strlen(cp
) > TZ_ABBR_MAX_LEN
&&
515 strcmp(cp
, GRANDPARENTED
) != 0)
516 *(cp
+ TZ_ABBR_MAX_LEN
) = '\0';
522 notify_check_tz(notify_tz_t
*p
)
529 nstat
= notify_check(p
->token
, &ncheck
);
530 if (nstat
|| ncheck
) {
532 #ifdef NOTIFY_TZ_DEBUG
533 NOTIFY_TZ_PRINTF("notify_check_tz: %s changed\n", (p
== &lcl_notify
) ? "lcl" : "gmt");
534 #endif /* NOTIFY_TZ_DEBUG */
536 #ifdef NOTIFY_TZ_DEBUG
537 NOTIFY_TZ_PRINTF("notify_check_tz: %s unchanged\n", (p
== &lcl_notify
) ? "lcl" : "gmt");
538 #endif /* NOTIFY_TZ_DEBUG */
541 extern uint32_t notify_monitor_file(int token
, char *path
, int flags
);
544 notify_register_tz(char *file
, notify_tz_t
*p
)
550 if (bootstrap_port
== MACH_PORT_NULL
) {
551 /* error handling below resets is_set, we don't want that */
555 /*----------------------------------------------------------------
556 * Since we don't record the last time zone filename, just cancel
557 * (which should remove the file monitor) and setup from scratch
558 *----------------------------------------------------------------*/
560 notify_cancel(p
->token
);
561 if (!file
|| *file
== 0) {
562 /* no time zone file to monitor */
566 /*----------------------------------------------------------------
567 * Just use com.apple.system.timezone if the path is /etc/localtime.
568 * Otherwise use com.apple.system.timezone.<fullpath>
569 *----------------------------------------------------------------*/
570 if (TZDEFAULT
&& strcmp(file
, TZDEFAULT
) == 0)
571 name
= (char *)notify_tz_name
;
573 name
= alloca(sizeof(notify_tz_name
) + strlen(file
) + 1);
578 strcpy(name
, notify_tz_name
);
582 #ifdef NOTIFY_TZ_DEBUG
583 NOTIFY_TZ_PRINTF("notify_register_tz: file=%s name=%s\n", file
, name
);
584 #endif /* NOTIFY_TZ_DEBUG */
585 nstat
= notify_register_check(name
, &p
->token
);
589 #ifdef NOTIFY_TZ_DEBUG
590 NOTIFY_TZ_PRINTF("***notify_register_tz: notify_register_check failed: %u\n", nstat
);
591 #endif /* NOTIFY_TZ_DEBUG */
593 NOTIFY_LOG("notify_register_check(%s) failed: %u\n", name
, nstat
);
594 #endif /* NOTIFY_TZ_LOG */
597 /* don't need to request monitoring /etc/localtime */
598 if (name
!= notify_tz_name
) {
599 #ifdef NOTIFY_TZ_DEBUG
600 NOTIFY_TZ_PRINTF("notify_register_tz: monitor %s\n", file
);
601 #endif /* NOTIFY_TZ_DEBUG */
602 nstat
= notify_monitor_file(p
->token
, file
, 0);
604 notify_cancel(p
->token
);
607 #ifdef NOTIFY_TZ_DEBUG
608 NOTIFY_TZ_PRINTF("***notify_register_tz: notify_monitor_file failed: %u\n", nstat
);
609 #endif /* NOTIFY_TZ_DEBUG */
611 NOTIFY_LOG("notify_monitor_file(%s) failed: %u\n", file
, nstat
);
612 #endif /* NOTIFY_TZ_LOG */
616 notify_check(p
->token
, &ncheck
); /* this always returns true */
618 #endif /* NOTIFY_TZ */
621 differ_by_repeat(const time_t t1
, const time_t t0
)
623 int_fast64_t _t0
= t0
;
624 int_fast64_t _t1
= t1
;
626 if (TYPE_INTEGRAL(time_t) &&
627 TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS
)
629 //turn ((int_fast64_t)(t1 - t0) == SECSPERREPEAT);
630 return _t1
- _t0
== SECSPERREPEAT
;
635 tzload(name
, sp
, path
, doextend
)
636 #else /* ! NOTIFY_TZ */
637 tzload(name
, sp
, doextend
)
638 #endif /* NOTIFY_TZ */
640 struct state
* const sp
;
642 char * path
; /* copy full path if non-NULL */
643 #endif /* NOTIFY_TZ */
644 register const int doextend
;
653 struct tzhead tzhead
;
654 char buf
[2 * sizeof(struct tzhead
) +
661 sp
->goback
= sp
->goahead
= FALSE
;
663 #ifdef NOTIFY_TZ_DEBUG
664 NOTIFY_TZ_PRINTF("tzload: name=%s\n", name
);
665 #endif /* NOTIFY_TZ_DEBUG */
666 /* XXX The following is from OpenBSD, and I'm not sure it is correct */
667 if (name
!= NULL
&& issetugid() != 0)
668 if ((name
[0] == ':' && name
[1] == '/') ||
669 name
[0] == '/' || strchr(name
, '.'))
673 *path
= 0; /* default to empty string on error */
674 #endif /* NOTIFY_TZ */
675 if (name
== NULL
&& (name
= TZDEFAULT
) == NULL
)
681 ** Section 4.9.1 of the C standard says that
682 ** "FILENAME_MAX expands to an integral constant expression
683 ** that is the size needed for an array of char large enough
684 ** to hold the longest file name string that the implementation
685 ** guarantees can be opened."
689 fullname
= malloc(FILENAME_MAX
+ 1);
690 if (fullname
== NULL
)
695 doaccess
= name
[0] == '/';
697 if ((p
= TZDIR
) == NULL
) {
701 if (strlen(p
) + 1 + strlen(name
) >= FILENAME_MAX
) {
705 (void) strcpy(fullname
, p
);
706 (void) strcat(fullname
, "/");
707 (void) strcat(fullname
, name
);
709 ** Set doaccess if '.' (as in "../") shows up in name.
711 if (strchr(name
, '.') != NULL
)
717 if (strlen(name
) > FILENAME_MAX
)
721 #endif /* NOTIFY_TZ */
722 if (doaccess
&& access(name
, R_OK
) != 0) {
726 if ((fid
= _open(name
, OPEN_MODE
)) == -1) {
730 if ((_fstat(fid
, &stab
) < 0) || !S_ISREG(stab
.st_mode
)) {
737 u
= malloc(sizeof(*u
));
740 #ifdef NOTIFY_TZ_DEBUG
741 NOTIFY_TZ_PRINTF("tzload: reading %s\n", name
);
742 #endif /* NOTIFY_TZ_DEBUG */
743 nread
= _read(fid
, u
->buf
, sizeof u
->buf
);
744 if (_close(fid
) < 0 || nread
<= 0)
746 for (stored
= 4; stored
<= 8; stored
*= 2) {
750 ttisstdcnt
= (int) detzcode(u
->tzhead
.tzh_ttisstdcnt
);
751 ttisgmtcnt
= (int) detzcode(u
->tzhead
.tzh_ttisgmtcnt
);
752 sp
->leapcnt
= (int) detzcode(u
->tzhead
.tzh_leapcnt
);
753 sp
->timecnt
= (int) detzcode(u
->tzhead
.tzh_timecnt
);
754 sp
->typecnt
= (int) detzcode(u
->tzhead
.tzh_typecnt
);
755 sp
->charcnt
= (int) detzcode(u
->tzhead
.tzh_charcnt
);
756 p
= u
->tzhead
.tzh_charcnt
+ sizeof u
->tzhead
.tzh_charcnt
;
757 if (sp
->leapcnt
< 0 || sp
->leapcnt
> TZ_MAX_LEAPS
||
758 sp
->typecnt
<= 0 || sp
->typecnt
> TZ_MAX_TYPES
||
759 sp
->timecnt
< 0 || sp
->timecnt
> TZ_MAX_TIMES
||
760 sp
->charcnt
< 0 || sp
->charcnt
> TZ_MAX_CHARS
||
761 (ttisstdcnt
!= sp
->typecnt
&& ttisstdcnt
!= 0) ||
762 (ttisgmtcnt
!= sp
->typecnt
&& ttisgmtcnt
!= 0))
764 if (nread
- (p
- u
->buf
) <
765 sp
->timecnt
* stored
+ /* ats */
766 sp
->timecnt
+ /* types */
767 sp
->typecnt
* 6 + /* ttinfos */
768 sp
->charcnt
+ /* chars */
769 sp
->leapcnt
* (stored
+ 4) + /* lsinfos */
770 ttisstdcnt
+ /* ttisstds */
771 ttisgmtcnt
) /* ttisgmts */
773 for (i
= 0; i
< sp
->timecnt
; ++i
) {
774 sp
->ats
[i
] = (stored
== 4) ?
775 detzcode(p
) : detzcode64(p
);
778 for (i
= 0; i
< sp
->timecnt
; ++i
) {
779 sp
->types
[i
] = (unsigned char) *p
++;
780 if (sp
->types
[i
] >= sp
->typecnt
)
783 for (i
= 0; i
< sp
->typecnt
; ++i
) {
784 struct ttinfo
* ttisp
;
786 ttisp
= &sp
->ttis
[i
];
787 ttisp
->tt_gmtoff
= detzcode(p
);
789 ttisp
->tt_isdst
= (unsigned char) *p
++;
790 if (ttisp
->tt_isdst
!= 0 && ttisp
->tt_isdst
!= 1)
792 ttisp
->tt_abbrind
= (unsigned char) *p
++;
793 if (ttisp
->tt_abbrind
< 0 ||
794 ttisp
->tt_abbrind
> sp
->charcnt
)
797 for (i
= 0; i
< sp
->charcnt
; ++i
)
799 sp
->chars
[i
] = '\0'; /* ensure '\0' at end */
800 for (i
= 0; i
< sp
->leapcnt
; ++i
) {
801 struct lsinfo
* lsisp
;
803 lsisp
= &sp
->lsis
[i
];
804 lsisp
->ls_trans
= (stored
== 4) ?
805 detzcode(p
) : detzcode64(p
);
807 lsisp
->ls_corr
= detzcode(p
);
810 for (i
= 0; i
< sp
->typecnt
; ++i
) {
811 struct ttinfo
* ttisp
;
813 ttisp
= &sp
->ttis
[i
];
815 ttisp
->tt_ttisstd
= FALSE
;
817 ttisp
->tt_ttisstd
= *p
++;
818 if (ttisp
->tt_ttisstd
!= TRUE
&&
819 ttisp
->tt_ttisstd
!= FALSE
)
823 for (i
= 0; i
< sp
->typecnt
; ++i
) {
824 struct ttinfo
* ttisp
;
826 ttisp
= &sp
->ttis
[i
];
828 ttisp
->tt_ttisgmt
= FALSE
;
830 ttisp
->tt_ttisgmt
= *p
++;
831 if (ttisp
->tt_ttisgmt
!= TRUE
&&
832 ttisp
->tt_ttisgmt
!= FALSE
)
837 ** Out-of-sort ats should mean we're running on a
838 ** signed time_t system but using a data file with
839 ** unsigned values (or vice versa).
841 for (i
= 0; i
< sp
->timecnt
- 2; ++i
)
842 if (sp
->ats
[i
] > sp
->ats
[i
+ 1]) {
844 if (TYPE_SIGNED(time_t)) {
846 ** Ignore the end (easy).
851 ** Ignore the beginning (harder).
855 for (j
= 0; j
+ i
< sp
->timecnt
; ++j
) {
856 sp
->ats
[j
] = sp
->ats
[j
+ i
];
857 sp
->types
[j
] = sp
->types
[j
+ i
];
864 ** If this is an old file, we're done.
866 if (u
->tzhead
.tzh_version
[0] == '\0')
869 for (i
= 0; i
< nread
; ++i
)
872 ** If this is a narrow integer time_t system, we're done.
874 if (stored
>= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
877 if (doextend
&& nread
> 2 &&
878 u
->buf
[0] == '\n' && u
->buf
[nread
- 1] == '\n' &&
879 sp
->typecnt
+ 2 <= TZ_MAX_TYPES
) {
883 ts
= malloc(sizeof(*ts
));
886 u
->buf
[nread
- 1] = '\0';
887 result
= tzparse(&u
->buf
[1], ts
, FALSE
);
888 if (result
== 0 && ts
->typecnt
== 2 &&
889 sp
->charcnt
+ ts
->charcnt
<= TZ_MAX_CHARS
) {
890 for (i
= 0; i
< 2; ++i
)
891 ts
->ttis
[i
].tt_abbrind
+=
893 for (i
= 0; i
< ts
->charcnt
; ++i
)
894 sp
->chars
[sp
->charcnt
++] =
897 while (i
< ts
->timecnt
&&
899 sp
->ats
[sp
->timecnt
- 1])
901 while (i
< ts
->timecnt
&&
902 sp
->timecnt
< TZ_MAX_TIMES
) {
903 sp
->ats
[sp
->timecnt
] =
905 sp
->types
[sp
->timecnt
] =
911 sp
->ttis
[sp
->typecnt
++] = ts
->ttis
[0];
912 sp
->ttis
[sp
->typecnt
++] = ts
->ttis
[1];
916 if (sp
->timecnt
> 1) {
917 for (i
= 1; i
< sp
->timecnt
; ++i
)
918 if (typesequiv(sp
, sp
->types
[i
], sp
->types
[0]) &&
919 differ_by_repeat(sp
->ats
[i
], sp
->ats
[0])) {
923 for (i
= sp
->timecnt
- 2; i
>= 0; --i
)
924 if (typesequiv(sp
, sp
->types
[sp
->timecnt
- 1],
926 differ_by_repeat(sp
->ats
[sp
->timecnt
- 1],
940 const struct state
* const sp
;
947 a
< 0 || a
>= sp
->typecnt
||
948 b
< 0 || b
>= sp
->typecnt
)
951 register const struct ttinfo
* ap
= &sp
->ttis
[a
];
952 register const struct ttinfo
* bp
= &sp
->ttis
[b
];
953 result
= ap
->tt_gmtoff
== bp
->tt_gmtoff
&&
954 ap
->tt_isdst
== bp
->tt_isdst
&&
955 ap
->tt_ttisstd
== bp
->tt_ttisstd
&&
956 ap
->tt_ttisgmt
== bp
->tt_ttisgmt
&&
957 strcmp(&sp
->chars
[ap
->tt_abbrind
],
958 &sp
->chars
[bp
->tt_abbrind
]) == 0;
963 static const int mon_lengths
[2][MONSPERYEAR
] = {
964 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
965 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
968 static const int year_lengths
[2] = {
969 DAYSPERNYEAR
, DAYSPERLYEAR
973 ** Given a pointer into a time zone string, scan until a character that is not
974 ** a valid character in a zone name is found. Return a pointer to that
979 getzname(strp
, name
, len
)
987 if (*strp
== '<' && (ket
= strchr(strp
, '>')) != NULL
) {
988 *name
= (char *)(strp
+ 1);
989 *len
= ket
- strp
- 1;
992 *name
= (char *)strp
;
993 while ((c
= *strp
) != '\0' && !is_digit(c
) && c
!= ',' && c
!= '-' &&
1001 ** Given a pointer into an extended time zone string, scan until the ending
1002 ** delimiter of the zone name is located. Return a pointer to the delimiter.
1004 ** As with getzname above, the legal character set is actually quite
1005 ** restricted, with other characters producing undefined results.
1006 ** We don't do any checking here; checking is done later in common-case code.
1010 getqzname(register const char *strp
, const int delim
)
1014 while ((c
= *strp
) != '\0' && c
!= delim
)
1020 ** Given a pointer into a time zone string, extract a number from that string.
1021 ** Check that the number is within a specified range; if it is not, return
1023 ** Otherwise, return a pointer to the first character not part of the number.
1027 getnum(strp
, nump
, min
, max
)
1036 if (strp
== NULL
|| !is_digit(c
= *strp
))
1040 num
= num
* 10 + (c
- '0');
1042 return NULL
; /* illegal value */
1044 } while (is_digit(c
));
1046 return NULL
; /* illegal value */
1052 ** Given a pointer into a time zone string, extract a number of seconds,
1053 ** in hh[:mm[:ss]] form, from the string.
1054 ** If any error occurs, return NULL.
1055 ** Otherwise, return a pointer to the first character not part of the number
1060 getsecs(strp
, secsp
)
1067 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
1068 ** "M10.4.6/26", which does not conform to Posix,
1069 ** but which specifies the equivalent of
1070 ** ``02:00 on the first Sunday on or after 23 Oct''.
1072 strp
= getnum(strp
, &num
, 0, HOURSPERDAY
* DAYSPERWEEK
- 1);
1075 *secsp
= num
* (long) SECSPERHOUR
;
1078 strp
= getnum(strp
, &num
, 0, MINSPERHOUR
- 1);
1081 *secsp
+= num
* SECSPERMIN
;
1084 /* `SECSPERMIN' allows for leap seconds. */
1085 strp
= getnum(strp
, &num
, 0, SECSPERMIN
);
1095 ** Given a pointer into a time zone string, extract an offset, in
1096 ** [+-]hh[:mm[:ss]] form, from the string.
1097 ** If any error occurs, return NULL.
1098 ** Otherwise, return a pointer to the first character not part of the time.
1102 getoffset(strp
, offsetp
)
1104 long * const offsetp
;
1111 } else if (*strp
== '+')
1113 strp
= getsecs(strp
, offsetp
);
1115 return NULL
; /* illegal time */
1117 *offsetp
= -*offsetp
;
1122 ** Given a pointer into a time zone string, extract a rule in the form
1123 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
1124 ** If a valid rule is not found, return NULL.
1125 ** Otherwise, return a pointer to the first character not part of the rule.
1129 getrule(strp
, rulep
)
1131 struct rule
* const rulep
;
1137 rulep
->r_type
= JULIAN_DAY
;
1139 strp
= getnum(strp
, &rulep
->r_day
, 1, DAYSPERNYEAR
);
1140 } else if (*strp
== 'M') {
1142 ** Month, week, day.
1144 rulep
->r_type
= MONTH_NTH_DAY_OF_WEEK
;
1146 strp
= getnum(strp
, &rulep
->r_mon
, 1, MONSPERYEAR
);
1151 strp
= getnum(strp
, &rulep
->r_week
, 1, 5);
1156 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERWEEK
- 1);
1157 } else if (is_digit(*strp
)) {
1161 rulep
->r_type
= DAY_OF_YEAR
;
1162 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERLYEAR
- 1);
1163 } else return NULL
; /* invalid format */
1171 strp
= getsecs(strp
, &rulep
->r_time
);
1172 } else rulep
->r_time
= 2 * SECSPERHOUR
; /* default = 2:00:00 */
1177 ** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
1178 ** year, a rule, and the offset from UTC at the time that rule takes effect,
1179 ** calculate the Epoch-relative time that rule takes effect.
1183 transtime(janfirst
, year
, rulep
, offset
)
1184 const time_t janfirst
;
1186 const struct rule
* const rulep
;
1192 int d
, m1
, yy0
, yy1
, yy2
, dow
;
1195 leapyear
= isleap(year
);
1196 switch (rulep
->r_type
) {
1200 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
1202 ** In non-leap years, or if the day number is 59 or less, just
1203 ** add SECSPERDAY times the day number-1 to the time of
1204 ** January 1, midnight, to get the day.
1206 value
= janfirst
+ (rulep
->r_day
- 1) * SECSPERDAY
;
1207 if (leapyear
&& rulep
->r_day
>= 60)
1208 value
+= SECSPERDAY
;
1214 ** Just add SECSPERDAY times the day number to the time of
1215 ** January 1, midnight, to get the day.
1217 value
= janfirst
+ rulep
->r_day
* SECSPERDAY
;
1220 case MONTH_NTH_DAY_OF_WEEK
:
1222 ** Mm.n.d - nth "dth day" of month m.
1225 for (i
= 0; i
< rulep
->r_mon
- 1; ++i
)
1226 value
+= mon_lengths
[leapyear
][i
] * SECSPERDAY
;
1229 ** Use Zeller's Congruence to get day-of-week of first day of
1232 m1
= (rulep
->r_mon
+ 9) % 12 + 1;
1233 yy0
= (rulep
->r_mon
<= 2) ? (year
- 1) : year
;
1236 dow
= ((26 * m1
- 2) / 10 +
1237 1 + yy2
+ yy2
/ 4 + yy1
/ 4 - 2 * yy1
) % 7;
1242 ** "dow" is the day-of-week of the first day of the month. Get
1243 ** the day-of-month (zero-origin) of the first "dow" day of the
1246 d
= rulep
->r_day
- dow
;
1249 for (i
= 1; i
< rulep
->r_week
; ++i
) {
1250 if (d
+ DAYSPERWEEK
>=
1251 mon_lengths
[leapyear
][rulep
->r_mon
- 1])
1257 ** "d" is the day-of-month (zero-origin) of the day we want.
1259 value
+= d
* SECSPERDAY
;
1264 ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
1265 ** question. To get the Epoch-relative time of the specified local
1266 ** time on that day, add the transition time and the current offset
1269 return value
+ rulep
->r_time
+ offset
;
1273 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
1278 tzparse(name
, sp
, lastditch
)
1280 struct state
* const sp
;
1281 const int lastditch
;
1283 const char * stdname
;
1284 const char * dstname
;
1290 unsigned char * typep
;
1294 INITIALIZE(dstname
);
1297 stdlen
= strlen(name
); /* length of standard zone name */
1299 if (stdlen
>= sizeof sp
->chars
)
1300 stdlen
= (sizeof sp
->chars
) - 1;
1303 name
= getzname(name
, (char **)&stdname
, &stdlen
);
1305 return -1; /* was "stdoffset = 0;" */
1307 name
= getoffset(name
, &stdoffset
);
1313 load_result
= tzload(TZDEFRULES
, sp
, NULL
, FALSE
);
1314 #else /* !NOTIFY_TZ */
1315 load_result
= tzload(TZDEFRULES
, sp
, FALSE
);
1316 #endif /* NOTIFY_TZ */
1317 if (load_result
!= 0)
1318 sp
->leapcnt
= 0; /* so, we're off a little */
1319 if (*name
!= '\0') {
1322 name
= getqzname(name
, '>');
1325 dstlen
= name
- dstname
;
1329 name
= getzname(name
, (char **)&dstname
, &dstlen
);
1331 if (*name
!= '\0' && *name
!= ',' && *name
!= ';') {
1332 name
= getoffset(name
, &dstoffset
);
1335 } else dstoffset
= stdoffset
- SECSPERHOUR
;
1336 if (*name
== '\0' && load_result
!= 0)
1337 name
= TZDEFRULESTRING
;
1338 if (*name
== ',' || *name
== ';') {
1347 if ((name
= getrule(name
, &start
)) == NULL
)
1351 if ((name
= getrule(name
, &end
)) == NULL
)
1355 sp
->typecnt
= 2; /* standard time and DST */
1357 ** Two transitions per year, from EPOCH_YEAR forward.
1359 sp
->ttis
[0].tt_gmtoff
= -dstoffset
;
1360 sp
->ttis
[0].tt_isdst
= 1;
1361 sp
->ttis
[0].tt_abbrind
= stdlen
+ 1;
1362 sp
->ttis
[1].tt_gmtoff
= -stdoffset
;
1363 sp
->ttis
[1].tt_isdst
= 0;
1364 sp
->ttis
[1].tt_abbrind
= 0;
1369 for (year
= EPOCH_YEAR
;
1370 sp
->timecnt
+ 2 <= TZ_MAX_TIMES
;
1374 starttime
= transtime(janfirst
, year
, &start
,
1376 endtime
= transtime(janfirst
, year
, &end
,
1378 if (starttime
> endtime
) {
1380 *typep
++ = 1; /* DST ends */
1382 *typep
++ = 0; /* DST begins */
1385 *typep
++ = 0; /* DST begins */
1387 *typep
++ = 1; /* DST ends */
1390 newfirst
= janfirst
;
1391 newfirst
+= year_lengths
[isleap(year
)] *
1393 if (newfirst
<= janfirst
)
1395 janfirst
= newfirst
;
1398 long theirstdoffset
;
1399 long theirdstoffset
;
1408 ** Initial values of theirstdoffset and theirdstoffset.
1411 for (i
= 0; i
< sp
->timecnt
; ++i
) {
1413 if (!sp
->ttis
[j
].tt_isdst
) {
1415 -sp
->ttis
[j
].tt_gmtoff
;
1420 for (i
= 0; i
< sp
->timecnt
; ++i
) {
1422 if (sp
->ttis
[j
].tt_isdst
) {
1424 -sp
->ttis
[j
].tt_gmtoff
;
1429 ** Initially we're assumed to be in standard time.
1432 theiroffset
= theirstdoffset
;
1434 ** Now juggle transition times and types
1435 ** tracking offsets as you do.
1437 for (i
= 0; i
< sp
->timecnt
; ++i
) {
1439 sp
->types
[i
] = sp
->ttis
[j
].tt_isdst
;
1440 if (sp
->ttis
[j
].tt_ttisgmt
) {
1441 /* No adjustment to transition time */
1444 ** If summer time is in effect, and the
1445 ** transition time was not specified as
1446 ** standard time, add the summer time
1447 ** offset to the transition time;
1448 ** otherwise, add the standard time
1449 ** offset to the transition time.
1452 ** Transitions from DST to DDST
1453 ** will effectively disappear since
1454 ** POSIX provides for only one DST
1457 if (isdst
&& !sp
->ttis
[j
].tt_ttisstd
) {
1458 sp
->ats
[i
] += dstoffset
-
1461 sp
->ats
[i
] += stdoffset
-
1465 theiroffset
= -sp
->ttis
[j
].tt_gmtoff
;
1466 if (sp
->ttis
[j
].tt_isdst
)
1467 theirdstoffset
= theiroffset
;
1468 else theirstdoffset
= theiroffset
;
1471 ** Finally, fill in ttis.
1472 ** ttisstd and ttisgmt need not be handled.
1474 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
1475 sp
->ttis
[0].tt_isdst
= FALSE
;
1476 sp
->ttis
[0].tt_abbrind
= 0;
1477 sp
->ttis
[1].tt_gmtoff
= -dstoffset
;
1478 sp
->ttis
[1].tt_isdst
= TRUE
;
1479 sp
->ttis
[1].tt_abbrind
= stdlen
+ 1;
1484 sp
->typecnt
= 1; /* only standard time */
1486 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
1487 sp
->ttis
[0].tt_isdst
= 0;
1488 sp
->ttis
[0].tt_abbrind
= 0;
1490 sp
->charcnt
= stdlen
+ 1;
1492 sp
->charcnt
+= dstlen
+ 1;
1493 if ((size_t) sp
->charcnt
> sizeof sp
->chars
)
1496 (void) strncpy(cp
, stdname
, stdlen
);
1500 (void) strncpy(cp
, dstname
, dstlen
);
1501 *(cp
+ dstlen
) = '\0';
1509 #else /* ! NOTIFY_TZ */
1511 #endif /* NOTIFY_TZ */
1512 struct state
* const sp
;
1515 #endif /* NOTIFY_TZ */
1518 if (tzload(gmt
, sp
, path
, TRUE
) != 0)
1519 #else /* ! NOTIFY_TZ */
1520 if (tzload(gmt
, sp
, TRUE
) != 0)
1521 #endif /* NOTIFY_TZ */
1522 (void) tzparse(gmt
, sp
, TRUE
);
1526 * In NULL_BOOTSTRAP environments, we can't use notifyd to learn about the changes in timezone.
1527 * Instead, we look at the modified time of the TZDEFAULT symlink.
1528 * As a performance optimization, we only reload the timezone data if the modified time is newer than the
1529 * last time we loaded the timezone file.
1531 * If the tzload fails, we need to reset the saved timestamp to force the timezone file to be reloaded next time
1532 * we try to use it. This is a special case that occurs at first boot for launchd (and other early boot-tasks)
1535 static struct timespec last_default_tzload_mtimespec
= {0, 0};
1537 tzsetwall_check_default_file_timestamp(void)
1543 struct stat statbuf
;
1545 if (lstat(TZDEFAULT
, &statbuf
) == 0) {
1546 if (statbuf
.st_mtimespec
.tv_sec
> last_default_tzload_mtimespec
.tv_sec
||
1547 (statbuf
.st_mtimespec
.tv_sec
== last_default_tzload_mtimespec
.tv_sec
&&
1548 statbuf
.st_mtimespec
.tv_nsec
> last_default_tzload_mtimespec
.tv_nsec
)) {
1549 /* Trigger resetting the local TZ */
1552 last_default_tzload_mtimespec
= statbuf
.st_mtimespec
;
1557 tzsetwall_basic(int rdlocked
)
1560 if (bootstrap_port
!= MACH_PORT_NULL
) {
1561 notify_check_tz(&lcl_notify
);
1563 tzsetwall_check_default_file_timestamp();
1566 tzsetwall_check_default_file_timestamp();
1567 #endif /* NOTIFY_TZ */
1570 _RWLOCK_RDLOCK(&lcl_rwlock
);
1571 if (lcl_is_set
< 0) {
1572 #ifdef NOTIFY_TZ_DEBUG
1573 NOTIFY_TZ_PRINTF("tzsetwall_basic lcl_is_set < 0\n");
1576 _RWLOCK_UNLOCK(&lcl_rwlock
);
1579 #ifdef NOTIFY_TZ_DEBUG
1580 NOTIFY_TZ_PRINTF("tzsetwall_basic not set\n");
1582 _RWLOCK_UNLOCK(&lcl_rwlock
);
1584 _RWLOCK_WRLOCK(&lcl_rwlock
);
1588 if (lclptr
== NULL
) {
1589 lclptr
= calloc(1, sizeof *lclptr
);
1590 if (lclptr
== NULL
) {
1591 settzname(); /* all we can do */
1592 _RWLOCK_UNLOCK(&lcl_rwlock
);
1594 _RWLOCK_RDLOCK(&lcl_rwlock
);
1598 #endif /* defined ALL_STATE */
1601 char fullname
[FILENAME_MAX
+ 1];
1602 if (tzload((char *) NULL
, lclptr
, fullname
, TRUE
) != 0) {
1603 // The load failed, so we need to reset the cached modified time
1604 // of the timezone file
1605 last_default_tzload_mtimespec
= (const struct timespec
){0};
1608 * If fullname is empty (an error occurred) then
1609 * default to the UTC path
1611 gmtload(lclptr
, *fullname
? NULL
: fullname
);
1613 notify_register_tz(fullname
, &lcl_notify
);
1615 #else /* ! NOTIFY_TZ */
1616 if (tzload((char *) NULL
, lclptr
, TRUE
) != 0)
1618 #endif /* NOTIFY_TZ */
1620 _RWLOCK_UNLOCK(&lcl_rwlock
);
1623 _RWLOCK_RDLOCK(&lcl_rwlock
);
1629 #ifdef NOTIFY_TZ_DEBUG
1630 NOTIFY_TZ_PRINTF("tzsetwall called\n");
1631 #endif /* NOTIFY_TZ_DEBUG */
1635 __private_extern__
void
1636 tzset_basic(int rdlocked
)
1640 name
= getenv("TZ");
1642 tzsetwall_basic(rdlocked
);
1647 notify_check_tz(&lcl_notify
);
1648 #endif /* NOTIFY_TZ */
1650 _RWLOCK_RDLOCK(&lcl_rwlock
);
1651 if (lcl_is_set
> 0 && strcmp(lcl_TZname
, name
) == 0) {
1653 _RWLOCK_UNLOCK(&lcl_rwlock
);
1654 #ifdef NOTIFY_TZ_DEBUG
1655 NOTIFY_TZ_PRINTF("tzset_basic matched %s\n", lcl_TZname
);
1659 _RWLOCK_UNLOCK(&lcl_rwlock
);
1661 _RWLOCK_WRLOCK(&lcl_rwlock
);
1662 lcl_is_set
= strlen(name
) < sizeof lcl_TZname
;
1664 (void) strcpy(lcl_TZname
, name
);
1667 if (lclptr
== NULL
) {
1668 lclptr
= (struct state
*) calloc(1, sizeof *lclptr
);
1669 if (lclptr
== NULL
) {
1670 settzname(); /* all we can do */
1671 _RWLOCK_UNLOCK(&lcl_rwlock
);
1673 _RWLOCK_RDLOCK(&lcl_rwlock
);
1677 #endif /* defined ALL_STATE */
1678 if (*name
== '\0') {
1680 ** User wants it fast rather than right.
1682 lclptr
->leapcnt
= 0; /* so, we're off a little */
1683 lclptr
->timecnt
= 0;
1684 lclptr
->typecnt
= 0;
1685 lclptr
->ttis
[0].tt_isdst
= 0;
1686 lclptr
->ttis
[0].tt_gmtoff
= 0;
1687 lclptr
->ttis
[0].tt_abbrind
= 0;
1688 (void) strcpy(lclptr
->chars
, gmt
);
1690 notify_register_tz(NULL
, &lcl_notify
);
1691 #endif /* NOTIFY_TZ */
1695 char fullname
[FILENAME_MAX
+ 1];
1697 * parsedOK indicates whether tzparse() was called and
1698 * succeeded. This means that TZ is a time conversion
1699 * specification, so we don't need to register for
1702 int parsedOK
= FALSE
;
1703 if (tzload(name
, lclptr
, fullname
, TRUE
) != 0) {
1704 if (name
[0] == ':' || !(parsedOK
= tzparse(name
, lclptr
, FALSE
) == 0)) {
1706 * If fullname is empty (an error occurred) then
1707 * default to the UTC path
1709 (void) gmtload(lclptr
, *fullname
? NULL
: fullname
);
1712 notify_register_tz(parsedOK
? NULL
: fullname
, &lcl_notify
);
1714 #else /* ! NOTIFY_TZ */
1715 if (tzload(name
, lclptr
, TRUE
) != 0)
1716 if (name
[0] == ':' || tzparse(name
, lclptr
, FALSE
) != 0)
1717 (void) gmtload(lclptr
);
1718 #endif /* NOTIFY_TZ */
1720 _RWLOCK_UNLOCK(&lcl_rwlock
);
1723 _RWLOCK_RDLOCK(&lcl_rwlock
);
1729 #ifdef NOTIFY_TZ_DEBUG
1730 NOTIFY_TZ_PRINTF("tzset called TZ=%s\n", getenv("TZ"));
1731 #endif /* NOTIFY_TZ_DEBUG */
1736 ** The easy way to behave "as if no library function calls" localtime
1737 ** is to not call it--so we drop its guts into "localsub", which can be
1738 ** freely called. (And no, the PANS doesn't require the above behavior--
1739 ** but it *is* desirable.)
1741 ** The unused offset argument is for the benefit of mktime variants.
1746 __private_extern__
struct tm
*
1747 #else /* !__LP64__ */
1748 __private_extern__
void
1749 #endif /* __LP64__ */
1750 localsub(const time_t *const timep
, const long offset
, struct tm
*const tmp
)
1753 const struct ttinfo
* ttisp
;
1757 #endif /* __LP64__ */
1758 const time_t t
= *timep
;
1760 #ifdef NOTIFY_TZ_DEBUG
1761 NOTIFY_TZ_PRINTF("localsub called\n");
1762 #endif /* NOTIFY_TZ_DEBUG */
1767 return gmtsub(timep
, offset
, tmp
);
1768 #else /* !__LP64__ */
1769 gmtsub(timep
, offset
, tmp
);
1771 #endif /* __LP64__ */
1773 #endif /* defined ALL_STATE */
1774 if ((sp
->goback
&& t
< sp
->ats
[0]) ||
1775 (sp
->goahead
&& t
> sp
->ats
[sp
->timecnt
- 1])) {
1777 register time_t seconds
;
1778 register time_t tcycles
;
1779 register int_fast64_t icycles
;
1782 seconds
= sp
->ats
[0] - t
;
1783 else seconds
= t
- sp
->ats
[sp
->timecnt
- 1];
1785 tcycles
= seconds
/ YEARSPERREPEAT
/ AVGSECSPERYEAR
;
1788 if (tcycles
- icycles
>= 1 || icycles
- tcycles
>= 1) {
1791 #else /* !__LP64__ */
1793 #endif /* __LP64__ */
1796 seconds
*= YEARSPERREPEAT
;
1797 seconds
*= AVGSECSPERYEAR
;
1800 else newt
-= seconds
;
1801 if (newt
< sp
->ats
[0] ||
1802 newt
> sp
->ats
[sp
->timecnt
- 1])
1804 return NULL
; /* "cannot happen" */
1805 result
= localsub(&newt
, offset
, tmp
);
1806 if (result
== tmp
) {
1807 #else /* !__LP64__ */
1809 localsub(&newt
, offset
, tmp
);
1811 #endif /* __LP64__ */
1812 register time_t newy
;
1814 newy
= tmp
->tm_year
;
1816 newy
-= icycles
* YEARSPERREPEAT
;
1817 else newy
+= icycles
* YEARSPERREPEAT
;
1818 tmp
->tm_year
= newy
;
1819 if (tmp
->tm_year
!= newy
)
1824 #else /* !__LP64__ */
1828 #endif /* __LP64__ */
1830 if (sp
->timecnt
== 0 || t
< sp
->ats
[0]) {
1832 while (sp
->ttis
[i
].tt_isdst
)
1833 if (++i
>= sp
->typecnt
) {
1838 register int lo
= 1;
1839 register int hi
= sp
->timecnt
;
1842 register int mid
= (lo
+ hi
) >> 1;
1844 if (t
< sp
->ats
[mid
])
1848 i
= (int) sp
->types
[lo
- 1];
1850 ttisp
= &sp
->ttis
[i
];
1852 ** To get (wrong) behavior that's compatible with System V Release 2.0
1853 ** you'd replace the statement below with
1854 ** t += ttisp->tt_gmtoff;
1855 ** timesub(&t, 0L, sp, tmp);
1858 result
= timesub(&t
, ttisp
->tt_gmtoff
, sp
, tmp
);
1861 #else /* !__LP64__ */
1862 timesub(&t
, ttisp
->tt_gmtoff
, sp
, tmp
);
1863 #endif /* __LP64__ */
1864 tmp
->tm_isdst
= ttisp
->tt_isdst
;
1865 tzname
[tmp
->tm_isdst
] = &sp
->chars
[ttisp
->tt_abbrind
];
1867 tmp
->TM_ZONE
= &sp
->chars
[ttisp
->tt_abbrind
];
1868 #endif /* defined TM_ZONE */
1871 #endif /* __LP64__ */
1875 localtime_key_init(void)
1878 localtime_key
= __LIBC_PTHREAD_KEY_LOCALTIME
;
1879 localtime_key_error
= pthread_key_init_np(localtime_key
, free
);
1883 localtime(const time_t *const timep
)
1887 if (__isthreaded
!= 0) {
1888 _pthread_once(&localtime_once
, localtime_key_init
);
1889 if (localtime_key_error
!= 0) {
1890 errno
= localtime_key_error
;
1893 p_tm
= _pthread_getspecific(localtime_key
);
1895 if ((p_tm
= (struct tm
*)malloc(sizeof(struct tm
)))
1898 _pthread_setspecific(localtime_key
, p_tm
);
1900 _RWLOCK_RDLOCK(&lcl_rwlock
);
1903 p_tm
= localsub(timep
, 0L, p_tm
);
1904 #else /* !__LP64__ */
1905 localsub(timep
, 0L, p_tm
);
1906 #endif /* __LP64__ */
1907 _RWLOCK_UNLOCK(&lcl_rwlock
);
1912 return localsub(timep
, 0L, &tm
);
1913 #else /* !__LP64__ */
1914 localsub(timep
, 0L, &tm
);
1916 #endif /* __LP64__ */
1921 ** Re-entrant version of localtime.
1925 localtime_r(const time_t *const __restrict timep
, struct tm
* __restrict tmp
)
1927 _RWLOCK_RDLOCK(&lcl_rwlock
);
1930 tmp
= localsub(timep
, 0L, tmp
);
1931 #else /* !__LP64__ */
1932 localsub(timep
, 0L, tmp
);
1933 #endif /* __LP64__ */
1934 _RWLOCK_UNLOCK(&lcl_rwlock
);
1945 #endif /* NOTIFY_TZ */
1946 gmtptr
= (struct state
*) calloc(1, sizeof *gmtptr
);
1948 #endif /* defined ALL_STATE */
1951 char fullname
[FILENAME_MAX
+ 1];
1952 gmtload(gmtptr
, fullname
);
1953 notify_register_tz(fullname
, &gmt_notify
);
1955 #else /* ! NOTIFY_TZ */
1957 #endif /* NOTIFY_TZ */
1961 ** gmtsub is to gmtime as localsub is to localtime.
1966 #else /* !__LP64__ */
1968 #endif /* __LP64__ */
1969 gmtsub(timep
, offset
, tmp
)
1970 const time_t * const timep
;
1972 struct tm
* const tmp
;
1975 register struct tm
* result
;
1976 #endif /* __LP64__ */
1978 #ifdef NOTIFY_TZ_DEBUG
1979 NOTIFY_TZ_PRINTF("gmtsub called\n");
1980 #endif /* NOTIFY_TZ_DEBUG */
1982 notify_check_tz(&gmt_notify
);
1983 #endif /* NOTIFY_TZ */
1984 pthread_once(&gmt_once
, gmt_init
);
1986 result
= timesub(timep
, offset
, gmtptr
, tmp
);
1989 #else /* !__LP64__ */
1990 timesub(timep
, offset
, gmtptr
, tmp
);
1991 #endif /* __LP64__ */
1994 ** Could get fancy here and deliver something such as
1995 ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
1996 ** but this is no time for a treasure hunt.
1999 tmp
->TM_ZONE
= (char*)wildabbr
;
2003 tmp
->TM_ZONE
= (char *)gmt
;
2004 else tmp
->TM_ZONE
= gmtptr
->chars
;
2005 #endif /* defined ALL_STATE */
2007 tmp
->TM_ZONE
= gmtptr
->chars
;
2008 #endif /* State Farm */
2010 #endif /* defined TM_ZONE */
2013 #endif /* __LP64__ */
2017 gmtime_key_init(void)
2020 gmtime_key
= __LIBC_PTHREAD_KEY_GMTIME
;
2021 gmtime_key_error
= pthread_key_init_np(gmtime_key
, free
);
2025 gmtime(const time_t *const timep
)
2029 if (__isthreaded
!= 0) {
2030 _pthread_once(&gmtime_once
, gmtime_key_init
);
2031 if (gmtime_key_error
!= 0) {
2032 errno
= gmtime_key_error
;
2036 * Changed to follow POSIX.1 threads standard, which
2037 * is what BSD currently has.
2039 if ((p_tm
= _pthread_getspecific(gmtime_key
)) == NULL
) {
2040 if ((p_tm
= (struct tm
*)malloc(sizeof(struct tm
)))
2044 _pthread_setspecific(gmtime_key
, p_tm
);
2047 return gmtsub(timep
, 0L, p_tm
);
2048 #else /* !__LP64__ */
2049 gmtsub(timep
, 0L, p_tm
);
2051 #endif /* __LP64__ */
2055 return gmtsub(timep
, 0L, &tm
);
2056 #else /* !__LP64__ */
2057 gmtsub(timep
, 0L, &tm
);
2059 #endif /* __LP64__ */
2064 * Re-entrant version of gmtime.
2068 gmtime_r(const time_t *const timep
, struct tm
*tmp
)
2072 return gmtsub(timep
, 0L, tmp
);
2073 #else /* !__LP64__ */
2074 gmtsub(timep
, 0L, tmp
);
2076 #endif /* __LP64__ */
2082 offtime(const time_t *const timep
, const long offset
)
2085 return gmtsub(timep
, offset
, &tm
);
2086 #else /* !__LP64__ */
2087 gmtsub(timep
, offset
, &tm
);
2089 #endif /* __LP64__ */
2092 #endif /* defined STD_INSPIRED */
2095 ** Return the number of leap years through the end of the given year
2096 ** where, to make the math easy, the answer for year zero is defined as zero.
2100 leaps_thru_end_of(y
)
2101 register const int y
;
2104 return (y
>= 0) ? (y
/ 4 - y
/ 100 + y
/ 400) :
2105 -(leaps_thru_end_of(-(y
+ 1)) + 1);
2106 #else /* !__LP64__ */
2107 return (y
/ 4 - y
/ 100 + y
/ 400);
2108 #endif /* __LP64__ */
2113 #else /* !__LP64__ */
2115 #endif /* __LP64__ */
2116 timesub(timep
, offset
, sp
, tmp
)
2117 const time_t * const timep
;
2119 const struct state
* const sp
;
2120 struct tm
* const tmp
;
2122 const struct lsinfo
* lp
;
2135 i
= (sp
== NULL
) ? 0 : sp
->leapcnt
;
2136 #endif /* defined ALL_STATE */
2139 #endif /* State Farm */
2142 if (*timep
>= lp
->ls_trans
) {
2143 if (*timep
== lp
->ls_trans
) {
2144 hit
= ((i
== 0 && lp
->ls_corr
> 0) ||
2145 lp
->ls_corr
> sp
->lsis
[i
- 1].ls_corr
);
2148 sp
->lsis
[i
].ls_trans
==
2149 sp
->lsis
[i
- 1].ls_trans
+ 1 &&
2150 sp
->lsis
[i
].ls_corr
==
2151 sp
->lsis
[i
- 1].ls_corr
+ 1) {
2160 days
= *timep
/ SECSPERDAY
;
2161 rem
= *timep
% SECSPERDAY
;
2163 if (*timep
== 0x80000000) {
2165 ** A 3B1 muffs the division on the most negative number.
2170 #endif /* defined mc68k */
2171 rem
+= (offset
- corr
);
2176 while (rem
>= SECSPERDAY
) {
2180 tmp
->tm_hour
= (int) (rem
/ SECSPERHOUR
);
2181 rem
= rem
% SECSPERHOUR
;
2182 tmp
->tm_min
= (int) (rem
/ SECSPERMIN
);
2184 ** A positive leap second requires a special
2185 ** representation. This uses "... ??:59:60" et seq.
2187 tmp
->tm_sec
= (int) (rem
% SECSPERMIN
) + hit
;
2188 tmp
->tm_wday
= (int) ((EPOCH_WDAY
+ days
) % DAYSPERWEEK
);
2189 if (tmp
->tm_wday
< 0)
2190 tmp
->tm_wday
+= DAYSPERWEEK
;
2192 #define _LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
2194 #define LEAPS_THRU_END_OF(y) ((y) >= 0 ? _LEAPS_THRU_END_OF(y) : _LEAPS_THRU_END_OF((y) + 1) - 1)
2195 #else /* !__LP64__ */
2196 #define LEAPS_THRU_END_OF(y) _LEAPS_THRU_END_OF(y)
2197 #endif /* __LP64__ */
2198 while (days
< 0 || days
>= (long) year_lengths
[yleap
= isleap(y
)]) {
2201 newy
= y
+ days
/ DAYSPERNYEAR
;
2204 days
-= (newy
- y
) * DAYSPERNYEAR
+
2205 LEAPS_THRU_END_OF(newy
- 1) -
2206 LEAPS_THRU_END_OF(y
- 1);
2211 if (y
< INT_MIN
|| y
> INT_MAX
) {
2216 #else /* !__LP64__ */
2217 tmp
->tm_year
= y
- TM_YEAR_BASE
;
2218 #endif /* __LP64__ */
2219 tmp
->tm_yday
= (int) days
;
2220 ip
= mon_lengths
[yleap
];
2221 for (tmp
->tm_mon
= 0; days
>= (long) ip
[tmp
->tm_mon
]; ++(tmp
->tm_mon
))
2222 days
= days
- (long) ip
[tmp
->tm_mon
];
2223 tmp
->tm_mday
= (int) (days
+ 1);
2226 tmp
->TM_GMTOFF
= offset
;
2227 #endif /* defined TM_GMTOFF */
2230 #endif /* __LP64__ */
2234 ctime(const time_t *const timep
)
2237 ** Section 4.12.3.2 of X3.159-1989 requires that
2238 ** The ctime function converts the calendar time pointed to by timer
2239 ** to local time in the form of a string. It is equivalent to
2240 ** asctime(localtime(timer))
2244 * In 64-bit, the timep value may produce a time value with a year
2245 * that exceeds 32-bits in size (won't fit in struct tm), so localtime
2248 struct tm
*tm
= localtime(timep
);
2253 #else /* !__LP64__ */
2254 return asctime(localtime(timep
));
2255 #endif /* __LP64__ */
2259 ctime_r(const time_t *const timep
, char *buf
)
2265 * In 64-bit, the timep value may produce a time value with a year
2266 * that exceeds 32-bits in size (won't fit in struct tm), so localtime_r
2269 if (localtime_r(timep
, &mytm
) == NULL
)
2271 return asctime_r(&mytm
, buf
);
2272 #else /* !__LP64__ */
2273 return asctime_r(localtime_r(timep
, &mytm
), buf
);
2274 #endif /* __LP64__ */
2278 ** Adapted from code provided by Robert Elz, who writes:
2279 ** The "best" way to do mktime I think is based on an idea of Bob
2280 ** Kridle's (so its said...) from a long time ago.
2281 ** It does a binary search of the time_t space. Since time_t's are
2282 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
2283 ** would still be very reasonable).
2288 #endif /* !defined WRONG */
2291 ** Simplified normalize logic courtesy Paul Eggert.
2295 increment_overflow(number
, delta
)
2303 return (*number
< number0
) != (delta
< 0);
2307 long_increment_overflow(number
, delta
)
2315 return (*number
< number0
) != (delta
< 0);
2319 normalize_overflow(int *const tensptr
, int *const unitsptr
, const int base
)
2323 tensdelta
= (*unitsptr
>= 0) ?
2324 (*unitsptr
/ base
) :
2325 (-1 - (-1 - *unitsptr
) / base
);
2326 *unitsptr
-= tensdelta
* base
;
2327 return increment_overflow(tensptr
, tensdelta
);
2331 long_normalize_overflow(long *const tensptr
, int *const unitsptr
, const int base
)
2333 register int tensdelta
;
2335 tensdelta
= (*unitsptr
>= 0) ?
2336 (*unitsptr
/ base
) :
2337 (-1 - (-1 - *unitsptr
) / base
);
2338 *unitsptr
-= tensdelta
* base
;
2339 return long_increment_overflow(tensptr
, tensdelta
);
2344 const struct tm
* const atmp
;
2345 const struct tm
* const btmp
;
2350 * Assume that atmp and btmp point to normalized tm strutures.
2351 * So only arithmetic with tm_year could overflow in 64-bit.
2353 if (atmp
->tm_year
!= btmp
->tm_year
) {
2354 return (atmp
->tm_year
> btmp
->tm_year
? 1 : -1);
2356 if ((result
= (atmp
->tm_mon
- btmp
->tm_mon
)) == 0 &&
2357 (result
= (atmp
->tm_mday
- btmp
->tm_mday
)) == 0 &&
2358 (result
= (atmp
->tm_hour
- btmp
->tm_hour
)) == 0 &&
2359 (result
= (atmp
->tm_min
- btmp
->tm_min
)) == 0)
2360 result
= atmp
->tm_sec
- btmp
->tm_sec
;
2365 time2sub(struct tm
*const tmp
,
2367 struct tm
*(*const funcp
)(const time_t *, long, struct tm
*),
2368 #else /* !__LP64__ */
2369 void(*funcp
) (const time_t *, long, struct tm
*),
2370 #endif /* __LP64__ */
2373 const int do_norm_secs
,
2376 const struct state
* sp
;
2386 struct tm yourtm
, mytm
;
2391 if (normalize_overflow(&yourtm
.tm_min
, &yourtm
.tm_sec
,
2395 if (normalize_overflow(&yourtm
.tm_hour
, &yourtm
.tm_min
, MINSPERHOUR
))
2397 if (normalize_overflow(&yourtm
.tm_mday
, &yourtm
.tm_hour
, HOURSPERDAY
))
2400 if (long_normalize_overflow(&y
, &yourtm
.tm_mon
, MONSPERYEAR
))
2403 ** Turn y into an actual year number for now.
2404 ** It is converted back to an offset from TM_YEAR_BASE later.
2406 if (long_increment_overflow(&y
, TM_YEAR_BASE
))
2408 while (yourtm
.tm_mday
<= 0) {
2409 if (long_increment_overflow(&y
, -1))
2411 li
= y
+ (1 < yourtm
.tm_mon
);
2412 yourtm
.tm_mday
+= year_lengths
[isleap(li
)];
2414 while (yourtm
.tm_mday
> DAYSPERLYEAR
) {
2415 li
= y
+ (1 < yourtm
.tm_mon
);
2416 yourtm
.tm_mday
-= year_lengths
[isleap(li
)];
2417 if (long_increment_overflow(&y
, 1))
2421 i
= mon_lengths
[isleap(y
)][yourtm
.tm_mon
];
2422 if (yourtm
.tm_mday
<= i
)
2424 yourtm
.tm_mday
-= i
;
2425 if (++yourtm
.tm_mon
>= MONSPERYEAR
) {
2427 if (long_increment_overflow(&y
, 1))
2431 if (long_increment_overflow(&y
, -TM_YEAR_BASE
))
2434 if (yourtm
.tm_year
!= y
)
2436 /* Don't go below 1900 for POLA */
2437 if (yourtm
.tm_year
< 0)
2439 if (yourtm
.tm_sec
>= 0 && yourtm
.tm_sec
< SECSPERMIN
)
2441 else if (y
+ TM_YEAR_BASE
< EPOCH_YEAR
) {
2443 ** We can't set tm_sec to 0, because that might push the
2444 ** time below the minimum representable time.
2445 ** Set tm_sec to 59 instead.
2446 ** This assumes that the minimum representable time is
2447 ** not in the same minute that a leap second was deleted from,
2448 ** which is a safer assumption than using 58 would be.
2450 if (increment_overflow(&yourtm
.tm_sec
, 1 - SECSPERMIN
))
2452 saved_seconds
= yourtm
.tm_sec
;
2453 yourtm
.tm_sec
= SECSPERMIN
- 1;
2455 saved_seconds
= yourtm
.tm_sec
;
2459 ** Do a binary search (this works whatever time_t's type is).
2461 if (!TYPE_SIGNED(time_t)) {
2464 } else if (!TYPE_INTEGRAL(time_t)) {
2465 if (sizeof(time_t) > sizeof(float))
2466 hi
= (time_t) DBL_MAX
;
2467 else hi
= (time_t) FLT_MAX
;
2471 for (i
= 0; i
< (int) TYPE_BIT(time_t) - 1; ++i
)
2476 t
= lo
/ 2 + hi
/ 2;
2482 if ((*funcp
)(&t
, offset
, &mytm
) == NULL
) {
2484 ** Assume that t is too extreme to be represented in
2485 ** a struct tm; arrange things so that it is less
2486 ** extreme on the next pass.
2488 dir
= (t
> 0) ? 1 : -1;
2489 } else dir
= tmcomp(&mytm
, &yourtm
);
2490 #else /* !__LP64__ */
2491 (*funcp
)(&t
, offset
, &mytm
);
2492 dir
= tmcomp(&mytm
, &yourtm
);
2493 // If we have searched the entire space without a match, exit
2494 if (dir
!= 0 && t
== lo
&& t
== hi
)
2496 #endif /* __LP64__ */
2503 } else if (t
== hi
) {
2516 sp
= (funcp
== localsub
) ? lclptr
: gmtptr
;
2517 if (unix03
&& sp
->typecnt
== 1 && yourtm
.tm_isdst
> 0)
2518 yourtm
.tm_isdst
= 0; /* alternative time does not apply */
2519 if (yourtm
.tm_isdst
< 0 || mytm
.tm_isdst
== yourtm
.tm_isdst
)
2522 ** Right time, wrong type.
2523 ** Hunt for right time, right type.
2524 ** It's okay to guess wrong since the guess
2530 #endif /* defined ALL_STATE */
2531 for (i
= sp
->typecnt
- 1; i
>= 0; --i
) {
2532 if (sp
->ttis
[i
].tt_isdst
!= yourtm
.tm_isdst
)
2534 for (j
= sp
->typecnt
- 1; j
>= 0; --j
) {
2535 if (sp
->ttis
[j
].tt_isdst
== yourtm
.tm_isdst
)
2537 newt
= t
+ sp
->ttis
[j
].tt_gmtoff
-
2538 sp
->ttis
[i
].tt_gmtoff
;
2540 if ((*funcp
)(&newt
, offset
, &mytm
) == NULL
)
2542 #else /* !__LP64__ */
2543 (*funcp
)(&newt
, offset
, &mytm
);
2544 #endif /* __LP64__ */
2545 if (tmcomp(&mytm
, &yourtm
) != 0)
2547 if (mytm
.tm_isdst
!= yourtm
.tm_isdst
)
2559 newt
= t
+ saved_seconds
;
2560 if ((newt
< t
) != (saved_seconds
< 0))
2564 if ((*funcp
)(&t
, offset
, tmp
) == NULL
)
2566 #else /* !__LP64__ */
2567 (*funcp
)(&t
, offset
, tmp
);
2568 #endif /* __LP64__ */
2574 time2(struct tm
* const tmp
,
2576 struct tm
* (*const funcp
)(const time_t *, long, struct tm
*),
2577 #else /* !__LP64__ */
2578 void (*const funcp
)(const time_t *, long, struct tm
*),
2579 #endif /* __LP64__ */
2587 ** First try without normalization of seconds
2588 ** (in case tm_sec contains a value associated with a leap second).
2589 ** If that fails, try with normalization of seconds.
2591 t
= time2sub(tmp
, funcp
, offset
, okayp
, FALSE
, unix03
);
2592 return *okayp
? t
: time2sub(tmp
, funcp
, offset
, okayp
, TRUE
, unix03
);
2595 __private_extern__
time_t
2596 time1(tmp
, funcp
, offset
, unix03
)
2597 struct tm
* const tmp
;
2599 struct tm
* (* const funcp
)(const time_t *, long, struct tm
*);
2600 #else /* !__LP64__ */
2601 void (* const funcp
)(const time_t *, long, struct tm
*);
2602 #endif /* __LP64__ */
2607 const struct state
* sp
;
2609 int sameind
, otherind
;
2612 int seen
[TZ_MAX_TYPES
];
2613 int types
[TZ_MAX_TYPES
];
2621 if (tmp
->tm_isdst
> 1)
2623 t
= time2(tmp
, funcp
, offset
, &okay
, unix03
);
2626 ** PCTS code courtesy Grant Sullivan.
2630 if (tmp
->tm_isdst
< 0)
2631 tmp
->tm_isdst
= 0; /* reset to std and try again */
2632 #endif /* defined PCTS */
2634 if (okay
|| tmp
->tm_isdst
< 0)
2636 #endif /* !defined PCTS */
2638 ** We're supposed to assume that somebody took a time of one type
2639 ** and did some math on it that yielded a "struct tm" that's bad.
2640 ** We try to divine the type they started from and adjust to the
2643 sp
= (const struct state
*) ((funcp
== localsub
) ? lclptr
: gmtptr
);
2647 #endif /* defined ALL_STATE */
2648 for (i
= 0; i
< sp
->typecnt
; ++i
)
2651 for (i
= sp
->timecnt
- 1; i
>= 0; --i
)
2652 if (!seen
[sp
->types
[i
]]) {
2653 seen
[sp
->types
[i
]] = TRUE
;
2654 types
[nseen
++] = sp
->types
[i
];
2656 for (sameind
= 0; sameind
< nseen
; ++sameind
) {
2657 samei
= types
[sameind
];
2658 if (sp
->ttis
[samei
].tt_isdst
!= tmp
->tm_isdst
)
2660 for (otherind
= 0; otherind
< nseen
; ++otherind
) {
2661 otheri
= types
[otherind
];
2662 if (sp
->ttis
[otheri
].tt_isdst
== tmp
->tm_isdst
)
2664 tmp
->tm_sec
+= sp
->ttis
[otheri
].tt_gmtoff
-
2665 sp
->ttis
[samei
].tt_gmtoff
;
2666 tmp
->tm_isdst
= !tmp
->tm_isdst
;
2667 t
= time2(tmp
, funcp
, offset
, &okay
, unix03
);
2670 tmp
->tm_sec
-= sp
->ttis
[otheri
].tt_gmtoff
-
2671 sp
->ttis
[samei
].tt_gmtoff
;
2672 tmp
->tm_isdst
= !tmp
->tm_isdst
;
2677 #else /* BUILDING_VARIANT */
2678 extern pthread_rwlock_t lcl_rwlock
;
2679 #endif /* BUILDING_VARIANT */
2682 mktime(struct tm
*const tmp
)
2684 time_t mktime_return_value
;
2686 _RWLOCK_RDLOCK(&lcl_rwlock
);
2688 mktime_return_value
= time1(tmp
, localsub
, 0L, __DARWIN_UNIX03
);
2689 _RWLOCK_UNLOCK(&lcl_rwlock
);
2691 return(mktime_return_value
);
2694 #if !BUILDING_VARIANT
2698 timelocal(struct tm
*const tmp
)
2701 tmp
->tm_isdst
= -1; /* in case it wasn't initialized */
2706 timegm(struct tm
*const tmp
)
2710 return time1(tmp
, gmtsub
, 0L, __DARWIN_UNIX03
);
2714 timeoff(struct tm
*const tmp
, const long offset
)
2718 return time1(tmp
, gmtsub
, offset
, __DARWIN_UNIX03
);
2721 #endif /* defined STD_INSPIRED */
2726 ** The following is supplied for compatibility with
2727 ** previous versions of the CMUCS runtime library.
2731 gtime(struct tm
*const tmp
)
2733 const time_t t
= mktime(tmp
);
2740 #endif /* defined CMUCS */
2743 ** XXX--is the below the right way to conditionalize??
2749 ** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
2750 ** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
2751 ** is not the case if we are accounting for leap seconds.
2752 ** So, we provide the following conversion routines for use
2753 ** when exchanging timestamps with POSIX conforming systems.
2757 leapcorr(time_t *timep
)
2767 if (*timep
>= lp
->ls_trans
)
2774 time2posix(time_t t
)
2777 return t
- leapcorr(&t
);
2781 posix2time(time_t t
)
2788 ** For a positive leap second hit, the result
2789 ** is not unique. For a negative leap second
2790 ** hit, the corresponding time doesn't exist,
2791 ** so we return an adjacent second.
2793 x
= t
+ leapcorr(&t
);
2794 y
= x
- leapcorr(&x
);
2798 y
= x
- leapcorr(&x
);
2805 y
= x
- leapcorr(&x
);
2813 #endif /* defined STD_INSPIRED */
2814 #endif /* !BUILDING_VARIANT */
2815 #pragma clang diagnostic pop