[BZ #9895]
[glibc.git] / time / tzset.c
blob5cde0bfbd5d777541c40fcf36591fd93418ec97a
1 /* Copyright (C) 1991-2002,2003,2004,2007,2009 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
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.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307 USA. */
19 #include <ctype.h>
20 #include <errno.h>
21 #include <bits/libc-lock.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
29 #define NOID
30 #include <timezone/tzfile.h>
32 char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
33 int __daylight = 0;
34 long int __timezone = 0L;
36 weak_alias (__tzname, tzname)
37 weak_alias (__daylight, daylight)
38 weak_alias (__timezone, timezone)
40 /* This locks all the state variables in tzfile.c and this file. */
41 __libc_lock_define_initialized (static, tzset_lock)
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)
49 /* This structure contains all the information about a
50 timezone given in the POSIX standard TZ envariable. */
51 typedef struct
53 const char *name;
55 /* When to change. */
56 enum { J0, J1, M } type; /* Interpretation of: */
57 unsigned short int m, n, d; /* Month, week, day. */
58 unsigned int secs; /* Time of day. */
60 long int offset; /* Seconds east of GMT (west if < 0). */
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;
68 /* tz_rules[0] is standard, tz_rules[1] is daylight. */
69 static tz_rule tz_rules[2];
72 static void compute_change (tz_rule *rule, int year) __THROW internal_function;
73 static void tzset_internal (int always, int explicit)
74 __THROW internal_function;
76 /* List of buffers containing time zone strings. */
77 struct tzstring_l
79 struct tzstring_l *next;
80 size_t len; /* strlen(data) - doesn't count terminating NUL! */
81 char data[0];
84 static struct tzstring_l *tzstring_list;
86 /* Allocate a permanent home for S. It will never be moved or deallocated,
87 but may share space with other strings.
88 Don't modify the returned string. */
89 char *
90 __tzstring (const char *s)
92 char *p;
93 struct tzstring_l *t, *u, *new;
94 size_t len = strlen (s);
96 /* Walk the list and look for a match. If this string is the same
97 as the end of an already-allocated string, it can share space. */
98 for (u = t = tzstring_list; t; u = t, t = t->next)
99 if (len <= t->len)
101 p = &t->data[t->len - len];
102 if (strcmp (s, p) == 0)
103 return p;
106 /* Not found; allocate a new buffer. */
107 new = malloc (sizeof (struct tzstring_l) + len + 1);
108 if (!new)
109 return NULL;
111 new->next = NULL;
112 new->len = len;
113 strcpy (new->data, s);
115 if (u)
116 u->next = new;
117 else
118 tzstring_list = new;
120 return new->data;
123 /* Maximum length of a timezone name. tzset_internal keeps this up to date
124 (never decreasing it) when ! __use_tzfile.
125 tzfile.c keeps it up to date when __use_tzfile. */
126 size_t __tzname_cur_max;
128 long int
129 __tzname_max ()
131 __libc_lock_lock (tzset_lock);
133 tzset_internal (0, 0);
135 __libc_lock_unlock (tzset_lock);
137 return __tzname_cur_max;
140 static char *old_tz;
142 static void
143 internal_function
144 update_vars (void)
146 __daylight = tz_rules[0].offset != tz_rules[1].offset;
147 __timezone = -tz_rules[0].offset;
148 __tzname[0] = (char *) tz_rules[0].name;
149 __tzname[1] = (char *) tz_rules[1].name;
151 /* Keep __tzname_cur_max up to date. */
152 size_t len0 = strlen (__tzname[0]);
153 size_t len1 = strlen (__tzname[1]);
154 if (len0 > __tzname_cur_max)
155 __tzname_cur_max = len0;
156 if (len1 > __tzname_cur_max)
157 __tzname_cur_max = len1;
160 /* Parse the POSIX TZ-style string. */
161 void
162 __tzset_parse_tz (tz)
163 const char *tz;
165 register size_t l;
166 char *tzbuf;
167 unsigned short int hh, mm, ss;
168 unsigned short int whichrule;
170 /* Clear out old state and reset to unnamed UTC. */
171 memset (tz_rules, 0, sizeof tz_rules);
172 tz_rules[0].name = tz_rules[1].name = "";
174 /* Get the standard timezone name. */
175 tzbuf = strdupa (tz);
177 if (sscanf (tz, "%[A-Za-z]", tzbuf) != 1)
179 /* Check for the quoted version. */
180 char *wp = tzbuf;
181 if (*tz++ != '<')
182 goto out;
184 while (isalnum (*tz) || *tz == '+' || *tz == '-')
185 *wp++ = *tz++;
186 if (*tz++ != '>' || wp - tzbuf < 3)
187 goto out;
188 *wp = '\0';
190 else if ((l = strlen (tzbuf)) < 3)
191 goto out;
192 else
193 tz += l;
195 tz_rules[0].name = __tzstring (tzbuf);
197 /* Figure out the standard offset from UTC. */
198 if (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit (*tz)))
199 goto out;
201 if (*tz == '-' || *tz == '+')
202 tz_rules[0].offset = *tz++ == '-' ? 1L : -1L;
203 else
204 tz_rules[0].offset = -1L;
205 switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
207 default:
208 tz_rules[0].offset = 0;
209 goto out;
210 case 1:
211 mm = 0;
212 case 2:
213 ss = 0;
214 case 3:
215 break;
217 tz_rules[0].offset *= (min (ss, 59) + (min (mm, 59) * 60) +
218 (min (hh, 24) * 60 * 60));
220 for (l = 0; l < 3; ++l)
222 while (isdigit(*tz))
223 ++tz;
224 if (l < 2 && *tz == ':')
225 ++tz;
228 /* Get the DST timezone name (if any). */
229 if (*tz != '\0')
231 char *n = tzbuf + strlen (tzbuf) + 1;
233 if (sscanf (tz, "%[A-Za-z]", tzbuf) != 1)
235 /* Check for the quoted version. */
236 char *wp = tzbuf;
237 const char *rp = tz;
238 if (*rp++ != '<')
239 /* Punt on name, set up the offsets. */
240 goto done_names;
242 while (isalnum (*rp) || *rp == '+' || *rp == '-')
243 *wp++ = *rp++;
244 if (*rp++ != '>' || wp - tzbuf < 3)
245 /* Punt on name, set up the offsets. */
246 goto done_names;
247 *wp = '\0';
248 tz = rp;
250 else if ((l = strlen (tzbuf)) < 3)
251 /* Punt on name, set up the offsets. */
252 goto done_names;
253 else
254 tz += l;
256 tz_rules[1].name = __tzstring (n);
258 /* Figure out the DST offset from GMT. */
259 if (*tz == '-' || *tz == '+')
260 tz_rules[1].offset = *tz++ == '-' ? 1L : -1L;
261 else
262 tz_rules[1].offset = -1L;
264 switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
266 default:
267 /* Default to one hour later than standard time. */
268 tz_rules[1].offset = tz_rules[0].offset + (60 * 60);
269 break;
271 case 1:
272 mm = 0;
273 case 2:
274 ss = 0;
275 case 3:
276 tz_rules[1].offset *= (min (ss, 59) + (min (mm, 59) * 60) +
277 (min (hh, 24) * (60 * 60)));
278 break;
280 for (l = 0; l < 3; ++l)
282 while (isdigit (*tz))
283 ++tz;
284 if (l < 2 && *tz == ':')
285 ++tz;
287 if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0'))
289 /* There is no rule. See if there is a default rule file. */
290 __tzfile_default (tz_rules[0].name, tz_rules[1].name,
291 tz_rules[0].offset, tz_rules[1].offset);
292 if (__use_tzfile)
294 free (old_tz);
295 old_tz = NULL;
296 return;
300 else
302 /* There is no DST. */
303 tz_rules[1].name = tz_rules[0].name;
304 tz_rules[1].offset = tz_rules[0].offset;
305 goto out;
308 done_names:
309 /* Figure out the standard <-> DST rules. */
310 for (whichrule = 0; whichrule < 2; ++whichrule)
312 register tz_rule *tzr = &tz_rules[whichrule];
314 /* Ignore comma to support string following the incorrect
315 specification in early POSIX.1 printings. */
316 tz += *tz == ',';
318 /* Get the date of the change. */
319 if (*tz == 'J' || isdigit (*tz))
321 char *end;
322 tzr->type = *tz == 'J' ? J1 : J0;
323 if (tzr->type == J1 && !isdigit (*++tz))
324 goto out;
325 tzr->d = (unsigned short int) strtoul (tz, &end, 10);
326 if (end == tz || tzr->d > 365)
327 goto out;
328 else if (tzr->type == J1 && tzr->d == 0)
329 goto out;
330 tz = end;
332 else if (*tz == 'M')
334 int n;
335 tzr->type = M;
336 if (sscanf (tz, "M%hu.%hu.%hu%n",
337 &tzr->m, &tzr->n, &tzr->d, &n) != 3 ||
338 tzr->m < 1 || tzr->m > 12 ||
339 tzr->n < 1 || tzr->n > 5 || tzr->d > 6)
340 goto out;
341 tz += n;
343 else if (*tz == '\0')
345 /* United States Federal Law, the equivalent of "M4.1.0,M10.5.0". */
346 tzr->type = M;
347 if (tzr == &tz_rules[0])
349 tzr->m = 4;
350 tzr->n = 1;
351 tzr->d = 0;
353 else
355 tzr->m = 10;
356 tzr->n = 5;
357 tzr->d = 0;
360 else
361 goto out;
363 if (*tz != '\0' && *tz != '/' && *tz != ',')
364 goto out;
365 else if (*tz == '/')
367 /* Get the time of day of the change. */
368 ++tz;
369 if (*tz == '\0')
370 goto out;
371 switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
373 default:
374 hh = 2; /* Default to 2:00 AM. */
375 case 1:
376 mm = 0;
377 case 2:
378 ss = 0;
379 case 3:
380 break;
382 for (l = 0; l < 3; ++l)
384 while (isdigit (*tz))
385 ++tz;
386 if (l < 2 && *tz == ':')
387 ++tz;
389 tzr->secs = (hh * 60 * 60) + (mm * 60) + ss;
391 else
392 /* Default to 2:00 AM. */
393 tzr->secs = 2 * 60 * 60;
395 tzr->computed_for = -1;
398 out:
399 update_vars ();
402 /* Interpret the TZ envariable. */
403 static void
404 internal_function
405 tzset_internal (always, explicit)
406 int always;
407 int explicit;
409 static int is_initialized;
410 register const char *tz;
412 if (is_initialized && !always)
413 return;
414 is_initialized = 1;
416 /* Examine the TZ environment variable. */
417 tz = getenv ("TZ");
418 if (tz == NULL && !explicit)
419 /* Use the site-wide default. This is a file name which means we
420 would not see changes to the file if we compare only the file
421 name for change. We want to notice file changes if tzset() has
422 been called explicitly. Leave TZ as NULL in this case. */
423 tz = TZDEFAULT;
424 if (tz && *tz == '\0')
425 /* User specified the empty string; use UTC explicitly. */
426 tz = "Universal";
428 /* A leading colon means "implementation defined syntax".
429 We ignore the colon and always use the same algorithm:
430 try a data file, and if none exists parse the 1003.1 syntax. */
431 if (tz && *tz == ':')
432 ++tz;
434 /* Check whether the value changed since the last run. */
435 if (old_tz != NULL && tz != NULL && strcmp (tz, old_tz) == 0)
436 /* No change, simply return. */
437 return;
439 if (tz == NULL)
440 /* No user specification; use the site-wide default. */
441 tz = TZDEFAULT;
443 tz_rules[0].name = NULL;
444 tz_rules[1].name = NULL;
446 /* Save the value of `tz'. */
447 free (old_tz);
448 old_tz = tz ? __strdup (tz) : NULL;
450 /* Try to read a data file. */
451 __tzfile_read (tz, 0, NULL);
452 if (__use_tzfile)
453 return;
455 /* No data file found. Default to UTC if nothing specified. */
457 if (tz == NULL || *tz == '\0'
458 || (TZDEFAULT != NULL && strcmp (tz, TZDEFAULT) == 0))
460 tz_rules[0].name = tz_rules[1].name = "UTC";
461 tz_rules[0].type = tz_rules[1].type = J0;
462 tz_rules[0].m = tz_rules[0].n = tz_rules[0].d = 0;
463 tz_rules[1].m = tz_rules[1].n = tz_rules[1].d = 0;
464 tz_rules[0].secs = tz_rules[1].secs = 0;
465 tz_rules[0].offset = tz_rules[1].offset = 0L;
466 tz_rules[0].change = tz_rules[1].change = (time_t) -1;
467 tz_rules[0].computed_for = tz_rules[1].computed_for = 0;
468 update_vars ();
469 return;
472 __tzset_parse_tz (tz);
475 /* Figure out the exact time (as a time_t) in YEAR
476 when the change described by RULE will occur and
477 put it in RULE->change, saving YEAR in RULE->computed_for. */
478 static void
479 internal_function
480 compute_change (rule, year)
481 tz_rule *rule;
482 int year;
484 register time_t t;
486 if (year != -1 && rule->computed_for == year)
487 /* Operations on times in 2 BC will be slower. Oh well. */
488 return;
490 /* First set T to January 1st, 0:00:00 GMT in YEAR. */
491 if (year > 1970)
492 t = ((year - 1970) * 365
493 + /* Compute the number of leapdays between 1970 and YEAR
494 (exclusive). There is a leapday every 4th year ... */
495 + ((year - 1) / 4 - 1970 / 4)
496 /* ... except every 100th year ... */
497 - ((year - 1) / 100 - 1970 / 100)
498 /* ... but still every 400th year. */
499 + ((year - 1) / 400 - 1970 / 400)) * SECSPERDAY;
500 else
501 t = 0;
503 switch (rule->type)
505 case J1:
506 /* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap years.
507 In non-leap years, or if the day number is 59 or less, just
508 add SECSPERDAY times the day number-1 to the time of
509 January 1, midnight, to get the day. */
510 t += (rule->d - 1) * SECSPERDAY;
511 if (rule->d >= 60 && __isleap (year))
512 t += SECSPERDAY;
513 break;
515 case J0:
516 /* n - Day of year.
517 Just add SECSPERDAY times the day number to the time of Jan 1st. */
518 t += rule->d * SECSPERDAY;
519 break;
521 case M:
522 /* Mm.n.d - Nth "Dth day" of month M. */
524 unsigned int i;
525 int d, m1, yy0, yy1, yy2, dow;
526 const unsigned short int *myday =
527 &__mon_yday[__isleap (year)][rule->m];
529 /* First add SECSPERDAY for each day in months before M. */
530 t += myday[-1] * SECSPERDAY;
532 /* Use Zeller's Congruence to get day-of-week of first day of month. */
533 m1 = (rule->m + 9) % 12 + 1;
534 yy0 = (rule->m <= 2) ? (year - 1) : year;
535 yy1 = yy0 / 100;
536 yy2 = yy0 % 100;
537 dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
538 if (dow < 0)
539 dow += 7;
541 /* DOW is the day-of-week of the first day of the month. Get the
542 day-of-month (zero-origin) of the first DOW day of the month. */
543 d = rule->d - dow;
544 if (d < 0)
545 d += 7;
546 for (i = 1; i < rule->n; ++i)
548 if (d + 7 >= (int) myday[0] - myday[-1])
549 break;
550 d += 7;
553 /* D is the day-of-month (zero-origin) of the day we want. */
554 t += d * SECSPERDAY;
556 break;
559 /* T is now the Epoch-relative time of 0:00:00 GMT on the day we want.
560 Just add the time of day and local offset from GMT, and we're done. */
562 rule->change = t - rule->offset + rule->secs;
563 rule->computed_for = year;
567 /* Figure out the correct timezone for TM and set `__tzname',
568 `__timezone', and `__daylight' accordingly. */
569 void
570 internal_function
571 __tz_compute (timer, tm, use_localtime)
572 time_t timer;
573 struct tm *tm;
574 int use_localtime;
576 compute_change (&tz_rules[0], 1900 + tm->tm_year);
577 compute_change (&tz_rules[1], 1900 + tm->tm_year);
579 if (use_localtime)
581 int isdst;
583 /* We have to distinguish between northern and southern
584 hemisphere. For the latter the daylight saving time
585 ends in the next year. */
586 if (__builtin_expect (tz_rules[0].change
587 > tz_rules[1].change, 0))
588 isdst = (timer < tz_rules[1].change
589 || timer >= tz_rules[0].change);
590 else
591 isdst = (timer >= tz_rules[0].change
592 && timer < tz_rules[1].change);
593 tm->tm_isdst = isdst;
594 tm->tm_zone = __tzname[isdst];
595 tm->tm_gmtoff = tz_rules[isdst].offset;
599 /* Reinterpret the TZ environment variable and set `tzname'. */
600 #undef tzset
602 void
603 __tzset (void)
605 __libc_lock_lock (tzset_lock);
607 tzset_internal (1, 1);
609 if (!__use_tzfile)
611 /* Set `tzname'. */
612 __tzname[0] = (char *) tz_rules[0].name;
613 __tzname[1] = (char *) tz_rules[1].name;
616 __libc_lock_unlock (tzset_lock);
618 weak_alias (__tzset, tzset)
620 /* Return the `struct tm' representation of *TIMER in the local timezone.
621 Use local time if USE_LOCALTIME is nonzero, UTC otherwise. */
622 struct tm *
623 __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
625 long int leap_correction;
626 int leap_extra_secs;
628 if (timer == NULL)
630 __set_errno (EINVAL);
631 return NULL;
634 __libc_lock_lock (tzset_lock);
636 /* Update internal database according to current TZ setting.
637 POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
638 This is a good idea since this allows at least a bit more parallelism. */
639 tzset_internal (tp == &_tmbuf && use_localtime, 1);
641 if (__use_tzfile)
642 __tzfile_compute (*timer, use_localtime, &leap_correction,
643 &leap_extra_secs, tp);
644 else
646 if (! __offtime (timer, 0, tp))
647 tp = NULL;
648 else
649 __tz_compute (*timer, tp, use_localtime);
650 leap_correction = 0L;
651 leap_extra_secs = 0;
654 if (tp)
656 if (! use_localtime)
658 tp->tm_isdst = 0;
659 tp->tm_zone = "GMT";
660 tp->tm_gmtoff = 0L;
663 if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp))
664 tp->tm_sec += leap_extra_secs;
665 else
666 tp = NULL;
669 __libc_lock_unlock (tzset_lock);
671 return tp;
675 libc_freeres_fn (free_mem)
677 while (tzstring_list != NULL)
679 struct tzstring_l *old = tzstring_list;
681 tzstring_list = tzstring_list->next;
682 free (old);
684 free (old_tz);
685 old_tz = NULL;