Update.
[glibc.git] / time / tzset.c
blob79cc610b38d8ac9aad4cb2d362b18bf16333c51d
1 /* Copyright (C) 1991-2002,2003,2004 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 __P ((tz_rule *rule, int year)) internal_function;
73 static void tz_compute __P ((const struct tm *tm))
74 internal_function;
75 static void tzset_internal __P ((int always, int explicit)) internal_function;
77 /* List of buffers containing time zone strings. */
78 struct tzstring_l
80 struct tzstring_l *next;
81 size_t len; /* strlen(data) - doesn't count terminating NUL! */
82 char data[0];
85 static struct tzstring_l *tzstring_list;
87 /* Allocate a permanent home for S. It will never be moved or deallocated,
88 but may share space with other strings.
89 Don't modify the returned string. */
90 char *
91 __tzstring (const char *s)
93 char *p;
94 struct tzstring_l *t, *u, *new;
95 size_t len = strlen(s);
97 /* Walk the list and look for a match. If this string is the same
98 as the end of an already-allocated string, it can share space. */
99 for (u = t = tzstring_list; t; u = t, t = t->next)
100 if (len <= t->len)
102 p = &t->data[t->len - len];
103 if (strcmp (s, p) == 0)
104 return p;
107 /* Not found; allocate a new buffer. */
108 new = malloc (sizeof (struct tzstring_l) + len + 1);
109 if (!new)
110 return NULL;
112 new->next = NULL;
113 new->len = len;
114 strcpy (new->data, s);
116 if (u)
117 u->next = new;
118 else
119 tzstring_list = new;
121 return new->data;
124 /* Maximum length of a timezone name. tzset_internal keeps this up to date
125 (never decreasing it) when ! __use_tzfile.
126 tzfile.c keeps it up to date when __use_tzfile. */
127 size_t __tzname_cur_max;
129 long int
130 __tzname_max ()
132 __libc_lock_lock (tzset_lock);
134 tzset_internal (0, 0);
136 __libc_lock_unlock (tzset_lock);
138 return __tzname_cur_max;
141 static char *old_tz;
143 /* Interpret the TZ envariable. */
144 static void
145 internal_function
146 tzset_internal (always, explicit)
147 int always;
148 int explicit;
150 static int is_initialized;
151 register const char *tz;
152 register size_t l;
153 char *tzbuf;
154 unsigned short int hh, mm, ss;
155 unsigned short int whichrule;
157 if (is_initialized && !always)
158 return;
159 is_initialized = 1;
161 /* Examine the TZ environment variable. */
162 tz = getenv ("TZ");
163 if (tz == NULL && !explicit)
164 /* Use the site-wide default. This is a file name which means we
165 would not see changes to the file if we compare only the file
166 name for change. We want to notice file changes if tzset() has
167 been called explicitly. Leave TZ as NULL in this case. */
168 tz = TZDEFAULT;
169 if (tz && *tz == '\0')
170 /* User specified the empty string; use UTC explicitly. */
171 tz = "Universal";
173 /* A leading colon means "implementation defined syntax".
174 We ignore the colon and always use the same algorithm:
175 try a data file, and if none exists parse the 1003.1 syntax. */
176 if (tz && *tz == ':')
177 ++tz;
179 /* Check whether the value changes since the last run. */
180 if (old_tz != NULL && tz != NULL && strcmp (tz, old_tz) == 0)
181 /* No change, simply return. */
182 return;
184 if (tz == NULL)
185 /* No user specification; use the site-wide default. */
186 tz = TZDEFAULT;
188 tz_rules[0].name = NULL;
189 tz_rules[1].name = NULL;
191 /* Save the value of `tz'. */
192 if (old_tz != NULL)
193 free (old_tz);
194 old_tz = tz ? __strdup (tz) : NULL;
196 /* Try to read a data file. */
197 __tzfile_read (tz, 0, NULL);
198 if (__use_tzfile)
199 return;
201 /* No data file found. Default to UTC if nothing specified. */
203 if (tz == NULL || *tz == '\0'
204 || (TZDEFAULT != NULL && strcmp (tz, TZDEFAULT) == 0))
206 tz_rules[0].name = tz_rules[1].name = "UTC";
207 tz_rules[0].type = tz_rules[1].type = J0;
208 tz_rules[0].m = tz_rules[0].n = tz_rules[0].d = 0;
209 tz_rules[1].m = tz_rules[1].n = tz_rules[1].d = 0;
210 tz_rules[0].secs = tz_rules[1].secs = 0;
211 tz_rules[0].offset = tz_rules[1].offset = 0L;
212 tz_rules[0].change = tz_rules[1].change = (time_t) -1;
213 tz_rules[0].computed_for = tz_rules[1].computed_for = 0;
214 goto out;
217 /* Clear out old state and reset to unnamed UTC. */
218 memset (tz_rules, 0, sizeof tz_rules);
219 tz_rules[0].name = tz_rules[1].name = "";
221 /* Get the standard timezone name. */
222 tzbuf = strdupa (tz);
224 if (sscanf (tz, "%[^0-9,+-]", tzbuf) != 1 ||
225 (l = strlen (tzbuf)) < 3)
226 goto out;
228 tz_rules[0].name = __tzstring (tzbuf);
230 tz += l;
232 /* Figure out the standard offset from UTC. */
233 if (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit (*tz)))
234 goto out;
236 if (*tz == '-' || *tz == '+')
237 tz_rules[0].offset = *tz++ == '-' ? 1L : -1L;
238 else
239 tz_rules[0].offset = -1L;
240 switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
242 default:
243 goto out;
244 case 1:
245 mm = 0;
246 case 2:
247 ss = 0;
248 case 3:
249 break;
251 tz_rules[0].offset *= (min (ss, 59) + (min (mm, 59) * 60) +
252 (min (hh, 24) * 60 * 60));
254 for (l = 0; l < 3; ++l)
256 while (isdigit(*tz))
257 ++tz;
258 if (l < 2 && *tz == ':')
259 ++tz;
262 /* Get the DST timezone name (if any). */
263 if (*tz != '\0')
265 char *n = tzbuf + strlen (tzbuf) + 1;
266 if (sscanf (tz, "%[^0-9,+-]", n) != 1 ||
267 (l = strlen (n)) < 3)
268 goto done_names; /* Punt on name, set up the offsets. */
270 tz_rules[1].name = __tzstring (n);
272 tz += l;
274 /* Figure out the DST offset from GMT. */
275 if (*tz == '-' || *tz == '+')
276 tz_rules[1].offset = *tz++ == '-' ? 1L : -1L;
277 else
278 tz_rules[1].offset = -1L;
280 switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
282 default:
283 /* Default to one hour later than standard time. */
284 tz_rules[1].offset = tz_rules[0].offset + (60 * 60);
285 break;
287 case 1:
288 mm = 0;
289 case 2:
290 ss = 0;
291 case 3:
292 tz_rules[1].offset *= (min (ss, 59) + (min (mm, 59) * 60) +
293 (min (hh, 23) * (60 * 60)));
294 break;
296 for (l = 0; l < 3; ++l)
298 while (isdigit (*tz))
299 ++tz;
300 if (l < 2 && *tz == ':')
301 ++tz;
303 if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0'))
305 /* There is no rule. See if there is a default rule file. */
306 __tzfile_default (tz_rules[0].name, tz_rules[1].name,
307 tz_rules[0].offset, tz_rules[1].offset);
308 if (__use_tzfile)
310 free (old_tz);
311 old_tz = NULL;
312 return;
316 else
318 /* There is no DST. */
319 tz_rules[1].name = tz_rules[0].name;
320 tz_rules[1].offset = tz_rules[0].offset;
321 goto out;
324 done_names:
325 /* Figure out the standard <-> DST rules. */
326 for (whichrule = 0; whichrule < 2; ++whichrule)
328 register tz_rule *tzr = &tz_rules[whichrule];
330 /* Ignore comma to support string following the incorrect
331 specification in early POSIX.1 printings. */
332 tz += *tz == ',';
334 /* Get the date of the change. */
335 if (*tz == 'J' || isdigit (*tz))
337 char *end;
338 tzr->type = *tz == 'J' ? J1 : J0;
339 if (tzr->type == J1 && !isdigit (*++tz))
340 goto out;
341 tzr->d = (unsigned short int) strtoul (tz, &end, 10);
342 if (end == tz || tzr->d > 365)
343 goto out;
344 else if (tzr->type == J1 && tzr->d == 0)
345 goto out;
346 tz = end;
348 else if (*tz == 'M')
350 int n;
351 tzr->type = M;
352 if (sscanf (tz, "M%hu.%hu.%hu%n",
353 &tzr->m, &tzr->n, &tzr->d, &n) != 3 ||
354 tzr->m < 1 || tzr->m > 12 ||
355 tzr->n < 1 || tzr->n > 5 || tzr->d > 6)
356 goto out;
357 tz += n;
359 else if (*tz == '\0')
361 /* United States Federal Law, the equivalent of "M4.1.0,M10.5.0". */
362 tzr->type = M;
363 if (tzr == &tz_rules[0])
365 tzr->m = 4;
366 tzr->n = 1;
367 tzr->d = 0;
369 else
371 tzr->m = 10;
372 tzr->n = 5;
373 tzr->d = 0;
376 else
377 goto out;
379 if (*tz != '\0' && *tz != '/' && *tz != ',')
380 goto out;
381 else if (*tz == '/')
383 /* Get the time of day of the change. */
384 ++tz;
385 if (*tz == '\0')
386 goto out;
387 switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
389 default:
390 hh = 2; /* Default to 2:00 AM. */
391 case 1:
392 mm = 0;
393 case 2:
394 ss = 0;
395 case 3:
396 break;
398 for (l = 0; l < 3; ++l)
400 while (isdigit (*tz))
401 ++tz;
402 if (l < 2 && *tz == ':')
403 ++tz;
405 tzr->secs = (hh * 60 * 60) + (mm * 60) + ss;
407 else
408 /* Default to 2:00 AM. */
409 tzr->secs = 2 * 60 * 60;
411 tzr->computed_for = -1;
414 out:
415 __daylight = tz_rules[0].offset != tz_rules[1].offset;
416 __timezone = -tz_rules[0].offset;
417 __tzname[0] = (char *) tz_rules[0].name;
418 __tzname[1] = (char *) tz_rules[1].name;
421 /* Keep __tzname_cur_max up to date. */
422 size_t len0 = strlen (__tzname[0]);
423 size_t len1 = strlen (__tzname[1]);
424 if (len0 > __tzname_cur_max)
425 __tzname_cur_max = len0;
426 if (len1 > __tzname_cur_max)
427 __tzname_cur_max = len1;
431 /* Figure out the exact time (as a time_t) in YEAR
432 when the change described by RULE will occur and
433 put it in RULE->change, saving YEAR in RULE->computed_for. */
434 static void
435 internal_function
436 compute_change (rule, year)
437 tz_rule *rule;
438 int year;
440 register time_t t;
442 if (year != -1 && rule->computed_for == year)
443 /* Operations on times in 2 BC will be slower. Oh well. */
444 return;
446 /* First set T to January 1st, 0:00:00 GMT in YEAR. */
447 if (year > 1970)
448 t = ((year - 1970) * 365
449 + /* Compute the number of leapdays between 1970 and YEAR
450 (exclusive). There is a leapday every 4th year ... */
451 + ((year - 1) / 4 - 1970 / 4)
452 /* ... except every 100th year ... */
453 - ((year - 1) / 100 - 1970 / 100)
454 /* ... but still every 400th year. */
455 + ((year - 1) / 400 - 1970 / 400)) * SECSPERDAY;
456 else
457 t = 0;
459 switch (rule->type)
461 case J1:
462 /* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap years.
463 In non-leap years, or if the day number is 59 or less, just
464 add SECSPERDAY times the day number-1 to the time of
465 January 1, midnight, to get the day. */
466 t += (rule->d - 1) * SECSPERDAY;
467 if (rule->d >= 60 && __isleap (year))
468 t += SECSPERDAY;
469 break;
471 case J0:
472 /* n - Day of year.
473 Just add SECSPERDAY times the day number to the time of Jan 1st. */
474 t += rule->d * SECSPERDAY;
475 break;
477 case M:
478 /* Mm.n.d - Nth "Dth day" of month M. */
480 unsigned int i;
481 int d, m1, yy0, yy1, yy2, dow;
482 const unsigned short int *myday =
483 &__mon_yday[__isleap (year)][rule->m];
485 /* First add SECSPERDAY for each day in months before M. */
486 t += myday[-1] * SECSPERDAY;
488 /* Use Zeller's Congruence to get day-of-week of first day of month. */
489 m1 = (rule->m + 9) % 12 + 1;
490 yy0 = (rule->m <= 2) ? (year - 1) : year;
491 yy1 = yy0 / 100;
492 yy2 = yy0 % 100;
493 dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
494 if (dow < 0)
495 dow += 7;
497 /* DOW is the day-of-week of the first day of the month. Get the
498 day-of-month (zero-origin) of the first DOW day of the month. */
499 d = rule->d - dow;
500 if (d < 0)
501 d += 7;
502 for (i = 1; i < rule->n; ++i)
504 if (d + 7 >= (int) myday[0] - myday[-1])
505 break;
506 d += 7;
509 /* D is the day-of-month (zero-origin) of the day we want. */
510 t += d * SECSPERDAY;
512 break;
515 /* T is now the Epoch-relative time of 0:00:00 GMT on the day we want.
516 Just add the time of day and local offset from GMT, and we're done. */
518 rule->change = t - rule->offset + rule->secs;
519 rule->computed_for = year;
523 /* Figure out the correct timezone for TM and set `__tzname',
524 `__timezone', and `__daylight' accordingly. */
525 static void
526 internal_function
527 tz_compute (tm)
528 const struct tm *tm;
530 compute_change (&tz_rules[0], 1900 + tm->tm_year);
531 compute_change (&tz_rules[1], 1900 + tm->tm_year);
534 /* Reinterpret the TZ environment variable and set `tzname'. */
535 #undef tzset
537 void
538 __tzset (void)
540 __libc_lock_lock (tzset_lock);
542 tzset_internal (1, 1);
544 if (!__use_tzfile)
546 /* Set `tzname'. */
547 __tzname[0] = (char *) tz_rules[0].name;
548 __tzname[1] = (char *) tz_rules[1].name;
551 __libc_lock_unlock (tzset_lock);
553 weak_alias (__tzset, tzset)
555 /* Return the `struct tm' representation of *TIMER in the local timezone.
556 Use local time if USE_LOCALTIME is nonzero, UTC otherwise. */
557 struct tm *
558 __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
560 long int leap_correction;
561 int leap_extra_secs;
563 if (timer == NULL)
565 __set_errno (EINVAL);
566 return NULL;
569 __libc_lock_lock (tzset_lock);
571 /* Update internal database according to current TZ setting.
572 POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
573 This is a good idea since this allows at least a bit more parallelism.
574 By analogy we apply the same rule to gmtime_r. */
575 tzset_internal (tp == &_tmbuf, 0);
577 if (__use_tzfile)
578 __tzfile_compute (*timer, use_localtime, &leap_correction,
579 &leap_extra_secs, tp);
580 else
582 if (! __offtime (timer, 0, tp))
583 tp = NULL;
584 else
585 tz_compute (tp);
586 leap_correction = 0L;
587 leap_extra_secs = 0;
590 if (tp)
592 if (use_localtime)
594 if (!__use_tzfile)
596 int isdst;
598 /* We have to distinguish between northern and southern
599 hemisphere. For the latter the daylight saving time
600 ends in the next year. */
601 if (__builtin_expect (tz_rules[0].change
602 > tz_rules[1].change, 0))
603 isdst = (*timer < tz_rules[1].change
604 || *timer >= tz_rules[0].change);
605 else
606 isdst = (*timer >= tz_rules[0].change
607 && *timer < tz_rules[1].change);
608 tp->tm_isdst = isdst;
609 tp->tm_zone = __tzname[isdst];
610 tp->tm_gmtoff = tz_rules[isdst].offset;
613 else
615 tp->tm_isdst = 0;
616 tp->tm_zone = "GMT";
617 tp->tm_gmtoff = 0L;
620 if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp))
621 tp->tm_sec += leap_extra_secs;
622 else
623 tp = NULL;
626 __libc_lock_unlock (tzset_lock);
628 return tp;
632 libc_freeres_fn (free_mem)
634 while (tzstring_list != NULL)
636 struct tzstring_l *old = tzstring_list;
638 tzstring_list = tzstring_list->next;
639 free (old);
641 free (old_tz);
642 old_tz = NULL;