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