]> git.ipfire.org Git - thirdparty/glibc.git/blame - time/tzset.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / time / tzset.c
CommitLineData
bfff8b1b 1/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
f65fd747 2 This file is part of the GNU C Library.
28f540f4 3
f65fd747 4 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
28f540f4 8
f65fd747
UD
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
41bdb6e2 12 Lesser General Public License for more details.
28f540f4 13
41bdb6e2 14 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
28f540f4 17
28f540f4 18#include <ctype.h>
9a0a462c 19#include <errno.h>
ec999b8e 20#include <libc-lock.h>
42261ad7 21#include <stdbool.h>
28f540f4
RM
22#include <stddef.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <time.h>
27
9a0a462c 28
28f540f4 29#define NOID
14ea22e9 30#include <timezone/tzfile.h>
28f540f4 31
28f540f4
RM
32char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
33int __daylight = 0;
34long int __timezone = 0L;
35
0ac2e7d8
BK
36weak_alias (__tzname, tzname)
37weak_alias (__daylight, daylight)
38weak_alias (__timezone, timezone)
39
9a0a462c 40/* This locks all the state variables in tzfile.c and this file. */
727211c4 41__libc_lock_define_initialized (static, tzset_lock)
9a0a462c 42
28f540f4
RM
43
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)
47
48
49/* This structure contains all the information about a
50 timezone given in the POSIX standard TZ envariable. */
51typedef struct
52 {
cd6ede75 53 const char *name;
28f540f4
RM
54
55 /* When to change. */
56 enum { J0, J1, M } type; /* Interpretation of: */
57 unsigned short int m, n, d; /* Month, week, day. */
0748546f 58 int secs; /* Time of day. */
28f540f4
RM
59
60 long int offset; /* Seconds east of GMT (west if < 0). */
61
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;
67
68/* tz_rules[0] is standard, tz_rules[1] is daylight. */
69static tz_rule tz_rules[2];
f65fd747
UD
70
71
79937577 72static void compute_change (tz_rule *rule, int year) __THROW internal_function;
79937577
UD
73static void tzset_internal (int always, int explicit)
74 __THROW internal_function;
28f540f4 75\f
2698e32c
UD
76/* List of buffers containing time zone strings. */
77struct tzstring_l
cd6ede75 78{
2698e32c
UD
79 struct tzstring_l *next;
80 size_t len; /* strlen(data) - doesn't count terminating NUL! */
81 char data[0];
cd6ede75
UD
82};
83
418f1701 84static struct tzstring_l *tzstring_list;
cd6ede75 85
42261ad7
FW
86/* Allocate a permanent home for the first LEN characters of S. It
87 will never be moved or deallocated, but may share space with other
88 strings. Don't modify the returned string. */
89static char *
90__tzstring_len (const char *s, size_t len)
cd6ede75 91{
cd6ede75 92 char *p;
2698e32c 93 struct tzstring_l *t, *u, *new;
2698e32c
UD
94
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)
98 if (len <= t->len)
99 {
100 p = &t->data[t->len - len];
42261ad7 101 if (memcmp (s, p, len) == 0)
cd6ede75 102 return p;
2698e32c
UD
103 }
104
105 /* Not found; allocate a new buffer. */
106 new = malloc (sizeof (struct tzstring_l) + len + 1);
107 if (!new)
108 return NULL;
109
110 new->next = NULL;
111 new->len = len;
42261ad7
FW
112 memcpy (new->data, s, len);
113 new->data[len] = '\0';
2698e32c
UD
114
115 if (u)
116 u->next = new;
117 else
118 tzstring_list = new;
119
120 return new->data;
cd6ede75 121}
42261ad7
FW
122
123/* Allocate a permanent home for S. It will never be moved or
124 deallocated, but may share space with other strings. Don't modify
125 the returned string. */
126char *
127__tzstring (const char *s)
128{
129 return __tzstring_len (s, strlen (s));
130}
cd6ede75 131\f
a3931cbe
UD
132/* Maximum length of a timezone name. tzset_internal keeps this up to date
133 (never decreasing it) when ! __use_tzfile.
134 tzfile.c keeps it up to date when __use_tzfile. */
135size_t __tzname_cur_max;
136
137long int
60d2f8f3 138__tzname_max (void)
a3931cbe
UD
139{
140 __libc_lock_lock (tzset_lock);
141
c3d1af70 142 tzset_internal (0, 0);
a3931cbe
UD
143
144 __libc_lock_unlock (tzset_lock);
145
146 return __tzname_cur_max;
147}
148\f
c4563d2d 149static char *old_tz;
28f540f4 150
9a0a462c 151static void
dfd2257a 152internal_function
fa76dde2
UD
153update_vars (void)
154{
155 __daylight = tz_rules[0].offset != tz_rules[1].offset;
156 __timezone = -tz_rules[0].offset;
157 __tzname[0] = (char *) tz_rules[0].name;
158 __tzname[1] = (char *) tz_rules[1].name;
159
160 /* Keep __tzname_cur_max up to date. */
161 size_t len0 = strlen (__tzname[0]);
162 size_t len1 = strlen (__tzname[1]);
163 if (len0 > __tzname_cur_max)
164 __tzname_cur_max = len0;
165 if (len1 > __tzname_cur_max)
166 __tzname_cur_max = len1;
167}
168
bd82a247
UD
169
170static unsigned int
171__attribute_noinline__
172compute_offset (unsigned int ss, unsigned int mm, unsigned int hh)
173{
174 return min (ss, 59) + min (mm, 59) * 60 + min (hh, 24) * 60 * 60;
175}
176
42261ad7
FW
177/* Parses the time zone name at *TZP, and writes a pointer to an
178 interned string to tz_rules[WHICHRULE].name. On success, advances
179 *TZP, and returns true. Returns false otherwise. */
180static bool
181parse_tzname (const char **tzp, int whichrule)
28f540f4 182{
42261ad7
FW
183 const char *start = *tzp;
184 const char *p = start;
185 while (('a' <= *p && *p <= 'z')
186 || ('A' <= *p && *p <= 'Z'))
187 ++p;
188 size_t len = p - start;
189 if (len < 3)
82780cbe 190 {
42261ad7
FW
191 p = *tzp;
192 if (__glibc_unlikely (*p++ != '<'))
193 return false;
194 start = p;
195 while (('a' <= *p && *p <= 'z')
196 || ('A' <= *p && *p <= 'Z')
197 || ('0' <= *p && *p <= '9')
198 || *p == '+' || *p == '-')
199 ++p;
200 len = p - start;
201 if (*p++ != '>' || len < 3)
202 return false;
82780cbe 203 }
cc8dcf96
FW
204
205 const char *name = __tzstring_len (start, len);
206 if (name == NULL)
207 return false;
208 tz_rules[whichrule].name = name;
209
42261ad7
FW
210 *tzp = p;
211 return true;
212}
28f540f4 213
42261ad7
FW
214/* Parses the time zone offset at *TZP, and writes it to
215 tz_rules[WHICHRULE].offset. Returns true if the parse was
216 successful. */
217static bool
218parse_offset (const char **tzp, int whichrule)
219{
220 const char *tz = *tzp;
221 if (whichrule == 0
222 && (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit (*tz))))
223 return false;
28f540f4 224
42261ad7 225 long sign;
28f540f4 226 if (*tz == '-' || *tz == '+')
42261ad7 227 sign = *tz++ == '-' ? 1L : -1L;
28f540f4 228 else
42261ad7
FW
229 sign = -1L;
230 *tzp = tz;
231
232 unsigned short int hh;
233 unsigned short mm = 0;
234 unsigned short ss = 0;
235 int consumed = 0;
236 if (sscanf (tz, "%hu%n:%hu%n:%hu%n",
237 &hh, &consumed, &mm, &consumed, &ss, &consumed) > 0)
238 tz_rules[whichrule].offset = sign * compute_offset (ss, mm, hh);
239 else
240 /* Nothing could be parsed. */
241 if (whichrule == 0)
242 {
243 /* Standard time defaults to offset zero. */
244 tz_rules[0].offset = 0;
245 return false;
246 }
82780cbe 247 else
42261ad7
FW
248 /* DST defaults to one hour later than standard time. */
249 tz_rules[1].offset = tz_rules[0].offset + (60 * 60);
250 *tzp = tz + consumed;
251 return true;
252}
cd6ede75 253
42261ad7
FW
254/* Parses the standard <-> DST rules at *TZP. Updates
255 tz_rule[WHICHRULE]. On success, advances *TZP and returns true.
256 Otherwise, returns false. */
257static bool
258parse_rule (const char **tzp, int whichrule)
259{
260 const char *tz = *tzp;
261 tz_rule *tzr = &tz_rules[whichrule];
fd26970f 262
42261ad7
FW
263 /* Ignore comma to support string following the incorrect
264 specification in early POSIX.1 printings. */
265 tz += *tz == ',';
fd26970f 266
42261ad7
FW
267 /* Get the date of the change. */
268 if (*tz == 'J' || isdigit (*tz))
269 {
270 char *end;
271 tzr->type = *tz == 'J' ? J1 : J0;
272 if (tzr->type == J1 && !isdigit (*++tz))
273 return false;
274 unsigned long int d = strtoul (tz, &end, 10);
275 if (end == tz || d > 365)
276 return false;
277 if (tzr->type == J1 && d == 0)
278 return false;
279 tzr->d = d;
280 tz = end;
281 }
282 else if (*tz == 'M')
283 {
284 tzr->type = M;
285 int consumed;
286 if (sscanf (tz, "M%hu.%hu.%hu%n",
287 &tzr->m, &tzr->n, &tzr->d, &consumed) != 3
288 || tzr->m < 1 || tzr->m > 12
289 || tzr->n < 1 || tzr->n > 5 || tzr->d > 6)
290 return false;
291 tz += consumed;
292 }
293 else if (*tz == '\0')
294 {
295 /* Daylight time rules in the U.S. are defined in the U.S. Code,
296 Title 15, Chapter 6, Subchapter IX - Standard Time. These
297 dates were established by Congress in the Energy Policy Act
298 of 2005 [Pub. L. no. 109-58, 119 Stat 594 (2005)].
299 Below is the equivalent of "M3.2.0,M11.1.0" [/2 not needed
300 since 2:00AM is the default]. */
301 tzr->type = M;
302 if (tzr == &tz_rules[0])
fd26970f 303 {
42261ad7
FW
304 tzr->m = 3;
305 tzr->n = 2;
306 tzr->d = 0;
fd26970f 307 }
42261ad7 308 else
0413b54c 309 {
42261ad7
FW
310 tzr->m = 11;
311 tzr->n = 1;
312 tzr->d = 0;
0413b54c 313 }
28f540f4 314 }
5290baf0 315 else
42261ad7
FW
316 return false;
317
318 if (*tz != '\0' && *tz != '/' && *tz != ',')
319 return false;
320 else if (*tz == '/')
40a55d20 321 {
42261ad7
FW
322 /* Get the time of day of the change. */
323 int negative;
324 ++tz;
325 if (*tz == '\0')
326 return false;
327 negative = *tz == '-';
328 tz += negative;
329 /* Default to 2:00 AM. */
330 unsigned short hh = 2;
331 unsigned short mm = 0;
332 unsigned short ss = 0;
333 int consumed = 0;
334 sscanf (tz, "%hu%n:%hu%n:%hu%n",
335 &hh, &consumed, &mm, &consumed, &ss, &consumed);;
336 tz += consumed;
337 tzr->secs = (negative ? -1 : 1) * ((hh * 60 * 60) + (mm * 60) + ss);
40a55d20 338 }
42261ad7
FW
339 else
340 /* Default to 2:00 AM. */
341 tzr->secs = 2 * 60 * 60;
28f540f4 342
42261ad7
FW
343 tzr->computed_for = -1;
344 *tzp = tz;
345 return true;
346}
1cbca0d9 347
42261ad7
FW
348/* Parse the POSIX TZ-style string. */
349void
350__tzset_parse_tz (const char *tz)
351{
352 /* Clear out old state and reset to unnamed UTC. */
353 memset (tz_rules, '\0', sizeof tz_rules);
354 tz_rules[0].name = tz_rules[1].name = "";
1cbca0d9 355
42261ad7
FW
356 /* Get the standard timezone name. */
357 if (parse_tzname (&tz, 0) && parse_offset (&tz, 0))
358 {
359 /* Get the DST timezone name (if any). */
360 if (*tz != '\0')
28f540f4 361 {
42261ad7 362 if (parse_tzname (&tz, 1))
28f540f4 363 {
42261ad7
FW
364 parse_offset (&tz, 1);
365 if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0'))
366 {
367 /* There is no rule. See if there is a default rule
368 file. */
369 __tzfile_default (tz_rules[0].name, tz_rules[1].name,
370 tz_rules[0].offset, tz_rules[1].offset);
371 if (__use_tzfile)
372 {
373 free (old_tz);
374 old_tz = NULL;
375 return;
376 }
377 }
28f540f4 378 }
42261ad7
FW
379 /* Figure out the standard <-> DST rules. */
380 if (parse_rule (&tz, 0))
381 parse_rule (&tz, 1);
28f540f4
RM
382 }
383 else
28f540f4 384 {
42261ad7
FW
385 /* There is no DST. */
386 tz_rules[1].name = tz_rules[0].name;
387 tz_rules[1].offset = tz_rules[0].offset;
28f540f4 388 }
28f540f4 389 }
90865aa8 390
fa76dde2
UD
391 update_vars ();
392}
28f540f4 393
fa76dde2
UD
394/* Interpret the TZ envariable. */
395static void
396internal_function
9d46370c 397tzset_internal (int always, int explicit)
fa76dde2
UD
398{
399 static int is_initialized;
2e09a79a 400 const char *tz;
fa76dde2
UD
401
402 if (is_initialized && !always)
403 return;
404 is_initialized = 1;
405
406 /* Examine the TZ environment variable. */
407 tz = getenv ("TZ");
408 if (tz == NULL && !explicit)
409 /* Use the site-wide default. This is a file name which means we
410 would not see changes to the file if we compare only the file
411 name for change. We want to notice file changes if tzset() has
412 been called explicitly. Leave TZ as NULL in this case. */
413 tz = TZDEFAULT;
414 if (tz && *tz == '\0')
415 /* User specified the empty string; use UTC explicitly. */
416 tz = "Universal";
417
418 /* A leading colon means "implementation defined syntax".
419 We ignore the colon and always use the same algorithm:
420 try a data file, and if none exists parse the 1003.1 syntax. */
421 if (tz && *tz == ':')
422 ++tz;
423
58423c7d 424 /* Check whether the value changed since the last run. */
fa76dde2
UD
425 if (old_tz != NULL && tz != NULL && strcmp (tz, old_tz) == 0)
426 /* No change, simply return. */
427 return;
428
429 if (tz == NULL)
430 /* No user specification; use the site-wide default. */
431 tz = TZDEFAULT;
432
433 tz_rules[0].name = NULL;
434 tz_rules[1].name = NULL;
435
436 /* Save the value of `tz'. */
72e6cdfa 437 free (old_tz);
fa76dde2
UD
438 old_tz = tz ? __strdup (tz) : NULL;
439
440 /* Try to read a data file. */
441 __tzfile_read (tz, 0, NULL);
442 if (__use_tzfile)
443 return;
444
445 /* No data file found. Default to UTC if nothing specified. */
446
447 if (tz == NULL || *tz == '\0'
448 || (TZDEFAULT != NULL && strcmp (tz, TZDEFAULT) == 0))
449 {
bd82a247 450 memset (tz_rules, '\0', sizeof tz_rules);
fa76dde2 451 tz_rules[0].name = tz_rules[1].name = "UTC";
bd82a247
UD
452 if (J0 != 0)
453 tz_rules[0].type = tz_rules[1].type = J0;
fa76dde2 454 tz_rules[0].change = tz_rules[1].change = (time_t) -1;
fa76dde2
UD
455 update_vars ();
456 return;
457 }
458
459 __tzset_parse_tz (tz);
28f540f4
RM
460}
461\f
462/* Figure out the exact time (as a time_t) in YEAR
463 when the change described by RULE will occur and
a3931cbe
UD
464 put it in RULE->change, saving YEAR in RULE->computed_for. */
465static void
dfd2257a 466internal_function
9d46370c 467compute_change (tz_rule *rule, int year)
28f540f4 468{
2e09a79a 469 time_t t;
28f540f4
RM
470
471 if (year != -1 && rule->computed_for == year)
7fcc87f4 472 /* Operations on times in 2 BC will be slower. Oh well. */
a3931cbe 473 return;
1cbca0d9 474
28f540f4 475 /* First set T to January 1st, 0:00:00 GMT in YEAR. */
7fcc87f4
UD
476 if (year > 1970)
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;
485 else
486 t = 0;
28f540f4
RM
487
488 switch (rule->type)
489 {
490 case J1:
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))
497 t += SECSPERDAY;
498 break;
499
500 case J0:
501 /* n - Day of year.
502 Just add SECSPERDAY times the day number to the time of Jan 1st. */
503 t += rule->d * SECSPERDAY;
504 break;
505
506 case M:
507 /* Mm.n.d - Nth "Dth day" of month M. */
508 {
9a0a462c
UD
509 unsigned int i;
510 int d, m1, yy0, yy1, yy2, dow;
511 const unsigned short int *myday =
80fd7387 512 &__mon_yday[__isleap (year)][rule->m];
28f540f4
RM
513
514 /* First add SECSPERDAY for each day in months before M. */
80fd7387 515 t += myday[-1] * SECSPERDAY;
28f540f4
RM
516
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;
520 yy1 = yy0 / 100;
521 yy2 = yy0 % 100;
522 dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
523 if (dow < 0)
524 dow += 7;
525
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. */
528 d = rule->d - dow;
529 if (d < 0)
530 d += 7;
531 for (i = 1; i < rule->n; ++i)
532 {
9a0a462c 533 if (d + 7 >= (int) myday[0] - myday[-1])
28f540f4
RM
534 break;
535 d += 7;
536 }
537
538 /* D is the day-of-month (zero-origin) of the day we want. */
539 t += d * SECSPERDAY;
540 }
541 break;
542 }
543
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. */
546
68dbb3a6 547 rule->change = t - rule->offset + rule->secs;
28f540f4 548 rule->computed_for = year;
28f540f4
RM
549}
550
551
e3e35cfc 552/* Figure out the correct timezone for TM and set `__tzname',
a3931cbe 553 `__timezone', and `__daylight' accordingly. */
fa76dde2 554void
dfd2257a 555internal_function
9d46370c 556__tz_compute (time_t timer, struct tm *tm, int use_localtime)
28f540f4 557{
a3931cbe
UD
558 compute_change (&tz_rules[0], 1900 + tm->tm_year);
559 compute_change (&tz_rules[1], 1900 + tm->tm_year);
fa76dde2
UD
560
561 if (use_localtime)
562 {
563 int isdst;
564
565 /* We have to distinguish between northern and southern
566 hemisphere. For the latter the daylight saving time
567 ends in the next year. */
568 if (__builtin_expect (tz_rules[0].change
569 > tz_rules[1].change, 0))
570 isdst = (timer < tz_rules[1].change
571 || timer >= tz_rules[0].change);
572 else
573 isdst = (timer >= tz_rules[0].change
574 && timer < tz_rules[1].change);
575 tm->tm_isdst = isdst;
576 tm->tm_zone = __tzname[isdst];
577 tm->tm_gmtoff = tz_rules[isdst].offset;
578 }
28f540f4 579}
b24be05f 580\f
b24be05f 581/* Reinterpret the TZ environment variable and set `tzname'. */
4311b2a6 582#undef tzset
28f540f4 583
b24be05f 584void
10dc2a90 585__tzset (void)
b24be05f 586{
9a0a462c 587 __libc_lock_lock (tzset_lock);
68dbb3a6 588
c3d1af70 589 tzset_internal (1, 1);
68dbb3a6 590
860d3729
UD
591 if (!__use_tzfile)
592 {
593 /* Set `tzname'. */
594 __tzname[0] = (char *) tz_rules[0].name;
595 __tzname[1] = (char *) tz_rules[1].name;
596 }
68dbb3a6 597
9a0a462c 598 __libc_lock_unlock (tzset_lock);
b24be05f 599}
10dc2a90 600weak_alias (__tzset, tzset)
9a0a462c
UD
601\f
602/* Return the `struct tm' representation of *TIMER in the local timezone.
603 Use local time if USE_LOCALTIME is nonzero, UTC otherwise. */
604struct tm *
605__tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
606{
607 long int leap_correction;
608 int leap_extra_secs;
609
610 if (timer == NULL)
611 {
612 __set_errno (EINVAL);
613 return NULL;
614 }
615
616 __libc_lock_lock (tzset_lock);
617
618 /* Update internal database according to current TZ setting.
619 POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
58423c7d
UD
620 This is a good idea since this allows at least a bit more parallelism. */
621 tzset_internal (tp == &_tmbuf && use_localtime, 1);
9a0a462c
UD
622
623 if (__use_tzfile)
38e68573
UD
624 __tzfile_compute (*timer, use_localtime, &leap_correction,
625 &leap_extra_secs, tp);
9a0a462c
UD
626 else
627 {
a3931cbe 628 if (! __offtime (timer, 0, tp))
9a0a462c 629 tp = NULL;
a3931cbe 630 else
fa76dde2 631 __tz_compute (*timer, tp, use_localtime);
9a0a462c
UD
632 leap_correction = 0L;
633 leap_extra_secs = 0;
634 }
635
6807b1db
KE
636 __libc_lock_unlock (tzset_lock);
637
9a0a462c
UD
638 if (tp)
639 {
fa76dde2 640 if (! use_localtime)
9a0a462c
UD
641 {
642 tp->tm_isdst = 0;
643 tp->tm_zone = "GMT";
644 tp->tm_gmtoff = 0L;
645 }
646
fe0ec73e
UD
647 if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp))
648 tp->tm_sec += leap_extra_secs;
649 else
650 tp = NULL;
9a0a462c
UD
651 }
652
9a0a462c
UD
653 return tp;
654}
83628d31
UD
655
656
c877418f 657libc_freeres_fn (free_mem)
83628d31
UD
658{
659 while (tzstring_list != NULL)
660 {
661 struct tzstring_l *old = tzstring_list;
662
663 tzstring_list = tzstring_list->next;
664 free (old);
665 }
666 free (old_tz);
667 old_tz = NULL;
668}