tzset.c 16 KB

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