Update.
[glibc.git] / time / tzset.c
blob92e22083d5f626c81767753470ec9045d8d46b2b
1 /* Copyright (C) 1991,92,93,94,95,96,97,98 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 Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 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 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 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>
28 /* Defined in mktime.c. */
29 extern const unsigned short int __mon_yday[2][13];
31 /* Defined in localtime.c. */
32 extern struct tm _tmbuf;
34 #define NOID
35 #include <timezone/tzfile.h>
37 extern int __use_tzfile;
38 extern void __tzfile_read __P ((const char *file));
39 extern int __tzfile_compute __P ((time_t timer, int use_localtime,
40 long int *leap_correct, int *leap_hit,
41 struct tm *tp));
42 extern void __tzfile_default __P ((const char *std, const char *dst,
43 long int stdoff, long int dstoff));
44 extern char *__tzstring __P ((const char *string));
46 char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
47 int __daylight = 0;
48 long int __timezone = 0L;
50 weak_alias (__tzname, tzname)
51 weak_alias (__daylight, daylight)
52 weak_alias (__timezone, timezone)
54 /* This locks all the state variables in tzfile.c and this file. */
55 __libc_lock_define (static, tzset_lock)
58 #define min(a, b) ((a) < (b) ? (a) : (b))
59 #define max(a, b) ((a) > (b) ? (a) : (b))
60 #define sign(x) ((x) < 0 ? -1 : 1)
63 /* This structure contains all the information about a
64 timezone given in the POSIX standard TZ envariable. */
65 typedef struct
67 const char *name;
69 /* When to change. */
70 enum { J0, J1, M } type; /* Interpretation of: */
71 unsigned short int m, n, d; /* Month, week, day. */
72 unsigned int secs; /* Time of day. */
74 long int offset; /* Seconds east of GMT (west if < 0). */
76 /* We cache the computed time of change for a
77 given year so we don't have to recompute it. */
78 time_t change; /* When to change to this zone. */
79 int computed_for; /* Year above is computed for. */
80 } tz_rule;
82 /* tz_rules[0] is standard, tz_rules[1] is daylight. */
83 static tz_rule tz_rules[2];
86 static int compute_change __P ((tz_rule *rule, int year)) internal_function;
87 static int tz_compute __P ((time_t timer, const struct tm *tm))
88 internal_function;
89 static void tzset_internal __P ((int always)) internal_function;
91 /* List of buffers containing time zone strings. */
92 struct tzstring_l
94 struct tzstring_l *next;
95 size_t len; /* strlen(data) - doesn't count terminating NUL! */
96 char data[0];
99 struct tzstring_l *tzstring_list;
101 /* Allocate a permanent home for S. It will never be moved or deallocated,
102 but may share space with other strings.
103 Don't modify the returned string. */
104 char *
105 __tzstring (const char *s)
107 char *p;
108 struct tzstring_l *t, *u, *new;
109 size_t len = strlen(s);
111 /* Walk the list and look for a match. If this string is the same
112 as the end of an already-allocated string, it can share space. */
113 for (u = t = tzstring_list; t; u = t, t = t->next)
114 if (len <= t->len)
116 p = &t->data[t->len - len];
117 if (strcmp (s, p) == 0)
118 return p;
121 /* Not found; allocate a new buffer. */
122 new = malloc (sizeof (struct tzstring_l) + len + 1);
123 if (!new)
124 return NULL;
126 new->next = NULL;
127 new->len = len;
128 strcpy (new->data, s);
130 if (u)
131 u->next = new;
132 else
133 tzstring_list = new;
135 return new->data;
138 static char *old_tz = NULL;
140 /* Interpret the TZ envariable. */
141 static void
142 internal_function
143 tzset_internal (always)
144 int always;
146 static int is_initialized = 0;
147 register const char *tz;
148 register size_t l;
149 char *tzbuf;
150 unsigned short int hh, mm, ss;
151 unsigned short int whichrule;
153 if (is_initialized && !always)
154 return;
155 is_initialized = 1;
157 /* Examine the TZ environment variable. */
158 tz = getenv ("TZ");
159 if (tz == NULL)
160 /* No user specification; use the site-wide default. */
161 tz = TZDEFAULT;
162 else if (*tz == '\0')
163 /* User specified the empty string; use UTC explicitly. */
164 tz = "Universal";
166 /* A leading colon means "implementation defined syntax".
167 We ignore the colon and always use the same algorithm:
168 try a data file, and if none exists parse the 1003.1 syntax. */
169 if (tz && *tz == ':')
170 ++tz;
172 /* Check whether the value changes since the last run. */
173 if (old_tz != NULL && tz != NULL && strcmp (tz, old_tz) == 0)
174 /* No change, simply return. */
175 return;
177 tz_rules[0].name = NULL;
178 tz_rules[1].name = NULL;
180 /* Save the value of `tz'. */
181 if (old_tz != NULL)
182 free (old_tz);
183 old_tz = tz ? __strdup (tz) : NULL;
185 /* Try to read a data file. */
186 __tzfile_read (tz);
187 if (__use_tzfile)
188 return;
190 /* No data file found. Default to UTC if nothing specified. */
192 if (tz == NULL || *tz == '\0')
194 tz_rules[0].name = tz_rules[1].name = "UTC";
195 tz_rules[0].type = tz_rules[1].type = J0;
196 tz_rules[0].m = tz_rules[0].n = tz_rules[0].d = 0;
197 tz_rules[1].m = tz_rules[1].n = tz_rules[1].d = 0;
198 tz_rules[0].secs = tz_rules[1].secs = 0;
199 tz_rules[0].offset = tz_rules[1].offset = 0L;
200 tz_rules[0].change = tz_rules[1].change = (time_t) -1;
201 tz_rules[0].computed_for = tz_rules[1].computed_for = 0;
202 return;
205 /* Clear out old state and reset to unnamed UTC. */
206 memset (tz_rules, 0, sizeof tz_rules);
207 tz_rules[0].name = tz_rules[1].name = "";
209 /* Get the standard timezone name. */
210 tzbuf = strdupa (tz);
212 if (sscanf (tz, "%[^0-9,+-]", tzbuf) != 1 ||
213 (l = strlen (tzbuf)) < 3)
214 return;
216 tz_rules[0].name = __tzstring (tzbuf);
218 tz += l;
220 /* Figure out the standard offset from UTC. */
221 if (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit (*tz)))
222 return;
224 if (*tz == '-' || *tz == '+')
225 tz_rules[0].offset = *tz++ == '-' ? 1L : -1L;
226 else
227 tz_rules[0].offset = -1L;
228 switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
230 default:
231 return;
232 case 1:
233 mm = 0;
234 case 2:
235 ss = 0;
236 case 3:
237 break;
239 tz_rules[0].offset *= (min (ss, 59) + (min (mm, 59) * 60) +
240 (min (hh, 23) * 60 * 60));
242 for (l = 0; l < 3; ++l)
244 while (isdigit(*tz))
245 ++tz;
246 if (l < 2 && *tz == ':')
247 ++tz;
250 /* Get the DST timezone name (if any). */
251 if (*tz != '\0')
253 char *n = tzbuf + strlen (tzbuf) + 1;
254 if (sscanf (tz, "%[^0-9,+-]", n) != 1 ||
255 (l = strlen (n)) < 3)
256 goto done_names; /* Punt on name, set up the offsets. */
258 tz_rules[1].name = __tzstring (n);
260 tz += l;
262 /* Figure out the DST offset from GMT. */
263 if (*tz == '-' || *tz == '+')
264 tz_rules[1].offset = *tz++ == '-' ? 1L : -1L;
265 else
266 tz_rules[1].offset = -1L;
268 switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
270 default:
271 /* Default to one hour later than standard time. */
272 tz_rules[1].offset = tz_rules[0].offset + (60 * 60);
273 break;
275 case 1:
276 mm = 0;
277 case 2:
278 ss = 0;
279 case 3:
280 tz_rules[1].offset *= (min (ss, 59) + (min (mm, 59) * 60) +
281 (min (hh, 23) * (60 * 60)));
282 break;
284 for (l = 0; l < 3; ++l)
286 while (isdigit (*tz))
287 ++tz;
288 if (l < 2 && *tz == ':')
289 ++tz;
291 if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0'))
293 /* There is no rule. See if there is a default rule file. */
294 __tzfile_default (tz_rules[0].name, tz_rules[1].name,
295 tz_rules[0].offset, tz_rules[1].offset);
296 if (__use_tzfile)
298 free (old_tz);
299 old_tz = NULL;
300 return;
304 else
306 /* There is no DST. */
307 tz_rules[1].name = tz_rules[0].name;
308 tz_rules[1].offset = tz_rules[0].offset;
309 goto out;
312 done_names:
313 /* Figure out the standard <-> DST rules. */
314 for (whichrule = 0; whichrule < 2; ++whichrule)
316 register tz_rule *tzr = &tz_rules[whichrule];
318 /* Ignore comma to support string following the incorrect
319 specification in early POSIX.1 printings. */
320 tz += *tz == ',';
322 /* Get the date of the change. */
323 if (*tz == 'J' || isdigit (*tz))
325 char *end;
326 tzr->type = *tz == 'J' ? J1 : J0;
327 if (tzr->type == J1 && !isdigit (*++tz))
328 goto out;
329 tzr->d = (unsigned short int) strtoul (tz, &end, 10);
330 if (end == tz || tzr->d > 365)
331 goto out;
332 else if (tzr->type == J1 && tzr->d == 0)
333 goto out;
334 tz = end;
336 else if (*tz == 'M')
338 int n;
339 tzr->type = M;
340 if (sscanf (tz, "M%hu.%hu.%hu%n",
341 &tzr->m, &tzr->n, &tzr->d, &n) != 3 ||
342 tzr->m < 1 || tzr->m > 12 ||
343 tzr->n < 1 || tzr->n > 5 || tzr->d > 6)
344 goto out;
345 tz += n;
347 else if (*tz == '\0')
349 /* United States Federal Law, the equivalent of "M4.1.0,M10.5.0". */
350 tzr->type = M;
351 if (tzr == &tz_rules[0])
353 tzr->m = 4;
354 tzr->n = 1;
355 tzr->d = 0;
357 else
359 tzr->m = 10;
360 tzr->n = 5;
361 tzr->d = 0;
364 else
365 goto out;
367 if (*tz != '\0' && *tz != '/' && *tz != ',')
368 goto out;
369 else if (*tz == '/')
371 /* Get the time of day of the change. */
372 ++tz;
373 if (*tz == '\0')
374 goto out;
375 switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
377 default:
378 hh = 2; /* Default to 2:00 AM. */
379 case 1:
380 mm = 0;
381 case 2:
382 ss = 0;
383 case 3:
384 break;
386 for (l = 0; l < 3; ++l)
388 while (isdigit (*tz))
389 ++tz;
390 if (l < 2 && *tz == ':')
391 ++tz;
393 tzr->secs = (hh * 60 * 60) + (mm * 60) + ss;
395 else
396 /* Default to 2:00 AM. */
397 tzr->secs = 2 * 60 * 60;
399 tzr->computed_for = -1;
402 out:
403 /* We know the offset now, set `__timezone'. */
404 __timezone = -tz_rules[0].offset;
407 /* Maximum length of a timezone name. __tz_compute keeps this up to date
408 (never decreasing it) when ! __use_tzfile.
409 tzfile.c keeps it up to date when __use_tzfile. */
410 size_t __tzname_cur_max;
412 long int
413 __tzname_max ()
415 __libc_lock_lock (tzset_lock);
417 tzset_internal (0);
419 __libc_lock_unlock (tzset_lock);
421 return __tzname_cur_max;
424 /* Figure out the exact time (as a time_t) in YEAR
425 when the change described by RULE will occur and
426 put it in RULE->change, saving YEAR in RULE->computed_for.
427 Return nonzero if successful, zero on failure. */
428 static int
429 internal_function
430 compute_change (rule, year)
431 tz_rule *rule;
432 int year;
434 register time_t t;
435 int y;
437 if (year != -1 && rule->computed_for == year)
438 /* Operations on times in 1969 will be slower. Oh well. */
439 return 1;
441 /* First set T to January 1st, 0:00:00 GMT in YEAR. */
442 t = 0;
443 for (y = 1970; y < year; ++y)
444 t += SECSPERDAY * (__isleap (y) ? 366 : 365);
446 switch (rule->type)
448 case J1:
449 /* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap years.
450 In non-leap years, or if the day number is 59 or less, just
451 add SECSPERDAY times the day number-1 to the time of
452 January 1, midnight, to get the day. */
453 t += (rule->d - 1) * SECSPERDAY;
454 if (rule->d >= 60 && __isleap (year))
455 t += SECSPERDAY;
456 break;
458 case J0:
459 /* n - Day of year.
460 Just add SECSPERDAY times the day number to the time of Jan 1st. */
461 t += rule->d * SECSPERDAY;
462 break;
464 case M:
465 /* Mm.n.d - Nth "Dth day" of month M. */
467 unsigned int i;
468 int d, m1, yy0, yy1, yy2, dow;
469 const unsigned short int *myday =
470 &__mon_yday[__isleap (year)][rule->m];
472 /* First add SECSPERDAY for each day in months before M. */
473 t += myday[-1] * SECSPERDAY;
475 /* Use Zeller's Congruence to get day-of-week of first day of month. */
476 m1 = (rule->m + 9) % 12 + 1;
477 yy0 = (rule->m <= 2) ? (year - 1) : year;
478 yy1 = yy0 / 100;
479 yy2 = yy0 % 100;
480 dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
481 if (dow < 0)
482 dow += 7;
484 /* DOW is the day-of-week of the first day of the month. Get the
485 day-of-month (zero-origin) of the first DOW day of the month. */
486 d = rule->d - dow;
487 if (d < 0)
488 d += 7;
489 for (i = 1; i < rule->n; ++i)
491 if (d + 7 >= (int) myday[0] - myday[-1])
492 break;
493 d += 7;
496 /* D is the day-of-month (zero-origin) of the day we want. */
497 t += d * SECSPERDAY;
499 break;
502 /* T is now the Epoch-relative time of 0:00:00 GMT on the day we want.
503 Just add the time of day and local offset from GMT, and we're done. */
505 rule->change = t - rule->offset + rule->secs;
506 rule->computed_for = year;
507 return 1;
511 /* Figure out the correct timezone for *TIMER and TM (which must be the same)
512 and set `__tzname', `__timezone', and `__daylight' accordingly.
513 Return nonzero on success, zero on failure. */
514 static int
515 internal_function
516 tz_compute (timer, tm)
517 time_t timer;
518 const struct tm *tm;
520 if (! compute_change (&tz_rules[0], 1900 + tm->tm_year)
521 || ! compute_change (&tz_rules[1], 1900 + tm->tm_year))
522 return 0;
523 /* We have to distinguish between northern and southern hemisphere.
524 For the later the daylight saving time ends in the next year.
525 It is easier to detect this after first computing the time for the
526 wrong year since now we simply can compare the times to switch. */
527 if (tz_rules[0].change > tz_rules[1].change
528 && ! compute_change (&tz_rules[1], 1900 + tm->tm_year + 1))
529 return 0;
531 __daylight = tz_rules[0].offset != tz_rules[1].offset;
532 __timezone = -tz_rules[0].offset;
533 __tzname[0] = (char *) tz_rules[0].name;
534 __tzname[1] = (char *) tz_rules[1].name;
537 /* Keep __tzname_cur_max up to date. */
538 size_t len0 = strlen (__tzname[0]);
539 size_t len1 = strlen (__tzname[1]);
540 if (len0 > __tzname_cur_max)
541 __tzname_cur_max = len0;
542 if (len1 > __tzname_cur_max)
543 __tzname_cur_max = len1;
546 return 1;
549 /* Reinterpret the TZ environment variable and set `tzname'. */
550 #undef tzset
552 void
553 __tzset (void)
555 __libc_lock_lock (tzset_lock);
557 tzset_internal (1);
559 if (!__use_tzfile)
561 /* Set `tzname'. */
562 __tzname[0] = (char *) tz_rules[0].name;
563 __tzname[1] = (char *) tz_rules[1].name;
566 __libc_lock_unlock (tzset_lock);
568 weak_alias (__tzset, tzset)
570 /* Return the `struct tm' representation of *TIMER in the local timezone.
571 Use local time if USE_LOCALTIME is nonzero, UTC otherwise. */
572 struct tm *
573 __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
575 long int leap_correction;
576 int leap_extra_secs;
578 if (timer == NULL)
580 __set_errno (EINVAL);
581 return NULL;
584 __libc_lock_lock (tzset_lock);
586 /* Update internal database according to current TZ setting.
587 POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
588 This is a good idea since this allows at least a bit more parallelism.
589 By analogy we apply the same rule to gmtime_r. */
590 tzset_internal (tp == &_tmbuf);
592 if (__use_tzfile)
594 if (! __tzfile_compute (*timer, use_localtime,
595 &leap_correction, &leap_extra_secs, tp))
596 tp = NULL;
598 else
600 if (! (__offtime (timer, 0, tp) && tz_compute (*timer, tp)))
601 tp = NULL;
602 leap_correction = 0L;
603 leap_extra_secs = 0;
606 if (tp)
608 if (use_localtime)
610 if (!__use_tzfile)
612 int isdst = (*timer >= tz_rules[0].change
613 && *timer < tz_rules[1].change);
614 tp->tm_isdst = isdst;
615 tp->tm_zone = __tzname[isdst];
616 tp->tm_gmtoff = tz_rules[isdst].offset;
619 else
621 tp->tm_isdst = 0;
622 tp->tm_zone = "GMT";
623 tp->tm_gmtoff = 0L;
626 if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp))
627 tp->tm_sec += leap_extra_secs;
628 else
629 tp = NULL;
632 __libc_lock_unlock (tzset_lock);
634 return tp;