]> git.ipfire.org Git - thirdparty/glibc.git/blame - time/mktime.c
mktime: fix EOVERFLOW bug
[thirdparty/glibc.git] / time / mktime.c
CommitLineData
6226efbd 1/* Convert a 'struct tm' to a time_t value.
688903eb 2 Copyright (C) 1993-2018 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 20/* Define this to 1 to have a standalone program to test this implementation of
28f540f4 21 mktime. */
8e6fd2bd
PE
22#ifndef DEBUG_MKTIME
23# define DEBUG_MKTIME 0
24#endif
28f540f4 25
8e6fd2bd
PE
26/* The following macros influence what gets defined when this file is compiled:
27
28 Macro/expression Which gnulib module This compilation unit
29 should define
30
31 _LIBC (glibc proper) mktime
32
33 NEED_MKTIME_WORKING mktime rpl_mktime
34 || NEED_MKTIME_WINDOWS
35
36 NEED_MKTIME_INTERNAL mktime-internal mktime_internal
37
38 DEBUG_MKTIME (defined manually) my_mktime, main
39 */
40
41#if !defined _LIBC && !DEBUG_MKTIME
de20b81a 42# include <libc-config.h>
28f540f4
RM
43#endif
44
80fd7387 45/* Assume that leap seconds are possible, unless told otherwise.
6226efbd 46 If the host has a 'zic' command with a '-L leapsecondfilename' option,
80fd7387
RM
47 then it supports leap seconds; otherwise it probably doesn't. */
48#ifndef LEAP_SECONDS_POSSIBLE
9c2322bc 49# define LEAP_SECONDS_POSSIBLE 1
80fd7387
RM
50#endif
51
28f540f4
RM
52#include <time.h>
53
de20b81a 54#include <errno.h>
85e07670 55#include <limits.h>
8e6fd2bd
PE
56#include <stdbool.h>
57#include <stdlib.h>
58#include <string.h>
28f540f4 59
8e6fd2bd
PE
60#include <intprops.h>
61#include <verify.h>
9b5204dd 62
8e6fd2bd 63#if DEBUG_MKTIME
9c2322bc 64# include <stdio.h>
80fd7387 65/* Make it work even if the system's libc has its own mktime routine. */
826dd0ab 66# undef mktime
9c2322bc 67# define mktime my_mktime
f2b3078e 68#endif /* DEBUG_MKTIME */
28f540f4 69
8e6fd2bd
PE
70#ifndef NEED_MKTIME_INTERNAL
71# define NEED_MKTIME_INTERNAL 0
72#endif
73#ifndef NEED_MKTIME_WINDOWS
74# define NEED_MKTIME_WINDOWS 0
75#endif
76#ifndef NEED_MKTIME_WORKING
77# define NEED_MKTIME_WORKING DEBUG_MKTIME
78#endif
79
80#include "mktime-internal.h"
81
5a580643 82#if !defined _LIBC && (NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS)
8e6fd2bd
PE
83static void
84my_tzset (void)
85{
86# if NEED_MKTIME_WINDOWS
87 /* Rectify the value of the environment variable TZ.
88 There are four possible kinds of such values:
89 - Traditional US time zone names, e.g. "PST8PDT". Syntax: see
90 <https://msdn.microsoft.com/en-us/library/90s5c885.aspx>
91 - Time zone names based on geography, that contain one or more
92 slashes, e.g. "Europe/Moscow".
93 - Time zone names based on geography, without slashes, e.g.
94 "Singapore".
95 - Time zone names that contain explicit DST rules. Syntax: see
96 <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03>
97 The Microsoft CRT understands only the first kind. It produces incorrect
98 results if the value of TZ is of the other kinds.
99 But in a Cygwin environment, /etc/profile.d/tzset.sh sets TZ to a value
100 of the second kind for most geographies, or of the first kind in a few
101 other geographies. If it is of the second kind, neutralize it. For the
102 Microsoft CRT, an absent or empty TZ means the time zone that the user
103 has set in the Windows Control Panel.
104 If the value of TZ is of the third or fourth kind -- Cygwin programs
105 understand these syntaxes as well --, it does not matter whether we
106 neutralize it or not, since these values occur only when a Cygwin user
107 has set TZ explicitly; this case is 1. rare and 2. under the user's
108 responsibility. */
109 const char *tz = getenv ("TZ");
110 if (tz != NULL && strchr (tz, '/') != NULL)
111 _putenv ("TZ=");
112# elif HAVE_TZSET
113 tzset ();
62bdf9a6 114# endif
8e6fd2bd
PE
115}
116# undef __tzset
117# define __tzset() my_tzset ()
62bdf9a6
PE
118#endif
119
8e6fd2bd
PE
120#if defined _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL
121
122/* A signed type that can represent an integer number of years
123 multiplied by three times the number of seconds in a year. It is
124 needed when converting a tm_year value times the number of seconds
125 in a year. The factor of three comes because these products need
126 to be subtracted from each other, and sometimes with an offset
127 added to them, without worrying about overflow.
128
129 Much of the code uses long_int to represent time_t values, to
130 lessen the hassle of dealing with platforms where time_t is
131 unsigned, and because long_int should suffice to represent all
132 time_t values that mktime can generate even on platforms where
133 time_t is excessively wide. */
f04dfbc2 134
8e6fd2bd 135#if INT_MAX <= LONG_MAX / 3 / 366 / 24 / 60 / 60
f04dfbc2
PE
136typedef long int long_int;
137#else
138typedef long long int long_int;
139#endif
8e6fd2bd 140verify (INT_MAX <= TYPE_MAXIMUM (long_int) / 3 / 366 / 24 / 60 / 60);
f04dfbc2 141
1c67fabd 142/* Shift A right by B bits portably, by dividing A by 2**B and
8e6fd2bd
PE
143 truncating towards minus infinity. B should be in the range 0 <= B
144 <= LONG_INT_BITS - 2, where LONG_INT_BITS is the number of useful
145 bits in a long_int. LONG_INT_BITS is at least 32.
1c67fabd
RM
146
147 ISO C99 says that A >> B is implementation-defined if A < 0. Some
148 implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
149 right in the usual way when A < 0, so SHR falls back on division if
150 ordinary A >> B doesn't seem to be the usual signed shift. */
28f540f4 151
8e6fd2bd
PE
152static long_int
153shr (long_int a, int b)
154{
155 long_int one = 1;
156 return (-one >> 1 == -1
157 ? a >> b
158 : a / (one << b) - (a % (one << b) < 0));
159}
160
161/* Bounds for the intersection of time_t and long_int. */
162
163static long_int const mktime_min
164 = ((TYPE_SIGNED (time_t) && TYPE_MINIMUM (time_t) < TYPE_MINIMUM (long_int))
165 ? TYPE_MINIMUM (long_int) : TYPE_MINIMUM (time_t));
166static long_int const mktime_max
167 = (TYPE_MAXIMUM (long_int) < TYPE_MAXIMUM (time_t)
168 ? TYPE_MAXIMUM (long_int) : TYPE_MAXIMUM (time_t));
169
170verify (TYPE_IS_INTEGER (time_t));
a28a0500 171
80fd7387 172#define EPOCH_YEAR 1970
a28a0500 173#define TM_YEAR_BASE 1900
8e6fd2bd 174verify (TM_YEAR_BASE % 100 == 0);
28f540f4 175
8e6fd2bd
PE
176/* Is YEAR + TM_YEAR_BASE a leap year? */
177static bool
f04dfbc2 178leapyear (long_int year)
72035294
RM
179{
180 /* Don't add YEAR to TM_YEAR_BASE, as that might overflow.
181 Also, work even if YEAR is negative. */
182 return
183 ((year & 3) == 0
184 && (year % 100 != 0
185 || ((year / 100) & 3) == (- (TM_YEAR_BASE / 100) & 3)));
186}
28f540f4 187
80fd7387 188/* How many days come before each month (0-12). */
8592ae92
UD
189#ifndef _LIBC
190static
191#endif
80fd7387
RM
192const unsigned short int __mon_yday[2][13] =
193 {
194 /* Normal years. */
195 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
196 /* Leap years. */
197 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
198 };
28f540f4 199
28f540f4 200
8e6fd2bd
PE
201/* Do the values A and B differ according to the rules for tm_isdst?
202 A and B differ if one is zero and the other positive. */
203static bool
ce73d683
PE
204isdst_differ (int a, int b)
205{
206 return (!a != !b) && (0 <= a) && (0 <= b);
207}
208
e507cc56
RM
209/* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -
210 (YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks
8e6fd2bd 211 were not adjusted between the timestamps.
80fd7387 212
e507cc56 213 The YEAR values uses the same numbering as TP->tm_year. Values
8e6fd2bd
PE
214 need not be in the usual range. However, YEAR1 must not overflow
215 when multiplied by three times the number of seconds in a year, and
216 likewise for YDAY1 and three times the number of seconds in a day. */
e507cc56 217
8e6fd2bd 218static long_int
f04dfbc2 219ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1,
e507cc56
RM
220 int year0, int yday0, int hour0, int min0, int sec0)
221{
8e6fd2bd 222 verify (-1 / 2 == 0);
e507cc56
RM
223
224 /* Compute intervening leap days correctly even if year is negative.
225 Take care to avoid integer overflow here. */
8e6fd2bd
PE
226 int a4 = shr (year1, 2) + shr (TM_YEAR_BASE, 2) - ! (year1 & 3);
227 int b4 = shr (year0, 2) + shr (TM_YEAR_BASE, 2) - ! (year0 & 3);
e507cc56
RM
228 int a100 = a4 / 25 - (a4 % 25 < 0);
229 int b100 = b4 / 25 - (b4 % 25 < 0);
8e6fd2bd
PE
230 int a400 = shr (a100, 2);
231 int b400 = shr (b100, 2);
e507cc56
RM
232 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
233
8e6fd2bd
PE
234 /* Compute the desired time without overflowing. */
235 long_int years = year1 - year0;
236 long_int days = 365 * years + yday1 - yday0 + intervening_leap_days;
237 long_int hours = 24 * days + hour1 - hour0;
238 long_int minutes = 60 * hours + min1 - min0;
239 long_int seconds = 60 * minutes + sec1 - sec0;
e507cc56
RM
240 return seconds;
241}
242
8e6fd2bd
PE
243/* Return the average of A and B, even if A + B would overflow.
244 Round toward positive infinity. */
245static long_int
246long_int_avg (long_int a, long_int b)
62bdf9a6 247{
8e6fd2bd 248 return shr (a, 1) + shr (b, 1) + ((a | b) & 1);
62bdf9a6 249}
e507cc56
RM
250
251/* Return a time_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),
8e6fd2bd 252 assuming that T corresponds to *TP and that no clock adjustments
e507cc56 253 occurred between *TP and the desired time.
8e6fd2bd
PE
254 Although T and the returned value are of type long_int,
255 they represent time_t values and must be in time_t range.
256 If TP is null, return a value not equal to T; this avoids false matches.
257 YEAR and YDAY must not be so large that multiplying them by three times the
258 number of seconds in a year (or day, respectively) would overflow long_int.
de20b81a
PE
259 If TP is non-null and the returned value would be out of range, set
260 errno to EOVERFLOW and yield a minimal or maximal in-range value
261 that is not equal to T. */
8e6fd2bd 262static long_int
f04dfbc2 263guess_time_tm (long_int year, long_int yday, int hour, int min, int sec,
8e6fd2bd 264 long_int t, const struct tm *tp)
80fd7387 265{
e507cc56 266 if (tp)
fe0ec73e 267 {
8e6fd2bd
PE
268 long_int result;
269 long_int d = ydhms_diff (year, yday, hour, min, sec,
270 tp->tm_year, tp->tm_yday,
271 tp->tm_hour, tp->tm_min, tp->tm_sec);
272 if (! INT_ADD_WRAPV (t, d, &result))
273 return result;
de20b81a 274 __set_errno (EOVERFLOW);
fe0ec73e 275 }
e507cc56 276
de20b81a 277 /* An error occurred, probably overflow. Return the nearest result
e507cc56
RM
278 that is actually in range, except don't report a zero difference
279 if the actual difference is nonzero, as that would cause a false
41aba3d7
UD
280 match; and don't oscillate between two values, as that would
281 confuse the spring-forward gap detector. */
8e6fd2bd
PE
282 return (t < long_int_avg (mktime_min, mktime_max)
283 ? (t <= mktime_min + 1 ? t + 1 : mktime_min)
284 : (mktime_max - 1 <= t ? t - 1 : mktime_max));
285}
286
287/* Use CONVERT to convert T to a struct tm value in *TM. T must be in
288 range for time_t. Return TM if successful, NULL if T is out of
289 range for CONVERT. */
290static struct tm *
291convert_time (struct tm *(*convert) (const time_t *, struct tm *),
292 long_int t, struct tm *tm)
293{
294 time_t x = t;
295 return convert (&x, tm);
80fd7387
RM
296}
297
fe0ec73e
UD
298/* Use CONVERT to convert *T to a broken down time in *TP.
299 If *T is out of range for conversion, adjust it so that
8e6fd2bd
PE
300 it is the nearest in-range value and then convert that.
301 A value is in range if it fits in both time_t and long_int. */
fe0ec73e 302static struct tm *
eda78eec 303ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
8e6fd2bd 304 long_int *t, struct tm *tp)
fe0ec73e 305{
8e6fd2bd
PE
306 struct tm *r;
307 if (*t < mktime_min)
308 *t = mktime_min;
309 else if (mktime_max < *t)
310 *t = mktime_max;
311 r = convert_time (convert, *t, tp);
fe0ec73e 312
40437871 313 if (!r && *t)
fe0ec73e 314 {
8e6fd2bd
PE
315 long_int bad = *t;
316 long_int ok = 0;
fe0ec73e 317
8e6fd2bd 318 /* BAD is a known unconvertible value, and OK is a known good one.
fe0ec73e
UD
319 Use binary search to narrow the range between BAD and OK until
320 they differ by 1. */
8e6fd2bd 321 while (true)
fe0ec73e 322 {
8e6fd2bd
PE
323 long_int mid = long_int_avg (ok, bad);
324 if (mid != ok && mid != bad)
325 break;
326 r = convert_time (convert, mid, tp);
40437871
RM
327 if (r)
328 ok = mid;
fe0ec73e
UD
329 else
330 bad = mid;
331 }
332
333 if (!r && ok)
334 {
335 /* The last conversion attempt failed;
336 revert to the most recent successful attempt. */
8e6fd2bd 337 r = convert_time (convert, ok, tp);
fe0ec73e
UD
338 }
339 }
340
341 return r;
342}
343
344
80fd7387
RM
345/* Convert *TP to a time_t value, inverting
346 the monotonic and mostly-unit-linear conversion function CONVERT.
347 Use *OFFSET to keep track of a guess at the offset of the result,
348 compared to what the result would be for UTC without leap seconds.
e507cc56 349 If *OFFSET's guess is correct, only one CONVERT call is needed.
de20b81a
PE
350 If successful, set *TP to the canonicalized struct tm;
351 otherwise leave *TP alone, return ((time_t) -1) and set errno.
e507cc56 352 This function is external because it is used also by timegm.c. */
80fd7387 353time_t
eda78eec
UD
354__mktime_internal (struct tm *tp,
355 struct tm *(*convert) (const time_t *, struct tm *),
8e6fd2bd 356 mktime_offset_t *offset)
28f540f4 357{
8e6fd2bd 358 long_int t, gt, t0, t1, t2, dt;
80fd7387
RM
359 struct tm tm;
360
361 /* The maximum number of probes (calls to CONVERT) should be enough
362 to handle any combinations of time zone rule changes, solar time,
25b3b17b
UD
363 leap seconds, and oscillations around a spring-forward gap.
364 POSIX.1 prohibits leap seconds, but some hosts have them anyway. */
365 int remaining_probes = 6;
80fd7387
RM
366
367 /* Time requested. Copy it in case CONVERT modifies *TP; this can
368 occur if TP is localtime's returned value and CONVERT is localtime. */
369 int sec = tp->tm_sec;
370 int min = tp->tm_min;
371 int hour = tp->tm_hour;
372 int mday = tp->tm_mday;
373 int mon = tp->tm_mon;
374 int year_requested = tp->tm_year;
ce73d683 375 int isdst = tp->tm_isdst;
80fd7387 376
b5ef404e
UD
377 /* 1 if the previous probe was DST. */
378 int dst2;
379
80fd7387
RM
380 /* Ensure that mon is in range, and set year accordingly. */
381 int mon_remainder = mon % 12;
382 int negative_mon_remainder = mon_remainder < 0;
383 int mon_years = mon / 12 - negative_mon_remainder;
f04dfbc2
PE
384 long_int lyear_requested = year_requested;
385 long_int year = lyear_requested + mon_years;
80fd7387 386
8592ae92 387 /* The other values need not be in range:
8e6fd2bd 388 the remaining code handles overflows correctly. */
80fd7387
RM
389
390 /* Calculate day of year from year, month, and day of month.
391 The result need not be in range. */
e507cc56
RM
392 int mon_yday = ((__mon_yday[leapyear (year)]
393 [mon_remainder + 12 * negative_mon_remainder])
394 - 1);
f04dfbc2
PE
395 long_int lmday = mday;
396 long_int yday = mon_yday + lmday;
e507cc56 397
8e6fd2bd
PE
398 mktime_offset_t off = *offset;
399 int negative_offset_guess;
80fd7387 400
9a0a462c 401 int sec_requested = sec;
55544141 402
e507cc56
RM
403 if (LEAP_SECONDS_POSSIBLE)
404 {
405 /* Handle out-of-range seconds specially,
406 since ydhms_tm_diff assumes every minute has 60 seconds. */
407 if (sec < 0)
408 sec = 0;
409 if (59 < sec)
410 sec = 59;
411 }
412
413 /* Invert CONVERT by probing. First assume the same offset as last
414 time. */
415
8e6fd2bd 416 INT_SUBTRACT_WRAPV (0, off, &negative_offset_guess);
e507cc56 417 t0 = ydhms_diff (year, yday, hour, min, sec,
8e6fd2bd 418 EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, negative_offset_guess);
80fd7387 419
e507cc56 420 /* Repeatedly use the error to improve the guess. */
28f540f4 421
e507cc56 422 for (t = t1 = t2 = t0, dst2 = 0;
8e6fd2bd 423 (gt = guess_time_tm (year, yday, hour, min, sec, t,
e507cc56
RM
424 ranged_convert (convert, &t, &tm)),
425 t != gt);
426 t1 = t2, t2 = t, t = gt, dst2 = tm.tm_isdst != 0)
25b3b17b 427 if (t == t1 && t != t2
b5ef404e
UD
428 && (tm.tm_isdst < 0
429 || (isdst < 0
430 ? dst2 <= (tm.tm_isdst != 0)
431 : (isdst != 0) != (tm.tm_isdst != 0))))
25b3b17b
UD
432 /* We can't possibly find a match, as we are oscillating
433 between two values. The requested time probably falls
e507cc56
RM
434 within a spring-forward gap of size GT - T. Follow the common
435 practice in this case, which is to return a time that is GT - T
25b3b17b 436 away from the requested time, preferring a time whose
b5ef404e
UD
437 tm_isdst differs from the requested value. (If no tm_isdst
438 was requested and only one of the two values has a nonzero
439 tm_isdst, prefer that value.) In practice, this is more
440 useful than returning -1. */
e507cc56 441 goto offset_found;
25b3b17b 442 else if (--remaining_probes == 0)
de20b81a
PE
443 {
444 __set_errno (EOVERFLOW);
445 return -1;
446 }
80fd7387 447
e507cc56 448 /* We have a match. Check whether tm.tm_isdst has the requested
25b3b17b 449 value, if any. */
ce73d683 450 if (isdst_differ (isdst, tm.tm_isdst))
80fd7387 451 {
c0016081
UD
452 /* tm.tm_isdst has the wrong value. Look for a neighboring
453 time with the right value, and use its UTC offset.
c0016081 454
e507cc56
RM
455 Heuristic: probe the adjacent timestamps in both directions,
456 looking for the desired isdst. This should work for all real
457 time zone histories in the tz database. */
458
459 /* Distance between probes when looking for a DST boundary. In
460 tzdata2003a, the shortest period of DST is 601200 seconds
461 (e.g., America/Recife starting 2000-10-08 01:00), and the
462 shortest period of non-DST surrounded by DST is 694800
463 seconds (Africa/Tunis starting 1943-04-17 01:00). Use the
464 minimum of these two values, so we don't miss these short
465 periods when probing. */
466 int stride = 601200;
467
468 /* The longest period of DST in tzdata2003a is 536454000 seconds
469 (e.g., America/Jujuy starting 1946-10-01 01:00). The longest
470 period of non-DST is much longer, but it makes no real sense
471 to search for more than a year of non-DST, so use the DST
472 max. */
473 int duration_max = 536454000;
474
475 /* Search in both directions, so the maximum distance is half
476 the duration; add the stride to avoid off-by-1 problems. */
477 int delta_bound = duration_max / 2 + stride;
478
479 int delta, direction;
480
481 for (delta = stride; delta < delta_bound; delta += stride)
482 for (direction = -1; direction <= 1; direction += 2)
8e6fd2bd
PE
483 {
484 long_int ot;
485 if (! INT_ADD_WRAPV (t, delta * direction, &ot))
486 {
487 struct tm otm;
488 ranged_convert (convert, &ot, &otm);
489 if (! isdst_differ (isdst, otm.tm_isdst))
490 {
491 /* We found the desired tm_isdst.
492 Extrapolate back to the desired time. */
493 t = guess_time_tm (year, yday, hour, min, sec, ot, &otm);
494 ranged_convert (convert, &t, &tm);
495 goto offset_found;
496 }
497 }
498 }
80fd7387 499 }
28f540f4 500
e507cc56 501 offset_found:
8e6fd2bd
PE
502 /* Set *OFFSET to the low-order bits of T - T0 - NEGATIVE_OFFSET_GUESS.
503 This is just a heuristic to speed up the next mktime call, and
504 correctness is unaffected if integer overflow occurs here. */
505 INT_SUBTRACT_WRAPV (t, t0, &dt);
506 INT_SUBTRACT_WRAPV (dt, negative_offset_guess, offset);
80fd7387 507
e507cc56 508 if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec)
80fd7387
RM
509 {
510 /* Adjust time to reflect the tm_sec requested, not the normalized value.
511 Also, repair any damage from a false match due to a leap second. */
8e6fd2bd
PE
512 long_int sec_adjustment = sec == 0 && tm.tm_sec == 60;
513 sec_adjustment -= sec;
514 sec_adjustment += sec_requested;
515 if (INT_ADD_WRAPV (t, sec_adjustment, &t)
de20b81a
PE
516 || ! (mktime_min <= t && t <= mktime_max))
517 {
518 __set_errno (EOVERFLOW);
519 return -1;
520 }
521 if (! convert_time (convert, t, &tm))
78575a84
UD
522 return -1;
523 }
524
80fd7387
RM
525 *tp = tm;
526 return t;
527}
528
8e6fd2bd 529#endif /* _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL */
eda78eec 530
8e6fd2bd 531#if defined _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS
eda78eec
UD
532
533/* Convert *TP to a time_t value. */
534time_t
85e07670 535mktime (struct tm *tp)
eda78eec 536{
eda78eec 537 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
6226efbd 538 time zone names contained in the external variable 'tzname' shall
eda78eec
UD
539 be set as if the tzset() function had been called. */
540 __tzset ();
eda78eec 541
8e6fd2bd
PE
542# if defined _LIBC || NEED_MKTIME_WORKING
543 static mktime_offset_t localtime_offset;
7683e140 544 return __mktime_internal (tp, __localtime_r, &localtime_offset);
8e6fd2bd
PE
545# else
546# undef mktime
547 return mktime (tp);
548# endif
eda78eec 549}
8e6fd2bd 550#endif /* _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS */
eda78eec 551
80fd7387
RM
552#ifdef weak_alias
553weak_alias (mktime, timelocal)
28f540f4 554#endif
c5598d47
RM
555
556#ifdef _LIBC
557libc_hidden_def (mktime)
558libc_hidden_weak (timelocal)
559#endif
80fd7387 560\f
8e6fd2bd 561#if DEBUG_MKTIME
28f540f4 562
80fd7387 563static int
85e07670 564not_equal_tm (const struct tm *a, const struct tm *b)
80fd7387
RM
565{
566 return ((a->tm_sec ^ b->tm_sec)
567 | (a->tm_min ^ b->tm_min)
568 | (a->tm_hour ^ b->tm_hour)
569 | (a->tm_mday ^ b->tm_mday)
570 | (a->tm_mon ^ b->tm_mon)
571 | (a->tm_year ^ b->tm_year)
80fd7387 572 | (a->tm_yday ^ b->tm_yday)
ce73d683 573 | isdst_differ (a->tm_isdst, b->tm_isdst));
80fd7387 574}
28f540f4 575
80fd7387 576static void
85e07670 577print_tm (const struct tm *tp)
80fd7387 578{
fe0ec73e
UD
579 if (tp)
580 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
581 tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
582 tp->tm_hour, tp->tm_min, tp->tm_sec,
583 tp->tm_yday, tp->tm_wday, tp->tm_isdst);
584 else
585 printf ("0");
80fd7387 586}
28f540f4 587
80fd7387 588static int
85e07670 589check_result (time_t tk, struct tm tmk, time_t tl, const struct tm *lt)
80fd7387 590{
fe0ec73e 591 if (tk != tl || !lt || not_equal_tm (&tmk, lt))
80fd7387
RM
592 {
593 printf ("mktime (");
fe0ec73e 594 print_tm (lt);
85e07670
RM
595 printf (")\nyields (");
596 print_tm (&tmk);
597 printf (") == %ld, should be %ld\n", (long int) tk, (long int) tl);
80fd7387
RM
598 return 1;
599 }
600
601 return 0;
602}
28f540f4 603
80fd7387 604int
85e07670 605main (int argc, char **argv)
80fd7387
RM
606{
607 int status = 0;
608 struct tm tm, tmk, tml;
fe0ec73e 609 struct tm *lt;
85e07670 610 time_t tk, tl, tl1;
80fd7387
RM
611 char trailer;
612
8e6fd2bd
PE
613 /* Sanity check, plus call tzset. */
614 tl = 0;
615 if (! localtime (&tl))
616 {
617 printf ("localtime (0) fails\n");
618 status = 1;
619 }
620
80fd7387
RM
621 if ((argc == 3 || argc == 4)
622 && (sscanf (argv[1], "%d-%d-%d%c",
623 &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
624 == 3)
625 && (sscanf (argv[2], "%d:%d:%d%c",
626 &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
627 == 3))
628 {
629 tm.tm_year -= TM_YEAR_BASE;
630 tm.tm_mon--;
631 tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
632 tmk = tm;
633 tl = mktime (&tmk);
8e6fd2bd 634 lt = localtime_r (&tl, &tml);
85e07670 635 printf ("mktime returns %ld == ", (long int) tl);
80fd7387
RM
636 print_tm (&tmk);
637 printf ("\n");
fe0ec73e 638 status = check_result (tl, tmk, tl, lt);
80fd7387
RM
639 }
640 else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
641 {
642 time_t from = atol (argv[1]);
643 time_t by = atol (argv[2]);
644 time_t to = atol (argv[3]);
28f540f4 645
80fd7387 646 if (argc == 4)
85e07670 647 for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
80fd7387 648 {
8e6fd2bd 649 lt = localtime_r (&tl, &tml);
fe0ec73e
UD
650 if (lt)
651 {
8e6fd2bd 652 tmk = tml;
fe0ec73e 653 tk = mktime (&tmk);
85e07670 654 status |= check_result (tk, tmk, tl, &tml);
fe0ec73e
UD
655 }
656 else
657 {
8e6fd2bd 658 printf ("localtime_r (%ld) yields 0\n", (long int) tl);
fe0ec73e
UD
659 status = 1;
660 }
85e07670
RM
661 tl1 = tl + by;
662 if ((tl1 < tl) != (by < 0))
663 break;
80fd7387
RM
664 }
665 else
85e07670 666 for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
80fd7387
RM
667 {
668 /* Null benchmark. */
8e6fd2bd 669 lt = localtime_r (&tl, &tml);
fe0ec73e
UD
670 if (lt)
671 {
8e6fd2bd 672 tmk = tml;
fe0ec73e 673 tk = tl;
85e07670 674 status |= check_result (tk, tmk, tl, &tml);
fe0ec73e
UD
675 }
676 else
677 {
8e6fd2bd 678 printf ("localtime_r (%ld) yields 0\n", (long int) tl);
fe0ec73e
UD
679 status = 1;
680 }
85e07670
RM
681 tl1 = tl + by;
682 if ((tl1 < tl) != (by < 0))
683 break;
80fd7387
RM
684 }
685 }
686 else
687 printf ("Usage:\
688\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
689\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
690\t%s FROM BY TO - # Do not test those values (for benchmark).\n",
691 argv[0], argv[0], argv[0]);
692
693 return status;
28f540f4 694}
28f540f4 695
f2b3078e 696#endif /* DEBUG_MKTIME */
28f540f4
RM
697\f
698/*
699Local Variables:
f2b3078e 700compile-command: "gcc -DDEBUG_MKTIME -I. -Wall -W -O2 -g mktime.c -o mktime"
28f540f4
RM
701End:
702*/