1 /* Copyright (C) 1991-2013 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, see
16 <http://www.gnu.org/licenses/>. */
20 #include <bits/libc-lock.h>
29 #include <timezone/tzfile.h>
31 char *__tzname
[2] = { (char *) "GMT", (char *) "GMT" };
33 long int __timezone
= 0L;
35 weak_alias (__tzname
, tzname
)
36 weak_alias (__daylight
, daylight
)
37 weak_alias (__timezone
, timezone
)
39 /* This locks all the state variables in tzfile.c and this file. */
40 __libc_lock_define_initialized (static, tzset_lock
)
43 #define min(a, b) ((a) < (b) ? (a) : (b))
44 #define max(a, b) ((a) > (b) ? (a) : (b))
45 #define sign(x) ((x) < 0 ? -1 : 1)
48 /* This structure contains all the information about a
49 timezone given in the POSIX standard TZ envariable. */
55 enum { J0
, J1
, M
} type
; /* Interpretation of: */
56 unsigned short int m
, n
, d
; /* Month, week, day. */
57 unsigned int secs
; /* Time of day. */
59 long int offset
; /* Seconds east of GMT (west if < 0). */
61 /* We cache the computed time of change for a
62 given year so we don't have to recompute it. */
63 time_t change
; /* When to change to this zone. */
64 int computed_for
; /* Year above is computed for. */
67 /* tz_rules[0] is standard, tz_rules[1] is daylight. */
68 static tz_rule tz_rules
[2];
71 static void compute_change (tz_rule
*rule
, int year
) __THROW internal_function
;
72 static void tzset_internal (int always
, int explicit)
73 __THROW internal_function
;
75 /* List of buffers containing time zone strings. */
78 struct tzstring_l
*next
;
79 size_t len
; /* strlen(data) - doesn't count terminating NUL! */
83 static struct tzstring_l
*tzstring_list
;
85 /* Allocate a permanent home for S. It will never be moved or deallocated,
86 but may share space with other strings.
87 Don't modify the returned string. */
89 __tzstring (const char *s
)
92 struct tzstring_l
*t
, *u
, *new;
93 size_t len
= strlen (s
);
95 /* Walk the list and look for a match. If this string is the same
96 as the end of an already-allocated string, it can share space. */
97 for (u
= t
= tzstring_list
; t
; u
= t
, t
= t
->next
)
100 p
= &t
->data
[t
->len
- len
];
101 if (strcmp (s
, p
) == 0)
105 /* Not found; allocate a new buffer. */
106 new = malloc (sizeof (struct tzstring_l
) + len
+ 1);
112 strcpy (new->data
, s
);
122 /* Maximum length of a timezone name. tzset_internal keeps this up to date
123 (never decreasing it) when ! __use_tzfile.
124 tzfile.c keeps it up to date when __use_tzfile. */
125 size_t __tzname_cur_max
;
130 __libc_lock_lock (tzset_lock
);
132 tzset_internal (0, 0);
134 __libc_lock_unlock (tzset_lock
);
136 return __tzname_cur_max
;
145 __daylight
= tz_rules
[0].offset
!= tz_rules
[1].offset
;
146 __timezone
= -tz_rules
[0].offset
;
147 __tzname
[0] = (char *) tz_rules
[0].name
;
148 __tzname
[1] = (char *) tz_rules
[1].name
;
150 /* Keep __tzname_cur_max up to date. */
151 size_t len0
= strlen (__tzname
[0]);
152 size_t len1
= strlen (__tzname
[1]);
153 if (len0
> __tzname_cur_max
)
154 __tzname_cur_max
= len0
;
155 if (len1
> __tzname_cur_max
)
156 __tzname_cur_max
= len1
;
161 __attribute_noinline__
162 compute_offset (unsigned int ss
, unsigned int mm
, unsigned int hh
)
164 return min (ss
, 59) + min (mm
, 59) * 60 + min (hh
, 24) * 60 * 60;
168 /* Parse the POSIX TZ-style string. */
170 __tzset_parse_tz (tz
)
173 unsigned short int hh
, mm
, ss
;
175 /* Clear out old state and reset to unnamed UTC. */
176 memset (tz_rules
, '\0', sizeof tz_rules
);
177 tz_rules
[0].name
= tz_rules
[1].name
= "";
179 /* Get the standard timezone name. */
180 char *tzbuf
= strdupa (tz
);
183 if (sscanf (tz
, "%[A-Za-z]%n", tzbuf
, &consumed
) != 1)
185 /* Check for the quoted version. */
187 if (__builtin_expect (*tz
++ != '<', 0))
190 while (isalnum (*tz
) || *tz
== '+' || *tz
== '-')
192 if (__builtin_expect (*tz
++ != '>' || wp
- tzbuf
< 3, 0))
196 else if (__builtin_expect (consumed
< 3, 0))
201 tz_rules
[0].name
= __tzstring (tzbuf
);
203 /* Figure out the standard offset from UTC. */
204 if (*tz
== '\0' || (*tz
!= '+' && *tz
!= '-' && !isdigit (*tz
)))
207 if (*tz
== '-' || *tz
== '+')
208 tz_rules
[0].offset
= *tz
++ == '-' ? 1L : -1L;
210 tz_rules
[0].offset
= -1L;
211 switch (sscanf (tz
, "%hu%n:%hu%n:%hu%n",
212 &hh
, &consumed
, &mm
, &consumed
, &ss
, &consumed
))
215 tz_rules
[0].offset
= 0;
224 tz_rules
[0].offset
*= compute_offset (ss
, mm
, hh
);
227 /* Get the DST timezone name (if any). */
230 if (sscanf (tz
, "%[A-Za-z]%n", tzbuf
, &consumed
) != 1)
232 /* Check for the quoted version. */
235 if (__builtin_expect (*rp
++ != '<', 0))
236 /* Punt on name, set up the offsets. */
239 while (isalnum (*rp
) || *rp
== '+' || *rp
== '-')
241 if (__builtin_expect (*rp
++ != '>' || wp
- tzbuf
< 3, 0))
242 /* Punt on name, set up the offsets. */
247 else if (__builtin_expect (consumed
< 3, 0))
248 /* Punt on name, set up the offsets. */
253 tz_rules
[1].name
= __tzstring (tzbuf
);
255 /* Figure out the DST offset from GMT. */
256 if (*tz
== '-' || *tz
== '+')
257 tz_rules
[1].offset
= *tz
++ == '-' ? 1L : -1L;
259 tz_rules
[1].offset
= -1L;
261 switch (sscanf (tz
, "%hu%n:%hu%n:%hu%n",
262 &hh
, &consumed
, &mm
, &consumed
, &ss
, &consumed
))
265 /* Default to one hour later than standard time. */
266 tz_rules
[1].offset
= tz_rules
[0].offset
+ (60 * 60);
274 tz_rules
[1].offset
*= compute_offset (ss
, mm
, hh
);
278 if (*tz
== '\0' || (tz
[0] == ',' && tz
[1] == '\0'))
280 /* There is no rule. See if there is a default rule file. */
281 __tzfile_default (tz_rules
[0].name
, tz_rules
[1].name
,
282 tz_rules
[0].offset
, tz_rules
[1].offset
);
293 /* There is no DST. */
294 tz_rules
[1].name
= tz_rules
[0].name
;
295 tz_rules
[1].offset
= tz_rules
[0].offset
;
300 /* Figure out the standard <-> DST rules. */
301 for (unsigned int whichrule
= 0; whichrule
< 2; ++whichrule
)
303 tz_rule
*tzr
= &tz_rules
[whichrule
];
305 /* Ignore comma to support string following the incorrect
306 specification in early POSIX.1 printings. */
309 /* Get the date of the change. */
310 if (*tz
== 'J' || isdigit (*tz
))
313 tzr
->type
= *tz
== 'J' ? J1
: J0
;
314 if (tzr
->type
== J1
&& !isdigit (*++tz
))
316 unsigned long int d
= strtoul (tz
, &end
, 10);
317 if (end
== tz
|| d
> 365)
319 if (tzr
->type
== J1
&& d
== 0)
327 if (sscanf (tz
, "M%hu.%hu.%hu%n",
328 &tzr
->m
, &tzr
->n
, &tzr
->d
, &consumed
) != 3
329 || tzr
->m
< 1 || tzr
->m
> 12
330 || tzr
->n
< 1 || tzr
->n
> 5 || tzr
->d
> 6)
334 else if (*tz
== '\0')
336 /* Daylight time rules in the U.S. are defined in the
337 U.S. Code, Title 15, Chapter 6, Subchapter IX - Standard
338 Time. These dates were established by Congress in the
339 Energy Policy Act of 2005 [Pub. L. no. 109-58, 119 Stat 594
341 Below is the equivalent of "M3.2.0,M11.1.0" [/2 not needed
342 since 2:00AM is the default]. */
344 if (tzr
== &tz_rules
[0])
360 if (*tz
!= '\0' && *tz
!= '/' && *tz
!= ',')
364 /* Get the time of day of the change. */
369 switch (sscanf (tz
, "%hu%n:%hu%n:%hu%n",
370 &hh
, &consumed
, &mm
, &consumed
, &ss
, &consumed
))
373 hh
= 2; /* Default to 2:00 AM. */
382 tzr
->secs
= (hh
* 60 * 60) + (mm
* 60) + ss
;
385 /* Default to 2:00 AM. */
386 tzr
->secs
= 2 * 60 * 60;
388 tzr
->computed_for
= -1;
395 /* Interpret the TZ envariable. */
398 tzset_internal (always
, explicit)
402 static int is_initialized
;
405 if (is_initialized
&& !always
)
409 /* Examine the TZ environment variable. */
411 if (tz
== NULL
&& !explicit)
412 /* Use the site-wide default. This is a file name which means we
413 would not see changes to the file if we compare only the file
414 name for change. We want to notice file changes if tzset() has
415 been called explicitly. Leave TZ as NULL in this case. */
417 if (tz
&& *tz
== '\0')
418 /* User specified the empty string; use UTC explicitly. */
421 /* A leading colon means "implementation defined syntax".
422 We ignore the colon and always use the same algorithm:
423 try a data file, and if none exists parse the 1003.1 syntax. */
424 if (tz
&& *tz
== ':')
427 /* Check whether the value changed since the last run. */
428 if (old_tz
!= NULL
&& tz
!= NULL
&& strcmp (tz
, old_tz
) == 0)
429 /* No change, simply return. */
433 /* No user specification; use the site-wide default. */
436 tz_rules
[0].name
= NULL
;
437 tz_rules
[1].name
= NULL
;
439 /* Save the value of `tz'. */
441 old_tz
= tz
? __strdup (tz
) : NULL
;
443 /* Try to read a data file. */
444 __tzfile_read (tz
, 0, NULL
);
448 /* No data file found. Default to UTC if nothing specified. */
450 if (tz
== NULL
|| *tz
== '\0'
451 || (TZDEFAULT
!= NULL
&& strcmp (tz
, TZDEFAULT
) == 0))
453 memset (tz_rules
, '\0', sizeof tz_rules
);
454 tz_rules
[0].name
= tz_rules
[1].name
= "UTC";
456 tz_rules
[0].type
= tz_rules
[1].type
= J0
;
457 tz_rules
[0].change
= tz_rules
[1].change
= (time_t) -1;
462 __tzset_parse_tz (tz
);
465 /* Figure out the exact time (as a time_t) in YEAR
466 when the change described by RULE will occur and
467 put it in RULE->change, saving YEAR in RULE->computed_for. */
470 compute_change (rule
, year
)
476 if (year
!= -1 && rule
->computed_for
== year
)
477 /* Operations on times in 2 BC will be slower. Oh well. */
480 /* First set T to January 1st, 0:00:00 GMT in YEAR. */
482 t
= ((year
- 1970) * 365
483 + /* Compute the number of leapdays between 1970 and YEAR
484 (exclusive). There is a leapday every 4th year ... */
485 + ((year
- 1) / 4 - 1970 / 4)
486 /* ... except every 100th year ... */
487 - ((year
- 1) / 100 - 1970 / 100)
488 /* ... but still every 400th year. */
489 + ((year
- 1) / 400 - 1970 / 400)) * SECSPERDAY
;
496 /* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap years.
497 In non-leap years, or if the day number is 59 or less, just
498 add SECSPERDAY times the day number-1 to the time of
499 January 1, midnight, to get the day. */
500 t
+= (rule
->d
- 1) * SECSPERDAY
;
501 if (rule
->d
>= 60 && __isleap (year
))
507 Just add SECSPERDAY times the day number to the time of Jan 1st. */
508 t
+= rule
->d
* SECSPERDAY
;
512 /* Mm.n.d - Nth "Dth day" of month M. */
515 int d
, m1
, yy0
, yy1
, yy2
, dow
;
516 const unsigned short int *myday
=
517 &__mon_yday
[__isleap (year
)][rule
->m
];
519 /* First add SECSPERDAY for each day in months before M. */
520 t
+= myday
[-1] * SECSPERDAY
;
522 /* Use Zeller's Congruence to get day-of-week of first day of month. */
523 m1
= (rule
->m
+ 9) % 12 + 1;
524 yy0
= (rule
->m
<= 2) ? (year
- 1) : year
;
527 dow
= ((26 * m1
- 2) / 10 + 1 + yy2
+ yy2
/ 4 + yy1
/ 4 - 2 * yy1
) % 7;
531 /* DOW is the day-of-week of the first day of the month. Get the
532 day-of-month (zero-origin) of the first DOW day of the month. */
536 for (i
= 1; i
< rule
->n
; ++i
)
538 if (d
+ 7 >= (int) myday
[0] - myday
[-1])
543 /* D is the day-of-month (zero-origin) of the day we want. */
549 /* T is now the Epoch-relative time of 0:00:00 GMT on the day we want.
550 Just add the time of day and local offset from GMT, and we're done. */
552 rule
->change
= t
- rule
->offset
+ rule
->secs
;
553 rule
->computed_for
= year
;
557 /* Figure out the correct timezone for TM and set `__tzname',
558 `__timezone', and `__daylight' accordingly. */
561 __tz_compute (timer
, tm
, use_localtime
)
566 compute_change (&tz_rules
[0], 1900 + tm
->tm_year
);
567 compute_change (&tz_rules
[1], 1900 + tm
->tm_year
);
573 /* We have to distinguish between northern and southern
574 hemisphere. For the latter the daylight saving time
575 ends in the next year. */
576 if (__builtin_expect (tz_rules
[0].change
577 > tz_rules
[1].change
, 0))
578 isdst
= (timer
< tz_rules
[1].change
579 || timer
>= tz_rules
[0].change
);
581 isdst
= (timer
>= tz_rules
[0].change
582 && timer
< tz_rules
[1].change
);
583 tm
->tm_isdst
= isdst
;
584 tm
->tm_zone
= __tzname
[isdst
];
585 tm
->tm_gmtoff
= tz_rules
[isdst
].offset
;
589 /* Reinterpret the TZ environment variable and set `tzname'. */
595 __libc_lock_lock (tzset_lock
);
597 tzset_internal (1, 1);
602 __tzname
[0] = (char *) tz_rules
[0].name
;
603 __tzname
[1] = (char *) tz_rules
[1].name
;
606 __libc_lock_unlock (tzset_lock
);
608 weak_alias (__tzset
, tzset
)
610 /* Return the `struct tm' representation of *TIMER in the local timezone.
611 Use local time if USE_LOCALTIME is nonzero, UTC otherwise. */
613 __tz_convert (const time_t *timer
, int use_localtime
, struct tm
*tp
)
615 long int leap_correction
;
620 __set_errno (EINVAL
);
624 __libc_lock_lock (tzset_lock
);
626 /* Update internal database according to current TZ setting.
627 POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
628 This is a good idea since this allows at least a bit more parallelism. */
629 tzset_internal (tp
== &_tmbuf
&& use_localtime
, 1);
632 __tzfile_compute (*timer
, use_localtime
, &leap_correction
,
633 &leap_extra_secs
, tp
);
636 if (! __offtime (timer
, 0, tp
))
639 __tz_compute (*timer
, tp
, use_localtime
);
640 leap_correction
= 0L;
653 if (__offtime (timer
, tp
->tm_gmtoff
- leap_correction
, tp
))
654 tp
->tm_sec
+= leap_extra_secs
;
659 __libc_lock_unlock (tzset_lock
);
665 libc_freeres_fn (free_mem
)
667 while (tzstring_list
!= NULL
)
669 struct tzstring_l
*old
= tzstring_list
;
671 tzstring_list
= tzstring_list
->next
;