blob: 160f5ad460e4f62477ec0ed27fcace2a3dedfc3e [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* Copyright (C) 1991-2015 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
17
18#include <ctype.h>
19#include <errno.h>
20#include <bits/libc-lock.h>
21#include <stdbool.h>
22#include <stddef.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <time.h>
27
28
29#define NOID
30#include <timezone/tzfile.h>
31
32char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
33int __daylight = 0;
34long int __timezone = 0L;
35
36weak_alias (__tzname, tzname)
37weak_alias (__daylight, daylight)
38weak_alias (__timezone, timezone)
39
40/* This locks all the state variables in tzfile.c and this file. */
41__libc_lock_define_initialized (static, tzset_lock)
42
43
44#define min(a, b) ((a) < (b) ? (a) : (b))
45#define max(a, b) ((a) > (b) ? (a) : (b))
46#define sign(x) ((x) < 0 ? -1 : 1)
47
48
49/* This structure contains all the information about a
50 timezone given in the POSIX standard TZ envariable. */
51typedef struct
52 {
53 const char *name;
54
55 /* When to change. */
56 enum { J0, J1, M } type; /* Interpretation of: */
57 unsigned short int m, n, d; /* Month, week, day. */
58 int secs; /* Time of day. */
59
60 long int offset; /* Seconds east of GMT (west if < 0). */
61
62 /* We cache the computed time of change for a
63 given year so we don't have to recompute it. */
64 time_t change; /* When to change to this zone. */
65 int computed_for; /* Year above is computed for. */
66 } tz_rule;
67
68/* tz_rules[0] is standard, tz_rules[1] is daylight. */
69static tz_rule tz_rules[2];
70
71
72static void compute_change (tz_rule *rule, int year) __THROW internal_function;
73static void tzset_internal (int always, int explicit)
74 __THROW internal_function;
75
76/* List of buffers containing time zone strings. */
77struct tzstring_l
78{
79 struct tzstring_l *next;
80 size_t len; /* strlen(data) - doesn't count terminating NUL! */
81 char data[0];
82};
83
84static struct tzstring_l *tzstring_list;
85
86/* Allocate a permanent home for the first LEN characters of S. It
87 will never be moved or deallocated, but may share space with other
88 strings. Don't modify the returned string. */
89static char *
90__tzstring_len (const char *s, size_t len)
91{
92 char *p;
93 struct tzstring_l *t, *u, *new;
94
95 /* Walk the list and look for a match. If this string is the same
96 as the end of an already-allocated string, it can share space. */
97 for (u = t = tzstring_list; t; u = t, t = t->next)
98 if (len <= t->len)
99 {
100 p = &t->data[t->len - len];
101 if (memcmp (s, p, len) == 0)
102 return p;
103 }
104
105 /* Not found; allocate a new buffer. */
106 new = malloc (sizeof (struct tzstring_l) + len + 1);
107 if (!new)
108 return NULL;
109
110 new->next = NULL;
111 new->len = len;
112 memcpy (new->data, s, len);
113 new->data[len] = '\0';
114
115 if (u)
116 u->next = new;
117 else
118 tzstring_list = new;
119
120 return new->data;
121}
122
123/* Allocate a permanent home for S. It will never be moved or
124 deallocated, but may share space with other strings. Don't modify
125 the returned string. */
126char *
127__tzstring (const char *s)
128{
129 return __tzstring_len (s, strlen (s));
130}
131
132/* Maximum length of a timezone name. tzset_internal keeps this up to date
133 (never decreasing it) when ! __use_tzfile.
134 tzfile.c keeps it up to date when __use_tzfile. */
135size_t __tzname_cur_max;
136
137long int
138__tzname_max (void)
139{
140 __libc_lock_lock (tzset_lock);
141
142 tzset_internal (0, 0);
143
144 __libc_lock_unlock (tzset_lock);
145
146 return __tzname_cur_max;
147}
148
149static char *old_tz;
150
151static void
152internal_function
153update_vars (void)
154{
155 __daylight = tz_rules[0].offset != tz_rules[1].offset;
156 __timezone = -tz_rules[0].offset;
157 __tzname[0] = (char *) tz_rules[0].name;
158 __tzname[1] = (char *) tz_rules[1].name;
159
160 /* Keep __tzname_cur_max up to date. */
161 size_t len0 = strlen (__tzname[0]);
162 size_t len1 = strlen (__tzname[1]);
163 if (len0 > __tzname_cur_max)
164 __tzname_cur_max = len0;
165 if (len1 > __tzname_cur_max)
166 __tzname_cur_max = len1;
167}
168
169
170static unsigned int
171__attribute_noinline__
172compute_offset (unsigned int ss, unsigned int mm, unsigned int hh)
173{
174 return min (ss, 59) + min (mm, 59) * 60 + min (hh, 24) * 60 * 60;
175}
176
177/* Parses the time zone name at *TZP, and writes a pointer to an
178 interned string to tz_rules[WHICHRULE].name. On success, advances
179 *TZP, and returns true. Returns false otherwise. */
180static bool
181parse_tzname (const char **tzp, int whichrule)
182{
183 const char *start = *tzp;
184 const char *p = start;
185 while (('a' <= *p && *p <= 'z')
186 || ('A' <= *p && *p <= 'Z'))
187 ++p;
188 size_t len = p - start;
189 if (len < 3)
190 {
191 p = *tzp;
192 if (__glibc_unlikely (*p++ != '<'))
193 return false;
194 start = p;
195 while (('a' <= *p && *p <= 'z')
196 || ('A' <= *p && *p <= 'Z')
197 || ('0' <= *p && *p <= '9')
198 || *p == '+' || *p == '-')
199 ++p;
200 len = p - start;
201 if (*p++ != '>' || len < 3)
202 return false;
203 }
204
205 const char *name = __tzstring_len (start, len);
206 if (name == NULL)
207 return false;
208 tz_rules[whichrule].name = name;
209
210 *tzp = p;
211 return true;
212}
213
214/* Parses the time zone offset at *TZP, and writes it to
215 tz_rules[WHICHRULE].offset. Returns true if the parse was
216 successful. */
217static bool
218parse_offset (const char **tzp, int whichrule)
219{
220 const char *tz = *tzp;
221 if (whichrule == 0
222 && (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit (*tz))))
223 return false;
224
225 long sign;
226 if (*tz == '-' || *tz == '+')
227 sign = *tz++ == '-' ? 1L : -1L;
228 else
229 sign = -1L;
230 *tzp = tz;
231
232 unsigned short int hh;
233 unsigned short mm = 0;
234 unsigned short ss = 0;
235 int consumed = 0;
236 if (sscanf (tz, "%hu%n:%hu%n:%hu%n",
237 &hh, &consumed, &mm, &consumed, &ss, &consumed) > 0)
238 tz_rules[whichrule].offset = sign * compute_offset (ss, mm, hh);
239 else
240 /* Nothing could be parsed. */
241 if (whichrule == 0)
242 {
243 /* Standard time defaults to offset zero. */
244 tz_rules[0].offset = 0;
245 return false;
246 }
247 else
248 /* DST defaults to one hour later than standard time. */
249 tz_rules[1].offset = tz_rules[0].offset + (60 * 60);
250 *tzp = tz + consumed;
251 return true;
252}
253
254/* Parses the standard <-> DST rules at *TZP. Updates
255 tz_rule[WHICHRULE]. On success, advances *TZP and returns true.
256 Otherwise, returns false. */
257static bool
258parse_rule (const char **tzp, int whichrule)
259{
260 const char *tz = *tzp;
261 tz_rule *tzr = &tz_rules[whichrule];
262
263 /* Ignore comma to support string following the incorrect
264 specification in early POSIX.1 printings. */
265 tz += *tz == ',';
266
267 /* Get the date of the change. */
268 if (*tz == 'J' || isdigit (*tz))
269 {
270 char *end;
271 tzr->type = *tz == 'J' ? J1 : J0;
272 if (tzr->type == J1 && !isdigit (*++tz))
273 return false;
274 unsigned long int d = strtoul (tz, &end, 10);
275 if (end == tz || d > 365)
276 return false;
277 if (tzr->type == J1 && d == 0)
278 return false;
279 tzr->d = d;
280 tz = end;
281 }
282 else if (*tz == 'M')
283 {
284 tzr->type = M;
285 int consumed;
286 if (sscanf (tz, "M%hu.%hu.%hu%n",
287 &tzr->m, &tzr->n, &tzr->d, &consumed) != 3
288 || tzr->m < 1 || tzr->m > 12
289 || tzr->n < 1 || tzr->n > 5 || tzr->d > 6)
290 return false;
291 tz += consumed;
292 }
293 else if (*tz == '\0')
294 {
295 /* Daylight time rules in the U.S. are defined in the U.S. Code,
296 Title 15, Chapter 6, Subchapter IX - Standard Time. These
297 dates were established by Congress in the Energy Policy Act
298 of 2005 [Pub. L. no. 109-58, 119 Stat 594 (2005)].
299 Below is the equivalent of "M3.2.0,M11.1.0" [/2 not needed
300 since 2:00AM is the default]. */
301 tzr->type = M;
302 if (tzr == &tz_rules[0])
303 {
304 tzr->m = 3;
305 tzr->n = 2;
306 tzr->d = 0;
307 }
308 else
309 {
310 tzr->m = 11;
311 tzr->n = 1;
312 tzr->d = 0;
313 }
314 }
315 else
316 return false;
317
318 if (*tz != '\0' && *tz != '/' && *tz != ',')
319 return false;
320 else if (*tz == '/')
321 {
322 /* Get the time of day of the change. */
323 int negative;
324 ++tz;
325 if (*tz == '\0')
326 return false;
327 negative = *tz == '-';
328 tz += negative;
329 /* Default to 2:00 AM. */
330 unsigned short hh = 2;
331 unsigned short mm = 0;
332 unsigned short ss = 0;
333 int consumed = 0;
334 sscanf (tz, "%hu%n:%hu%n:%hu%n",
335 &hh, &consumed, &mm, &consumed, &ss, &consumed);;
336 tz += consumed;
337 tzr->secs = (negative ? -1 : 1) * ((hh * 60 * 60) + (mm * 60) + ss);
338 }
339 else
340 /* Default to 2:00 AM. */
341 tzr->secs = 2 * 60 * 60;
342
343 tzr->computed_for = -1;
344 *tzp = tz;
345 return true;
346}
347
348/* Parse the POSIX TZ-style string. */
349void
350__tzset_parse_tz (const char *tz)
351{
352 /* Clear out old state and reset to unnamed UTC. */
353 memset (tz_rules, '\0', sizeof tz_rules);
354 tz_rules[0].name = tz_rules[1].name = "";
355
356 /* Get the standard timezone name. */
357 if (parse_tzname (&tz, 0) && parse_offset (&tz, 0))
358 {
359 /* Get the DST timezone name (if any). */
360 if (*tz != '\0')
361 {
362 if (parse_tzname (&tz, 1))
363 {
364 parse_offset (&tz, 1);
365 if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0'))
366 {
367 /* There is no rule. See if there is a default rule
368 file. */
369 __tzfile_default (tz_rules[0].name, tz_rules[1].name,
370 tz_rules[0].offset, tz_rules[1].offset);
371 if (__use_tzfile)
372 {
373 free (old_tz);
374 old_tz = NULL;
375 return;
376 }
377 }
378 }
379 /* Figure out the standard <-> DST rules. */
380 if (parse_rule (&tz, 0))
381 parse_rule (&tz, 1);
382 }
383 else
384 {
385 /* There is no DST. */
386 tz_rules[1].name = tz_rules[0].name;
387 tz_rules[1].offset = tz_rules[0].offset;
388 }
389 }
390
391 update_vars ();
392}
393
394/* Interpret the TZ envariable. */
395static void
396internal_function
397tzset_internal (always, explicit)
398 int always;
399 int explicit;
400{
401 static int is_initialized;
402 const char *tz;
403
404 if (is_initialized && !always)
405 return;
406 is_initialized = 1;
407
408 /* Examine the TZ environment variable. */
409 tz = getenv ("TZ");
410 if (tz == NULL && !explicit)
411 /* Use the site-wide default. This is a file name which means we
412 would not see changes to the file if we compare only the file
413 name for change. We want to notice file changes if tzset() has
414 been called explicitly. Leave TZ as NULL in this case. */
415 tz = TZDEFAULT;
416 if (tz && *tz == '\0')
417 /* User specified the empty string; use UTC explicitly. */
418 tz = "Universal";
419
420 /* A leading colon means "implementation defined syntax".
421 We ignore the colon and always use the same algorithm:
422 try a data file, and if none exists parse the 1003.1 syntax. */
423 if (tz && *tz == ':')
424 ++tz;
425
426 /* Check whether the value changed since the last run. */
427 if (old_tz != NULL && tz != NULL && strcmp (tz, old_tz) == 0)
428 /* No change, simply return. */
429 return;
430
431 if (tz == NULL)
432 /* No user specification; use the site-wide default. */
433 tz = TZDEFAULT;
434
435 tz_rules[0].name = NULL;
436 tz_rules[1].name = NULL;
437
438 /* Save the value of `tz'. */
439 free (old_tz);
440 old_tz = tz ? __strdup (tz) : NULL;
441
442 /* Try to read a data file. */
443 __tzfile_read (tz, 0, NULL);
444 if (__use_tzfile)
445 return;
446
447 /* No data file found. Default to UTC if nothing specified. */
448
449 if (tz == NULL || *tz == '\0'
450 || (TZDEFAULT != NULL && strcmp (tz, TZDEFAULT) == 0))
451 {
452 memset (tz_rules, '\0', sizeof tz_rules);
453 tz_rules[0].name = tz_rules[1].name = "UTC";
454 if (J0 != 0)
455 tz_rules[0].type = tz_rules[1].type = J0;
456 tz_rules[0].change = tz_rules[1].change = (time_t) -1;
457 update_vars ();
458 return;
459 }
460
461 __tzset_parse_tz (tz);
462}
463
464/* Figure out the exact time (as a time_t) in YEAR
465 when the change described by RULE will occur and
466 put it in RULE->change, saving YEAR in RULE->computed_for. */
467static void
468internal_function
469compute_change (rule, year)
470 tz_rule *rule;
471 int year;
472{
473 time_t t;
474
475 if (year != -1 && rule->computed_for == year)
476 /* Operations on times in 2 BC will be slower. Oh well. */
477 return;
478
479 /* First set T to January 1st, 0:00:00 GMT in YEAR. */
480 if (year > 1970)
481 t = ((year - 1970) * 365
482 + /* Compute the number of leapdays between 1970 and YEAR
483 (exclusive). There is a leapday every 4th year ... */
484 + ((year - 1) / 4 - 1970 / 4)
485 /* ... except every 100th year ... */
486 - ((year - 1) / 100 - 1970 / 100)
487 /* ... but still every 400th year. */
488 + ((year - 1) / 400 - 1970 / 400)) * SECSPERDAY;
489 else
490 t = 0;
491
492 switch (rule->type)
493 {
494 case J1:
495 /* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap years.
496 In non-leap years, or if the day number is 59 or less, just
497 add SECSPERDAY times the day number-1 to the time of
498 January 1, midnight, to get the day. */
499 t += (rule->d - 1) * SECSPERDAY;
500 if (rule->d >= 60 && __isleap (year))
501 t += SECSPERDAY;
502 break;
503
504 case J0:
505 /* n - Day of year.
506 Just add SECSPERDAY times the day number to the time of Jan 1st. */
507 t += rule->d * SECSPERDAY;
508 break;
509
510 case M:
511 /* Mm.n.d - Nth "Dth day" of month M. */
512 {
513 unsigned int i;
514 int d, m1, yy0, yy1, yy2, dow;
515 const unsigned short int *myday =
516 &__mon_yday[__isleap (year)][rule->m];
517
518 /* First add SECSPERDAY for each day in months before M. */
519 t += myday[-1] * SECSPERDAY;
520
521 /* Use Zeller's Congruence to get day-of-week of first day of month. */
522 m1 = (rule->m + 9) % 12 + 1;
523 yy0 = (rule->m <= 2) ? (year - 1) : year;
524 yy1 = yy0 / 100;
525 yy2 = yy0 % 100;
526 dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
527 if (dow < 0)
528 dow += 7;
529
530 /* DOW is the day-of-week of the first day of the month. Get the
531 day-of-month (zero-origin) of the first DOW day of the month. */
532 d = rule->d - dow;
533 if (d < 0)
534 d += 7;
535 for (i = 1; i < rule->n; ++i)
536 {
537 if (d + 7 >= (int) myday[0] - myday[-1])
538 break;
539 d += 7;
540 }
541
542 /* D is the day-of-month (zero-origin) of the day we want. */
543 t += d * SECSPERDAY;
544 }
545 break;
546 }
547
548 /* T is now the Epoch-relative time of 0:00:00 GMT on the day we want.
549 Just add the time of day and local offset from GMT, and we're done. */
550
551 rule->change = t - rule->offset + rule->secs;
552 rule->computed_for = year;
553}
554
555
556/* Figure out the correct timezone for TM and set `__tzname',
557 `__timezone', and `__daylight' accordingly. */
558void
559internal_function
560__tz_compute (timer, tm, use_localtime)
561 time_t timer;
562 struct tm *tm;
563 int use_localtime;
564{
565 compute_change (&tz_rules[0], 1900 + tm->tm_year);
566 compute_change (&tz_rules[1], 1900 + tm->tm_year);
567
568 if (use_localtime)
569 {
570 int isdst;
571
572 /* We have to distinguish between northern and southern
573 hemisphere. For the latter the daylight saving time
574 ends in the next year. */
575 if (__builtin_expect (tz_rules[0].change
576 > tz_rules[1].change, 0))
577 isdst = (timer < tz_rules[1].change
578 || timer >= tz_rules[0].change);
579 else
580 isdst = (timer >= tz_rules[0].change
581 && timer < tz_rules[1].change);
582 tm->tm_isdst = isdst;
583 tm->tm_zone = __tzname[isdst];
584 tm->tm_gmtoff = tz_rules[isdst].offset;
585 }
586}
587
588/* Reinterpret the TZ environment variable and set `tzname'. */
589#undef tzset
590
591void
592__tzset (void)
593{
594 __libc_lock_lock (tzset_lock);
595
596 tzset_internal (1, 1);
597
598 if (!__use_tzfile)
599 {
600 /* Set `tzname'. */
601 __tzname[0] = (char *) tz_rules[0].name;
602 __tzname[1] = (char *) tz_rules[1].name;
603 }
604
605 __libc_lock_unlock (tzset_lock);
606}
607weak_alias (__tzset, tzset)
608
609/* Return the `struct tm' representation of *TIMER in the local timezone.
610 Use local time if USE_LOCALTIME is nonzero, UTC otherwise. */
611struct tm *
612__tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
613{
614 long int leap_correction;
615 int leap_extra_secs;
616
617 if (timer == NULL)
618 {
619 __set_errno (EINVAL);
620 return NULL;
621 }
622
623 __libc_lock_lock (tzset_lock);
624
625 /* Update internal database according to current TZ setting.
626 POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
627 This is a good idea since this allows at least a bit more parallelism. */
628 tzset_internal (tp == &_tmbuf && use_localtime, 1);
629
630 if (__use_tzfile)
631 __tzfile_compute (*timer, use_localtime, &leap_correction,
632 &leap_extra_secs, tp);
633 else
634 {
635 if (! __offtime (timer, 0, tp))
636 tp = NULL;
637 else
638 __tz_compute (*timer, tp, use_localtime);
639 leap_correction = 0L;
640 leap_extra_secs = 0;
641 }
642
643 __libc_lock_unlock (tzset_lock);
644
645 if (tp)
646 {
647 if (! use_localtime)
648 {
649 tp->tm_isdst = 0;
650 tp->tm_zone = "GMT";
651 tp->tm_gmtoff = 0L;
652 }
653
654 if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp))
655 tp->tm_sec += leap_extra_secs;
656 else
657 tp = NULL;
658 }
659
660 return tp;
661}
662
663
664libc_freeres_fn (free_mem)
665{
666 while (tzstring_list != NULL)
667 {
668 struct tzstring_l *old = tzstring_list;
669
670 tzstring_list = tzstring_list->next;
671 free (old);
672 }
673 free (old_tz);
674 old_tz = NULL;
675}