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
21 #include <bits/libc-lock.h>
30 #include <timezone/tzfile.h>
32 char *__tzname
[2] = { (char *) "GMT", (char *) "GMT" };
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. */
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. */
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. */
79 struct tzstring_l
*next
;
80 size_t len
; /* strlen(data) - doesn't count terminating NUL! */
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. */
90 __tzstring (const char *s
)
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
)
101 p
= &t
->data
[t
->len
- len
];
102 if (strcmp (s
, p
) == 0)
106 /* Not found; allocate a new buffer. */
107 new = malloc (sizeof (struct tzstring_l
) + len
+ 1);
113 strcpy (new->data
, s
);
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
;
131 __libc_lock_lock (tzset_lock
);
133 tzset_internal (0, 0);
135 __libc_lock_unlock (tzset_lock
);
137 return __tzname_cur_max
;
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
;
162 __attribute_noinline__
163 compute_offset (unsigned int ss
, unsigned int mm
, unsigned int hh
)
165 return min (ss
, 59) + min (mm
, 59) * 60 + min (hh
, 24) * 60 * 60;
169 /* Parse the POSIX TZ-style string. */
171 __tzset_parse_tz (tz
)
174 unsigned short int hh
, mm
, ss
;
176 /* Clear out old state and reset to unnamed UTC. */
177 memset (tz_rules
, '\0', sizeof tz_rules
);
178 tz_rules
[0].name
= tz_rules
[1].name
= "";
180 /* Get the standard timezone name. */
181 char *tzbuf
= strdupa (tz
);
184 if (sscanf (tz
, "%[A-Za-z]%n", tzbuf
, &consumed
) != 1)
186 /* Check for the quoted version. */
188 if (__builtin_expect (*tz
++ != '<', 0))
191 while (isalnum (*tz
) || *tz
== '+' || *tz
== '-')
193 if (__builtin_expect (*tz
++ != '>' || wp
- tzbuf
< 3, 0))
197 else if (__builtin_expect (consumed
< 3, 0))
202 tz_rules
[0].name
= __tzstring (tzbuf
);
204 /* Figure out the standard offset from UTC. */
205 if (*tz
== '\0' || (*tz
!= '+' && *tz
!= '-' && !isdigit (*tz
)))
208 if (*tz
== '-' || *tz
== '+')
209 tz_rules
[0].offset
= *tz
++ == '-' ? 1L : -1L;
211 tz_rules
[0].offset
= -1L;
212 switch (sscanf (tz
, "%hu%n:%hu%n:%hu%n",
213 &hh
, &consumed
, &mm
, &consumed
, &ss
, &consumed
))
216 tz_rules
[0].offset
= 0;
225 tz_rules
[0].offset
*= compute_offset (ss
, mm
, hh
);
228 /* Get the DST timezone name (if any). */
231 if (sscanf (tz
, "%[A-Za-z]%n", tzbuf
, &consumed
) != 1)
233 /* Check for the quoted version. */
236 if (__builtin_expect (*rp
++ != '<', 0))
237 /* Punt on name, set up the offsets. */
240 while (isalnum (*rp
) || *rp
== '+' || *rp
== '-')
242 if (__builtin_expect (*rp
++ != '>' || wp
- tzbuf
< 3, 0))
243 /* Punt on name, set up the offsets. */
248 else if (__builtin_expect (consumed
< 3, 0))
249 /* Punt on name, set up the offsets. */
254 tz_rules
[1].name
= __tzstring (tzbuf
);
256 /* Figure out the DST offset from GMT. */
257 if (*tz
== '-' || *tz
== '+')
258 tz_rules
[1].offset
= *tz
++ == '-' ? 1L : -1L;
260 tz_rules
[1].offset
= -1L;
262 switch (sscanf (tz
, "%hu%n:%hu%n:%hu%n",
263 &hh
, &consumed
, &mm
, &consumed
, &ss
, &consumed
))
266 /* Default to one hour later than standard time. */
267 tz_rules
[1].offset
= tz_rules
[0].offset
+ (60 * 60);
275 tz_rules
[1].offset
*= compute_offset (ss
, mm
, hh
);
279 if (*tz
== '\0' || (tz
[0] == ',' && tz
[1] == '\0'))
281 /* There is no rule. See if there is a default rule file. */
282 __tzfile_default (tz_rules
[0].name
, tz_rules
[1].name
,
283 tz_rules
[0].offset
, tz_rules
[1].offset
);
294 /* There is no DST. */
295 tz_rules
[1].name
= tz_rules
[0].name
;
296 tz_rules
[1].offset
= tz_rules
[0].offset
;
301 /* Figure out the standard <-> DST rules. */
302 for (unsigned int whichrule
= 0; whichrule
< 2; ++whichrule
)
304 register tz_rule
*tzr
= &tz_rules
[whichrule
];
306 /* Ignore comma to support string following the incorrect
307 specification in early POSIX.1 printings. */
310 /* Get the date of the change. */
311 if (*tz
== 'J' || isdigit (*tz
))
314 tzr
->type
= *tz
== 'J' ? J1
: J0
;
315 if (tzr
->type
== J1
&& !isdigit (*++tz
))
317 unsigned long int d
= strtoul (tz
, &end
, 10);
318 if (end
== tz
|| d
> 365)
320 if (tzr
->type
== J1
&& d
== 0)
328 if (sscanf (tz
, "M%hu.%hu.%hu%n",
329 &tzr
->m
, &tzr
->n
, &tzr
->d
, &consumed
) != 3
330 || tzr
->m
< 1 || tzr
->m
> 12
331 || tzr
->n
< 1 || tzr
->n
> 5 || tzr
->d
> 6)
335 else if (*tz
== '\0')
337 /* United States Federal Law, the equivalent of "M4.1.0,M10.5.0". */
339 if (tzr
== &tz_rules
[0])
355 if (*tz
!= '\0' && *tz
!= '/' && *tz
!= ',')
359 /* Get the time of day of the change. */
364 switch (sscanf (tz
, "%hu%n:%hu%n:%hu%n",
365 &hh
, &consumed
, &mm
, &consumed
, &ss
, &consumed
))
368 hh
= 2; /* Default to 2:00 AM. */
377 tzr
->secs
= (hh
* 60 * 60) + (mm
* 60) + ss
;
380 /* Default to 2:00 AM. */
381 tzr
->secs
= 2 * 60 * 60;
383 tzr
->computed_for
= -1;
390 /* Interpret the TZ envariable. */
393 tzset_internal (always
, explicit)
397 static int is_initialized
;
398 register const char *tz
;
400 if (is_initialized
&& !always
)
404 /* Examine the TZ environment variable. */
406 if (tz
== NULL
&& !explicit)
407 /* Use the site-wide default. This is a file name which means we
408 would not see changes to the file if we compare only the file
409 name for change. We want to notice file changes if tzset() has
410 been called explicitly. Leave TZ as NULL in this case. */
412 if (tz
&& *tz
== '\0')
413 /* User specified the empty string; use UTC explicitly. */
416 /* A leading colon means "implementation defined syntax".
417 We ignore the colon and always use the same algorithm:
418 try a data file, and if none exists parse the 1003.1 syntax. */
419 if (tz
&& *tz
== ':')
422 /* Check whether the value changed since the last run. */
423 if (old_tz
!= NULL
&& tz
!= NULL
&& strcmp (tz
, old_tz
) == 0)
424 /* No change, simply return. */
428 /* No user specification; use the site-wide default. */
431 tz_rules
[0].name
= NULL
;
432 tz_rules
[1].name
= NULL
;
434 /* Save the value of `tz'. */
436 old_tz
= tz
? __strdup (tz
) : NULL
;
438 /* Try to read a data file. */
439 __tzfile_read (tz
, 0, NULL
);
443 /* No data file found. Default to UTC if nothing specified. */
445 if (tz
== NULL
|| *tz
== '\0'
446 || (TZDEFAULT
!= NULL
&& strcmp (tz
, TZDEFAULT
) == 0))
448 memset (tz_rules
, '\0', sizeof tz_rules
);
449 tz_rules
[0].name
= tz_rules
[1].name
= "UTC";
451 tz_rules
[0].type
= tz_rules
[1].type
= J0
;
452 tz_rules
[0].change
= tz_rules
[1].change
= (time_t) -1;
457 __tzset_parse_tz (tz
);
460 /* Figure out the exact time (as a time_t) in YEAR
461 when the change described by RULE will occur and
462 put it in RULE->change, saving YEAR in RULE->computed_for. */
465 compute_change (rule
, year
)
471 if (year
!= -1 && rule
->computed_for
== year
)
472 /* Operations on times in 2 BC will be slower. Oh well. */
475 /* First set T to January 1st, 0:00:00 GMT in YEAR. */
477 t
= ((year
- 1970) * 365
478 + /* Compute the number of leapdays between 1970 and YEAR
479 (exclusive). There is a leapday every 4th year ... */
480 + ((year
- 1) / 4 - 1970 / 4)
481 /* ... except every 100th year ... */
482 - ((year
- 1) / 100 - 1970 / 100)
483 /* ... but still every 400th year. */
484 + ((year
- 1) / 400 - 1970 / 400)) * SECSPERDAY
;
491 /* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap years.
492 In non-leap years, or if the day number is 59 or less, just
493 add SECSPERDAY times the day number-1 to the time of
494 January 1, midnight, to get the day. */
495 t
+= (rule
->d
- 1) * SECSPERDAY
;
496 if (rule
->d
>= 60 && __isleap (year
))
502 Just add SECSPERDAY times the day number to the time of Jan 1st. */
503 t
+= rule
->d
* SECSPERDAY
;
507 /* Mm.n.d - Nth "Dth day" of month M. */
510 int d
, m1
, yy0
, yy1
, yy2
, dow
;
511 const unsigned short int *myday
=
512 &__mon_yday
[__isleap (year
)][rule
->m
];
514 /* First add SECSPERDAY for each day in months before M. */
515 t
+= myday
[-1] * SECSPERDAY
;
517 /* Use Zeller's Congruence to get day-of-week of first day of month. */
518 m1
= (rule
->m
+ 9) % 12 + 1;
519 yy0
= (rule
->m
<= 2) ? (year
- 1) : year
;
522 dow
= ((26 * m1
- 2) / 10 + 1 + yy2
+ yy2
/ 4 + yy1
/ 4 - 2 * yy1
) % 7;
526 /* DOW is the day-of-week of the first day of the month. Get the
527 day-of-month (zero-origin) of the first DOW day of the month. */
531 for (i
= 1; i
< rule
->n
; ++i
)
533 if (d
+ 7 >= (int) myday
[0] - myday
[-1])
538 /* D is the day-of-month (zero-origin) of the day we want. */
544 /* T is now the Epoch-relative time of 0:00:00 GMT on the day we want.
545 Just add the time of day and local offset from GMT, and we're done. */
547 rule
->change
= t
- rule
->offset
+ rule
->secs
;
548 rule
->computed_for
= year
;
552 /* Figure out the correct timezone for TM and set `__tzname',
553 `__timezone', and `__daylight' accordingly. */
556 __tz_compute (timer
, tm
, use_localtime
)
561 compute_change (&tz_rules
[0], 1900 + tm
->tm_year
);
562 compute_change (&tz_rules
[1], 1900 + tm
->tm_year
);
568 /* We have to distinguish between northern and southern
569 hemisphere. For the latter the daylight saving time
570 ends in the next year. */
571 if (__builtin_expect (tz_rules
[0].change
572 > tz_rules
[1].change
, 0))
573 isdst
= (timer
< tz_rules
[1].change
574 || timer
>= tz_rules
[0].change
);
576 isdst
= (timer
>= tz_rules
[0].change
577 && timer
< tz_rules
[1].change
);
578 tm
->tm_isdst
= isdst
;
579 tm
->tm_zone
= __tzname
[isdst
];
580 tm
->tm_gmtoff
= tz_rules
[isdst
].offset
;
584 /* Reinterpret the TZ environment variable and set `tzname'. */
590 __libc_lock_lock (tzset_lock
);
592 tzset_internal (1, 1);
597 __tzname
[0] = (char *) tz_rules
[0].name
;
598 __tzname
[1] = (char *) tz_rules
[1].name
;
601 __libc_lock_unlock (tzset_lock
);
603 weak_alias (__tzset
, tzset
)
605 /* Return the `struct tm' representation of *TIMER in the local timezone.
606 Use local time if USE_LOCALTIME is nonzero, UTC otherwise. */
608 __tz_convert (const time_t *timer
, int use_localtime
, struct tm
*tp
)
610 long int leap_correction
;
615 __set_errno (EINVAL
);
619 __libc_lock_lock (tzset_lock
);
621 /* Update internal database according to current TZ setting.
622 POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
623 This is a good idea since this allows at least a bit more parallelism. */
624 tzset_internal (tp
== &_tmbuf
&& use_localtime
, 1);
627 __tzfile_compute (*timer
, use_localtime
, &leap_correction
,
628 &leap_extra_secs
, tp
);
631 if (! __offtime (timer
, 0, tp
))
634 __tz_compute (*timer
, tp
, use_localtime
);
635 leap_correction
= 0L;
648 if (__offtime (timer
, tp
->tm_gmtoff
- leap_correction
, tp
))
649 tp
->tm_sec
+= leap_extra_secs
;
654 __libc_lock_unlock (tzset_lock
);
660 libc_freeres_fn (free_mem
)
662 while (tzstring_list
!= NULL
)
664 struct tzstring_l
*old
= tzstring_list
;
666 tzstring_list
= tzstring_list
->next
;