]> git.ipfire.org Git - thirdparty/glibc.git/blame - time/mktime.c
* time/mktime.c: Update obsolete URL in comment.
[thirdparty/glibc.git] / time / mktime.c
CommitLineData
6226efbd 1/* Convert a 'struct tm' to a time_t value.
04277e02 2 Copyright (C) 1993-2019 Free Software Foundation, Inc.
5290baf0 3 This file is part of the GNU C Library.
41aba3d7 4 Contributed by Paul Eggert <eggert@twinsun.com>.
28f540f4 5
5290baf0 6 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
28f540f4 10
5290baf0
UD
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 14 Lesser General Public License for more details.
28f540f4 15
41bdb6e2 16 You should have received a copy of the GNU Lesser General Public
59ba27a6 17 License along with the GNU C Library; if not, see
8e6fd2bd 18 <https://www.gnu.org/licenses/>. */
28f540f4 19
8e6fd2bd
PE
20/* The following macros influence what gets defined when this file is compiled:
21
22 Macro/expression Which gnulib module This compilation unit
23 should define
24
25 _LIBC (glibc proper) mktime
26
27 NEED_MKTIME_WORKING mktime rpl_mktime
28 || NEED_MKTIME_WINDOWS
29
30 NEED_MKTIME_INTERNAL mktime-internal mktime_internal
8e6fd2bd
PE
31 */
32
5d8af156 33#ifndef _LIBC
de20b81a 34# include <libc-config.h>
28f540f4
RM
35#endif
36
80fd7387 37/* Assume that leap seconds are possible, unless told otherwise.
6226efbd 38 If the host has a 'zic' command with a '-L leapsecondfilename' option,
80fd7387
RM
39 then it supports leap seconds; otherwise it probably doesn't. */
40#ifndef LEAP_SECONDS_POSSIBLE
9c2322bc 41# define LEAP_SECONDS_POSSIBLE 1
80fd7387
RM
42#endif
43
28f540f4
RM
44#include <time.h>
45
de20b81a 46#include <errno.h>
85e07670 47#include <limits.h>
8e6fd2bd
PE
48#include <stdbool.h>
49#include <stdlib.h>
50#include <string.h>
28f540f4 51
8e6fd2bd
PE
52#include <intprops.h>
53#include <verify.h>
9b5204dd 54
8e6fd2bd
PE
55#ifndef NEED_MKTIME_INTERNAL
56# define NEED_MKTIME_INTERNAL 0
57#endif
58#ifndef NEED_MKTIME_WINDOWS
59# define NEED_MKTIME_WINDOWS 0
60#endif
61#ifndef NEED_MKTIME_WORKING
5d8af156 62# define NEED_MKTIME_WORKING 0
8e6fd2bd
PE
63#endif
64
65#include "mktime-internal.h"
66
5a580643 67#if !defined _LIBC && (NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS)
8e6fd2bd
PE
68static void
69my_tzset (void)
70{
71# if NEED_MKTIME_WINDOWS
72 /* Rectify the value of the environment variable TZ.
73 There are four possible kinds of such values:
74 - Traditional US time zone names, e.g. "PST8PDT". Syntax: see
78919d38 75 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/tzset>
8e6fd2bd
PE
76 - Time zone names based on geography, that contain one or more
77 slashes, e.g. "Europe/Moscow".
78 - Time zone names based on geography, without slashes, e.g.
79 "Singapore".
80 - Time zone names that contain explicit DST rules. Syntax: see
81 <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03>
82 The Microsoft CRT understands only the first kind. It produces incorrect
83 results if the value of TZ is of the other kinds.
84 But in a Cygwin environment, /etc/profile.d/tzset.sh sets TZ to a value
85 of the second kind for most geographies, or of the first kind in a few
86 other geographies. If it is of the second kind, neutralize it. For the
87 Microsoft CRT, an absent or empty TZ means the time zone that the user
88 has set in the Windows Control Panel.
89 If the value of TZ is of the third or fourth kind -- Cygwin programs
90 understand these syntaxes as well --, it does not matter whether we
91 neutralize it or not, since these values occur only when a Cygwin user
92 has set TZ explicitly; this case is 1. rare and 2. under the user's
93 responsibility. */
94 const char *tz = getenv ("TZ");
95 if (tz != NULL && strchr (tz, '/') != NULL)
96 _putenv ("TZ=");
97# elif HAVE_TZSET
98 tzset ();
62bdf9a6 99# endif
8e6fd2bd
PE
100}
101# undef __tzset
102# define __tzset() my_tzset ()
62bdf9a6
PE
103#endif
104
8e6fd2bd
PE
105#if defined _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL
106
107/* A signed type that can represent an integer number of years
efbdddc3 108 multiplied by four times the number of seconds in a year. It is
8e6fd2bd 109 needed when converting a tm_year value times the number of seconds
efbdddc3 110 in a year. The factor of four comes because these products need
8e6fd2bd 111 to be subtracted from each other, and sometimes with an offset
efbdddc3
PE
112 added to them, and then with another timestamp added, without
113 worrying about overflow.
8e6fd2bd
PE
114
115 Much of the code uses long_int to represent time_t values, to
116 lessen the hassle of dealing with platforms where time_t is
117 unsigned, and because long_int should suffice to represent all
118 time_t values that mktime can generate even on platforms where
119 time_t is excessively wide. */
f04dfbc2 120
efbdddc3 121#if INT_MAX <= LONG_MAX / 4 / 366 / 24 / 60 / 60
f04dfbc2
PE
122typedef long int long_int;
123#else
124typedef long long int long_int;
125#endif
efbdddc3 126verify (INT_MAX <= TYPE_MAXIMUM (long_int) / 4 / 366 / 24 / 60 / 60);
f04dfbc2 127
1c67fabd 128/* Shift A right by B bits portably, by dividing A by 2**B and
8e6fd2bd
PE
129 truncating towards minus infinity. B should be in the range 0 <= B
130 <= LONG_INT_BITS - 2, where LONG_INT_BITS is the number of useful
131 bits in a long_int. LONG_INT_BITS is at least 32.
1c67fabd
RM
132
133 ISO C99 says that A >> B is implementation-defined if A < 0. Some
134 implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
135 right in the usual way when A < 0, so SHR falls back on division if
136 ordinary A >> B doesn't seem to be the usual signed shift. */
28f540f4 137
8e6fd2bd
PE
138static long_int
139shr (long_int a, int b)
140{
141 long_int one = 1;
142 return (-one >> 1 == -1
143 ? a >> b
144 : a / (one << b) - (a % (one << b) < 0));
145}
146
147/* Bounds for the intersection of time_t and long_int. */
148
149static long_int const mktime_min
150 = ((TYPE_SIGNED (time_t) && TYPE_MINIMUM (time_t) < TYPE_MINIMUM (long_int))
151 ? TYPE_MINIMUM (long_int) : TYPE_MINIMUM (time_t));
152static long_int const mktime_max
153 = (TYPE_MAXIMUM (long_int) < TYPE_MAXIMUM (time_t)
154 ? TYPE_MAXIMUM (long_int) : TYPE_MAXIMUM (time_t));
155
156verify (TYPE_IS_INTEGER (time_t));
a28a0500 157
80fd7387 158#define EPOCH_YEAR 1970
a28a0500 159#define TM_YEAR_BASE 1900
8e6fd2bd 160verify (TM_YEAR_BASE % 100 == 0);
28f540f4 161
8e6fd2bd
PE
162/* Is YEAR + TM_YEAR_BASE a leap year? */
163static bool
f04dfbc2 164leapyear (long_int year)
72035294
RM
165{
166 /* Don't add YEAR to TM_YEAR_BASE, as that might overflow.
167 Also, work even if YEAR is negative. */
168 return
169 ((year & 3) == 0
170 && (year % 100 != 0
171 || ((year / 100) & 3) == (- (TM_YEAR_BASE / 100) & 3)));
172}
28f540f4 173
80fd7387 174/* How many days come before each month (0-12). */
8592ae92
UD
175#ifndef _LIBC
176static
177#endif
80fd7387
RM
178const unsigned short int __mon_yday[2][13] =
179 {
180 /* Normal years. */
181 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
182 /* Leap years. */
183 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
184 };
28f540f4 185
28f540f4 186
8e6fd2bd
PE
187/* Do the values A and B differ according to the rules for tm_isdst?
188 A and B differ if one is zero and the other positive. */
189static bool
ce73d683
PE
190isdst_differ (int a, int b)
191{
192 return (!a != !b) && (0 <= a) && (0 <= b);
193}
194
e507cc56
RM
195/* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -
196 (YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks
8e6fd2bd 197 were not adjusted between the timestamps.
80fd7387 198
e507cc56 199 The YEAR values uses the same numbering as TP->tm_year. Values
efbdddc3
PE
200 need not be in the usual range. However, YEAR1 - YEAR0 must not
201 overflow even when multiplied by three times the number of seconds
202 in a year, and likewise for YDAY1 - YDAY0 and three times the
203 number of seconds in a day. */
e507cc56 204
8e6fd2bd 205static long_int
f04dfbc2 206ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1,
e507cc56
RM
207 int year0, int yday0, int hour0, int min0, int sec0)
208{
8e6fd2bd 209 verify (-1 / 2 == 0);
e507cc56
RM
210
211 /* Compute intervening leap days correctly even if year is negative.
212 Take care to avoid integer overflow here. */
8e6fd2bd
PE
213 int a4 = shr (year1, 2) + shr (TM_YEAR_BASE, 2) - ! (year1 & 3);
214 int b4 = shr (year0, 2) + shr (TM_YEAR_BASE, 2) - ! (year0 & 3);
e507cc56
RM
215 int a100 = a4 / 25 - (a4 % 25 < 0);
216 int b100 = b4 / 25 - (b4 % 25 < 0);
8e6fd2bd
PE
217 int a400 = shr (a100, 2);
218 int b400 = shr (b100, 2);
e507cc56
RM
219 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
220
8e6fd2bd
PE
221 /* Compute the desired time without overflowing. */
222 long_int years = year1 - year0;
223 long_int days = 365 * years + yday1 - yday0 + intervening_leap_days;
224 long_int hours = 24 * days + hour1 - hour0;
225 long_int minutes = 60 * hours + min1 - min0;
226 long_int seconds = 60 * minutes + sec1 - sec0;
e507cc56
RM
227 return seconds;
228}
229
8e6fd2bd
PE
230/* Return the average of A and B, even if A + B would overflow.
231 Round toward positive infinity. */
232static long_int
233long_int_avg (long_int a, long_int b)
62bdf9a6 234{
8e6fd2bd 235 return shr (a, 1) + shr (b, 1) + ((a | b) & 1);
62bdf9a6 236}
e507cc56 237
86aece3b
PE
238/* Return a long_int value corresponding to (YEAR-YDAY HOUR:MIN:SEC)
239 minus *TP seconds, assuming no clock adjustments occurred between
240 the two timestamps.
241
8e6fd2bd
PE
242 YEAR and YDAY must not be so large that multiplying them by three times the
243 number of seconds in a year (or day, respectively) would overflow long_int.
86aece3b 244 *TP should be in the usual range. */
8e6fd2bd 245static long_int
86aece3b
PE
246tm_diff (long_int year, long_int yday, int hour, int min, int sec,
247 struct tm const *tp)
80fd7387 248{
86aece3b
PE
249 return ydhms_diff (year, yday, hour, min, sec,
250 tp->tm_year, tp->tm_yday,
251 tp->tm_hour, tp->tm_min, tp->tm_sec);
8e6fd2bd
PE
252}
253
254/* Use CONVERT to convert T to a struct tm value in *TM. T must be in
86aece3b
PE
255 range for time_t. Return TM if successful, NULL (setting errno) on
256 failure. */
8e6fd2bd
PE
257static struct tm *
258convert_time (struct tm *(*convert) (const time_t *, struct tm *),
259 long_int t, struct tm *tm)
260{
261 time_t x = t;
262 return convert (&x, tm);
80fd7387
RM
263}
264
fe0ec73e
UD
265/* Use CONVERT to convert *T to a broken down time in *TP.
266 If *T is out of range for conversion, adjust it so that
8e6fd2bd 267 it is the nearest in-range value and then convert that.
86aece3b
PE
268 A value is in range if it fits in both time_t and long_int.
269 Return TP on success, NULL (setting errno) on failure. */
fe0ec73e 270static struct tm *
eda78eec 271ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
8e6fd2bd 272 long_int *t, struct tm *tp)
fe0ec73e 273{
86aece3b
PE
274 long_int t1 = (*t < mktime_min ? mktime_min
275 : *t <= mktime_max ? *t : mktime_max);
276 struct tm *r = convert_time (convert, t1, tp);
277 if (r)
fe0ec73e 278 {
86aece3b
PE
279 *t = t1;
280 return r;
281 }
282 if (errno != EOVERFLOW)
283 return NULL;
fe0ec73e 284
86aece3b
PE
285 long_int bad = t1;
286 long_int ok = 0;
287 struct tm oktm; oktm.tm_sec = -1;
f6b3331b 288
86aece3b
PE
289 /* BAD is a known out-of-range value, and OK is a known in-range one.
290 Use binary search to narrow the range between BAD and OK until
291 they differ by 1. */
292 while (true)
293 {
294 long_int mid = long_int_avg (ok, bad);
295 if (mid == ok || mid == bad)
296 break;
297 if (convert_time (convert, mid, tp))
298 ok = mid, oktm = *tp;
299 else if (errno != EOVERFLOW)
300 return NULL;
301 else
302 bad = mid;
fe0ec73e
UD
303 }
304
86aece3b
PE
305 if (oktm.tm_sec < 0)
306 return NULL;
307 *t = ok;
308 *tp = oktm;
309 return tp;
fe0ec73e
UD
310}
311
312
80fd7387
RM
313/* Convert *TP to a time_t value, inverting
314 the monotonic and mostly-unit-linear conversion function CONVERT.
315 Use *OFFSET to keep track of a guess at the offset of the result,
316 compared to what the result would be for UTC without leap seconds.
e507cc56 317 If *OFFSET's guess is correct, only one CONVERT call is needed.
de20b81a
PE
318 If successful, set *TP to the canonicalized struct tm;
319 otherwise leave *TP alone, return ((time_t) -1) and set errno.
e507cc56 320 This function is external because it is used also by timegm.c. */
80fd7387 321time_t
eda78eec
UD
322__mktime_internal (struct tm *tp,
323 struct tm *(*convert) (const time_t *, struct tm *),
8e6fd2bd 324 mktime_offset_t *offset)
28f540f4 325{
80fd7387
RM
326 struct tm tm;
327
328 /* The maximum number of probes (calls to CONVERT) should be enough
329 to handle any combinations of time zone rule changes, solar time,
25b3b17b
UD
330 leap seconds, and oscillations around a spring-forward gap.
331 POSIX.1 prohibits leap seconds, but some hosts have them anyway. */
332 int remaining_probes = 6;
80fd7387
RM
333
334 /* Time requested. Copy it in case CONVERT modifies *TP; this can
335 occur if TP is localtime's returned value and CONVERT is localtime. */
336 int sec = tp->tm_sec;
337 int min = tp->tm_min;
338 int hour = tp->tm_hour;
339 int mday = tp->tm_mday;
340 int mon = tp->tm_mon;
341 int year_requested = tp->tm_year;
ce73d683 342 int isdst = tp->tm_isdst;
80fd7387 343
b5ef404e 344 /* 1 if the previous probe was DST. */
86aece3b 345 int dst2 = 0;
b5ef404e 346
80fd7387
RM
347 /* Ensure that mon is in range, and set year accordingly. */
348 int mon_remainder = mon % 12;
349 int negative_mon_remainder = mon_remainder < 0;
350 int mon_years = mon / 12 - negative_mon_remainder;
f04dfbc2
PE
351 long_int lyear_requested = year_requested;
352 long_int year = lyear_requested + mon_years;
80fd7387 353
8592ae92 354 /* The other values need not be in range:
8e6fd2bd 355 the remaining code handles overflows correctly. */
80fd7387
RM
356
357 /* Calculate day of year from year, month, and day of month.
358 The result need not be in range. */
e507cc56
RM
359 int mon_yday = ((__mon_yday[leapyear (year)]
360 [mon_remainder + 12 * negative_mon_remainder])
361 - 1);
f04dfbc2
PE
362 long_int lmday = mday;
363 long_int yday = mon_yday + lmday;
e507cc56 364
8e6fd2bd
PE
365 mktime_offset_t off = *offset;
366 int negative_offset_guess;
80fd7387 367
9a0a462c 368 int sec_requested = sec;
55544141 369
e507cc56
RM
370 if (LEAP_SECONDS_POSSIBLE)
371 {
372 /* Handle out-of-range seconds specially,
efbdddc3 373 since ydhms_diff assumes every minute has 60 seconds. */
e507cc56
RM
374 if (sec < 0)
375 sec = 0;
376 if (59 < sec)
377 sec = 59;
378 }
379
380 /* Invert CONVERT by probing. First assume the same offset as last
381 time. */
382
8e6fd2bd 383 INT_SUBTRACT_WRAPV (0, off, &negative_offset_guess);
86aece3b
PE
384 long_int t0 = ydhms_diff (year, yday, hour, min, sec,
385 EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0,
386 negative_offset_guess);
387 long_int t = t0, t1 = t0, t2 = t0;
80fd7387 388
e507cc56 389 /* Repeatedly use the error to improve the guess. */
28f540f4 390
86aece3b
PE
391 while (true)
392 {
393 if (! ranged_convert (convert, &t, &tm))
de20b81a 394 return -1;
86aece3b
PE
395 long_int dt = tm_diff (year, yday, hour, min, sec, &tm);
396 if (dt == 0)
397 break;
398
399 if (t == t1 && t != t2
400 && (tm.tm_isdst < 0
401 || (isdst < 0
402 ? dst2 <= (tm.tm_isdst != 0)
403 : (isdst != 0) != (tm.tm_isdst != 0))))
404 /* We can't possibly find a match, as we are oscillating
405 between two values. The requested time probably falls
406 within a spring-forward gap of size DT. Follow the common
407 practice in this case, which is to return a time that is DT
408 away from the requested time, preferring a time whose
409 tm_isdst differs from the requested value. (If no tm_isdst
410 was requested and only one of the two values has a nonzero
411 tm_isdst, prefer that value.) In practice, this is more
412 useful than returning -1. */
413 goto offset_found;
414
415 remaining_probes--;
416 if (remaining_probes == 0)
417 {
418 __set_errno (EOVERFLOW);
419 return -1;
420 }
421
422 t1 = t2, t2 = t, t += dt, dst2 = tm.tm_isdst != 0;
423 }
80fd7387 424
e507cc56 425 /* We have a match. Check whether tm.tm_isdst has the requested
25b3b17b 426 value, if any. */
ce73d683 427 if (isdst_differ (isdst, tm.tm_isdst))
80fd7387 428 {
c0016081
UD
429 /* tm.tm_isdst has the wrong value. Look for a neighboring
430 time with the right value, and use its UTC offset.
c0016081 431
e507cc56
RM
432 Heuristic: probe the adjacent timestamps in both directions,
433 looking for the desired isdst. This should work for all real
434 time zone histories in the tz database. */
435
436 /* Distance between probes when looking for a DST boundary. In
437 tzdata2003a, the shortest period of DST is 601200 seconds
438 (e.g., America/Recife starting 2000-10-08 01:00), and the
439 shortest period of non-DST surrounded by DST is 694800
440 seconds (Africa/Tunis starting 1943-04-17 01:00). Use the
441 minimum of these two values, so we don't miss these short
442 periods when probing. */
443 int stride = 601200;
444
445 /* The longest period of DST in tzdata2003a is 536454000 seconds
446 (e.g., America/Jujuy starting 1946-10-01 01:00). The longest
447 period of non-DST is much longer, but it makes no real sense
448 to search for more than a year of non-DST, so use the DST
449 max. */
450 int duration_max = 536454000;
451
452 /* Search in both directions, so the maximum distance is half
453 the duration; add the stride to avoid off-by-1 problems. */
454 int delta_bound = duration_max / 2 + stride;
455
456 int delta, direction;
457
458 for (delta = stride; delta < delta_bound; delta += stride)
459 for (direction = -1; direction <= 1; direction += 2)
8e6fd2bd
PE
460 {
461 long_int ot;
462 if (! INT_ADD_WRAPV (t, delta * direction, &ot))
463 {
464 struct tm otm;
86aece3b
PE
465 if (! ranged_convert (convert, &ot, &otm))
466 return -1;
8e6fd2bd
PE
467 if (! isdst_differ (isdst, otm.tm_isdst))
468 {
469 /* We found the desired tm_isdst.
470 Extrapolate back to the desired time. */
86aece3b
PE
471 long_int gt = ot + tm_diff (year, yday, hour, min, sec,
472 &otm);
473 if (mktime_min <= gt && gt <= mktime_max)
474 {
475 if (convert_time (convert, gt, &tm))
476 {
477 t = gt;
478 goto offset_found;
479 }
480 if (errno != EOVERFLOW)
481 return -1;
482 }
8e6fd2bd
PE
483 }
484 }
485 }
86aece3b
PE
486
487 __set_errno (EOVERFLOW);
488 return -1;
80fd7387 489 }
28f540f4 490
e507cc56 491 offset_found:
8e6fd2bd
PE
492 /* Set *OFFSET to the low-order bits of T - T0 - NEGATIVE_OFFSET_GUESS.
493 This is just a heuristic to speed up the next mktime call, and
494 correctness is unaffected if integer overflow occurs here. */
6c90d759
PE
495 INT_SUBTRACT_WRAPV (t, t0, offset);
496 INT_SUBTRACT_WRAPV (*offset, negative_offset_guess, offset);
80fd7387 497
e507cc56 498 if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec)
80fd7387
RM
499 {
500 /* Adjust time to reflect the tm_sec requested, not the normalized value.
501 Also, repair any damage from a false match due to a leap second. */
8e6fd2bd
PE
502 long_int sec_adjustment = sec == 0 && tm.tm_sec == 60;
503 sec_adjustment -= sec;
504 sec_adjustment += sec_requested;
505 if (INT_ADD_WRAPV (t, sec_adjustment, &t)
de20b81a
PE
506 || ! (mktime_min <= t && t <= mktime_max))
507 {
508 __set_errno (EOVERFLOW);
509 return -1;
510 }
511 if (! convert_time (convert, t, &tm))
78575a84
UD
512 return -1;
513 }
514
80fd7387
RM
515 *tp = tm;
516 return t;
517}
518
8e6fd2bd 519#endif /* _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL */
eda78eec 520
8e6fd2bd 521#if defined _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS
eda78eec
UD
522
523/* Convert *TP to a time_t value. */
524time_t
85e07670 525mktime (struct tm *tp)
eda78eec 526{
eda78eec 527 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
6226efbd 528 time zone names contained in the external variable 'tzname' shall
eda78eec
UD
529 be set as if the tzset() function had been called. */
530 __tzset ();
eda78eec 531
8e6fd2bd
PE
532# if defined _LIBC || NEED_MKTIME_WORKING
533 static mktime_offset_t localtime_offset;
7683e140 534 return __mktime_internal (tp, __localtime_r, &localtime_offset);
8e6fd2bd
PE
535# else
536# undef mktime
537 return mktime (tp);
538# endif
eda78eec 539}
8e6fd2bd 540#endif /* _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS */
eda78eec 541
80fd7387
RM
542#ifdef weak_alias
543weak_alias (mktime, timelocal)
28f540f4 544#endif
c5598d47
RM
545
546#ifdef _LIBC
547libc_hidden_def (mktime)
548libc_hidden_weak (timelocal)
549#endif