summaryrefslogtreecommitdiffstats
path: root/gl/mktime.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl/mktime.c')
-rw-r--r--gl/mktime.c174
1 files changed, 90 insertions, 84 deletions
diff --git a/gl/mktime.c b/gl/mktime.c
index 94a4320e..4218fca6 100644
--- a/gl/mktime.c
+++ b/gl/mktime.c
@@ -1,5 +1,5 @@
1/* Convert a 'struct tm' to a time_t value. 1/* Convert a 'struct tm' to a time_t value.
2 Copyright (C) 1993-2023 Free Software Foundation, Inc. 2 Copyright (C) 1993-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 Contributed by Paul Eggert <eggert@twinsun.com>. 4 Contributed by Paul Eggert <eggert@twinsun.com>.
5 5
@@ -46,11 +46,11 @@
46#include <errno.h> 46#include <errno.h>
47#include <limits.h> 47#include <limits.h>
48#include <stdbool.h> 48#include <stdbool.h>
49#include <stdckdint.h>
49#include <stdlib.h> 50#include <stdlib.h>
50#include <string.h> 51#include <string.h>
51 52
52#include <intprops.h> 53#include <intprops.h>
53#include <verify.h>
54 54
55#ifndef NEED_MKTIME_INTERNAL 55#ifndef NEED_MKTIME_INTERNAL
56# define NEED_MKTIME_INTERNAL 0 56# define NEED_MKTIME_INTERNAL 0
@@ -62,6 +62,9 @@
62# define NEED_MKTIME_WORKING 0 62# define NEED_MKTIME_WORKING 0
63#endif 63#endif
64 64
65#ifdef _LIBC
66# include <tzset.h>
67#endif
65#include "mktime-internal.h" 68#include "mktime-internal.h"
66 69
67#if !defined _LIBC && (NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS) 70#if !defined _LIBC && (NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS)
@@ -98,8 +101,8 @@ my_tzset (void)
98 tzset (); 101 tzset ();
99# endif 102# endif
100} 103}
101# undef __tzset 104# undef tzset
102# define __tzset() my_tzset () 105# define tzset() my_tzset ()
103#endif 106#endif
104 107
105#if defined _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL 108#if defined _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL
@@ -118,12 +121,12 @@ my_tzset (void)
118 __time64_t values that mktime can generate even on platforms where 121 __time64_t values that mktime can generate even on platforms where
119 __time64_t is wider than the int components of struct tm. */ 122 __time64_t is wider than the int components of struct tm. */
120 123
121#if INT_MAX <= LONG_MAX / 4 / 366 / 24 / 60 / 60 124# if INT_MAX <= LONG_MAX / 4 / 366 / 24 / 60 / 60
122typedef long int long_int; 125typedef long int long_int;
123#else 126# else
124typedef long long int long_int; 127typedef long long int long_int;
125#endif 128# endif
126verify (INT_MAX <= TYPE_MAXIMUM (long_int) / 4 / 366 / 24 / 60 / 60); 129static_assert (INT_MAX <= TYPE_MAXIMUM (long_int) / 4 / 366 / 24 / 60 / 60);
127 130
128/* Shift A right by B bits portably, by dividing A by 2**B and 131/* Shift A right by B bits portably, by dividing A by 2**B and
129 truncating towards minus infinity. B should be in the range 0 <= B 132 truncating towards minus infinity. B should be in the range 0 <= B
@@ -154,9 +157,9 @@ static long_int const mktime_max
154 = (TYPE_MAXIMUM (long_int) < TYPE_MAXIMUM (__time64_t) 157 = (TYPE_MAXIMUM (long_int) < TYPE_MAXIMUM (__time64_t)
155 ? TYPE_MAXIMUM (long_int) : TYPE_MAXIMUM (__time64_t)); 158 ? TYPE_MAXIMUM (long_int) : TYPE_MAXIMUM (__time64_t));
156 159
157#define EPOCH_YEAR 1970 160# define EPOCH_YEAR 1970
158#define TM_YEAR_BASE 1900 161# define TM_YEAR_BASE 1900
159verify (TM_YEAR_BASE % 100 == 0); 162static_assert (TM_YEAR_BASE % 100 == 0);
160 163
161/* Is YEAR + TM_YEAR_BASE a leap year? */ 164/* Is YEAR + TM_YEAR_BASE a leap year? */
162static bool 165static bool
@@ -171,9 +174,9 @@ leapyear (long_int year)
171} 174}
172 175
173/* How many days come before each month (0-12). */ 176/* How many days come before each month (0-12). */
174#ifndef _LIBC 177# ifndef _LIBC
175static 178static
176#endif 179# endif
177const unsigned short int __mon_yday[2][13] = 180const unsigned short int __mon_yday[2][13] =
178 { 181 {
179 /* Normal years. */ 182 /* Normal years. */
@@ -205,7 +208,7 @@ static long_int
205ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1, 208ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1,
206 int year0, int yday0, int hour0, int min0, int sec0) 209 int year0, int yday0, int hour0, int min0, int sec0)
207{ 210{
208 verify (-1 / 2 == 0); 211 static_assert (-1 / 2 == 0);
209 212
210 /* Compute intervening leap days correctly even if year is negative. 213 /* Compute intervening leap days correctly even if year is negative.
211 Take care to avoid integer overflow here. */ 214 Take care to avoid integer overflow here. */
@@ -250,29 +253,34 @@ tm_diff (long_int year, long_int yday, int hour, int min, int sec,
250 tp->tm_hour, tp->tm_min, tp->tm_sec); 253 tp->tm_hour, tp->tm_min, tp->tm_sec);
251} 254}
252 255
253/* Use CONVERT to convert T to a struct tm value in *TM. T must be in 256#ifndef _LIBC
254 range for __time64_t. Return TM if successful, NULL (setting errno) on 257/* Convert T to a struct tm value in *TM. Use localtime64_r if LOCAL,
255 failure. */ 258 otherwise gmtime64_r. T must be in range for __time64_t. Return
259 TM if successful, NULL (setting errno) on failure. */
256static struct tm * 260static struct tm *
257convert_time (struct tm *(*convert) (const __time64_t *, struct tm *), 261convert_time (long_int t, bool local, struct tm *tm)
258 long_int t, struct tm *tm)
259{ 262{
260 __time64_t x = t; 263 __time64_t x = t;
261 return convert (&x, tm); 264 if (local)
265 return __localtime64_r (&x, tm);
266 else
267 return __gmtime64_r (&x, tm);
262} 268}
269# define __tz_convert convert_time
270#endif
263 271
264/* Use CONVERT to convert *T to a broken down time in *TP. 272/* Convert *T to a broken down time in *TP (as if by localtime if
265 If *T is out of range for conversion, adjust it so that 273 LOCAL, otherwise as if by gmtime). If *T is out of range for
266 it is the nearest in-range value and then convert that. 274 conversion, adjust it so that it is the nearest in-range value and
267 A value is in range if it fits in both __time64_t and long_int. 275 then convert that. A value is in range if it fits in both
268 Return TP on success, NULL (setting errno) on failure. */ 276 __time64_t and long_int. Return TP on success, NULL (setting
277 errno) on failure. */
269static struct tm * 278static struct tm *
270ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *), 279ranged_convert (bool local, long_int *t, struct tm *tp)
271 long_int *t, struct tm *tp)
272{ 280{
273 long_int t1 = (*t < mktime_min ? mktime_min 281 long_int t1 = (*t < mktime_min ? mktime_min
274 : *t <= mktime_max ? *t : mktime_max); 282 : *t <= mktime_max ? *t : mktime_max);
275 struct tm *r = convert_time (convert, t1, tp); 283 struct tm *r = __tz_convert (t1, local, tp);
276 if (r) 284 if (r)
277 { 285 {
278 *t = t1; 286 *t = t1;
@@ -293,7 +301,7 @@ ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *),
293 long_int mid = long_int_avg (ok, bad); 301 long_int mid = long_int_avg (ok, bad);
294 if (mid == ok || mid == bad) 302 if (mid == ok || mid == bad)
295 break; 303 break;
296 if (convert_time (convert, mid, tp)) 304 if (__tz_convert (mid, local, tp))
297 ok = mid, oktm = *tp; 305 ok = mid, oktm = *tp;
298 else if (errno != EOVERFLOW) 306 else if (errno != EOVERFLOW)
299 return NULL; 307 return NULL;
@@ -309,29 +317,38 @@ ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *),
309} 317}
310 318
311 319
312/* Convert *TP to a __time64_t value, inverting 320/* Convert *TP to a __time64_t value. If LOCAL, the reverse mapping
313 the monotonic and mostly-unit-linear conversion function CONVERT. 321 is performed as if localtime, otherwise as if by gmtime. Use
314 Use *OFFSET to keep track of a guess at the offset of the result, 322 *OFFSET to keep track of a guess at the offset of the result,
315 compared to what the result would be for UTC without leap seconds. 323 compared to what the result would be for UTC without leap seconds.
316 If *OFFSET's guess is correct, only one CONVERT call is needed. 324 If *OFFSET's guess is correct, only one reverse mapping call is
317 If successful, set *TP to the canonicalized struct tm; 325 needed. If successful, set *TP to the canonicalized struct tm;
318 otherwise leave *TP alone, return ((time_t) -1) and set errno. 326 otherwise leave *TP alone, return ((time_t) -1) and set errno.
319 This function is external because it is used also by timegm.c. */ 327 This function is external because it is used also by timegm.c.
328
329 If _LIBC, the caller must lock __tzset_lock. */
320__time64_t 330__time64_t
321__mktime_internal (struct tm *tp, 331__mktime_internal (struct tm *tp, bool local, mktime_offset_t *offset)
322 struct tm *(*convert) (const __time64_t *, struct tm *),
323 mktime_offset_t *offset)
324{ 332{
325 struct tm tm; 333 struct tm tm;
326 334
327 /* The maximum number of probes (calls to CONVERT) should be enough 335 /* The maximum number of probes should be enough to handle any
328 to handle any combinations of time zone rule changes, solar time, 336 combinations of time zone rule changes, solar time, leap seconds,
329 leap seconds, and oscillations around a spring-forward gap. 337 and oscillations around a spring-forward gap. POSIX.1 prohibits
330 POSIX.1 prohibits leap seconds, but some hosts have them anyway. */ 338 leap seconds, but some hosts have them anyway. */
331 int remaining_probes = 6; 339 int remaining_probes = 6;
332 340
333 /* Time requested. Copy it in case CONVERT modifies *TP; this can 341#ifndef _LIBC
334 occur if TP is localtime's returned value and CONVERT is localtime. */ 342 /* Gnulib mktime doesn't lock the tz state, so it may need to probe
343 more often if some other thread changes local time while
344 __mktime_internal is probing. Double the number of probes; this
345 should suffice for practical cases that are at all likely. */
346 remaining_probes *= 2;
347#endif
348
349 /* Time requested. Copy it in case gmtime/localtime modify *TP;
350 this can occur if TP is localtime's returned value and CONVERT is
351 localtime. */
335 int sec = tp->tm_sec; 352 int sec = tp->tm_sec;
336 int min = tp->tm_min; 353 int min = tp->tm_min;
337 int hour = tp->tm_hour; 354 int hour = tp->tm_hour;
@@ -340,8 +357,8 @@ __mktime_internal (struct tm *tp,
340 int year_requested = tp->tm_year; 357 int year_requested = tp->tm_year;
341 int isdst = tp->tm_isdst; 358 int isdst = tp->tm_isdst;
342 359
343 /* 1 if the previous probe was DST. */ 360 /* True if the previous probe was DST. */
344 int dst2 = 0; 361 bool dst2 = false;
345 362
346 /* Ensure that mon is in range, and set year accordingly. */ 363 /* Ensure that mon is in range, and set year accordingly. */
347 int mon_remainder = mon % 12; 364 int mon_remainder = mon % 12;
@@ -379,7 +396,7 @@ __mktime_internal (struct tm *tp,
379 /* Invert CONVERT by probing. First assume the same offset as last 396 /* Invert CONVERT by probing. First assume the same offset as last
380 time. */ 397 time. */
381 398
382 INT_SUBTRACT_WRAPV (0, off, &negative_offset_guess); 399 ckd_sub (&negative_offset_guess, 0, off);
383 long_int t0 = ydhms_diff (year, yday, hour, min, sec, 400 long_int t0 = ydhms_diff (year, yday, hour, min, sec,
384 EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, 401 EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0,
385 negative_offset_guess); 402 negative_offset_guess);
@@ -389,7 +406,7 @@ __mktime_internal (struct tm *tp,
389 406
390 while (true) 407 while (true)
391 { 408 {
392 if (! ranged_convert (convert, &t, &tm)) 409 if (! ranged_convert (local, &t, &tm))
393 return -1; 410 return -1;
394 long_int dt = tm_diff (year, yday, hour, min, sec, &tm); 411 long_int dt = tm_diff (year, yday, hour, min, sec, &tm);
395 if (dt == 0) 412 if (dt == 0)
@@ -430,13 +447,10 @@ __mktime_internal (struct tm *tp,
430 447
431 Heuristic: probe the adjacent timestamps in both directions, 448 Heuristic: probe the adjacent timestamps in both directions,
432 looking for the desired isdst. If none is found within a 449 looking for the desired isdst. If none is found within a
433 reasonable duration bound, assume a one-hour DST difference. 450 reasonable duration bound, ignore the disagreement.
434 This should work for all real time zone histories in the tz 451 This should work for all real time zone histories in the tz
435 database. */ 452 database. */
436 453
437 /* +1 if we wanted standard time but got DST, -1 if the reverse. */
438 int dst_difference = (isdst == 0) - (tm.tm_isdst == 0);
439
440 /* Distance between probes when looking for a DST boundary. In 454 /* Distance between probes when looking for a DST boundary. In
441 tzdata2003a, the shortest period of DST is 601200 seconds 455 tzdata2003a, the shortest period of DST is 601200 seconds
442 (e.g., America/Recife starting 2000-10-08 01:00), and the 456 (e.g., America/Recife starting 2000-10-08 01:00), and the
@@ -446,29 +460,25 @@ __mktime_internal (struct tm *tp,
446 periods when probing. */ 460 periods when probing. */
447 int stride = 601200; 461 int stride = 601200;
448 462
449 /* In TZDB 2021e, the longest period of DST (or of non-DST), in 463 /* Do not probe too far away from the requested time,
450 which the DST (or adjacent DST) difference is not one hour, 464 by striding until at least a year has passed, but then giving up.
451 is 457243209 seconds: e.g., America/Cambridge_Bay with leap 465 This helps avoid unexpected results in (for example) Asia/Kolkata,
452 seconds, starting 1965-10-31 00:00 in a switch from 466 for which today's users expect to see no DST even though it
453 double-daylight time (-05) to standard time (-07), and 467 did observe DST long ago. */
454 continuing to 1980-04-27 02:00 in a switch from standard time 468 int year_seconds_bound = 366 * 24 * 60 * 60 + 1;
455 (-07) to daylight time (-06). */ 469 int delta_bound = year_seconds_bound + stride;
456 int duration_max = 457243209;
457
458 /* Search in both directions, so the maximum distance is half
459 the duration; add the stride to avoid off-by-1 problems. */
460 int delta_bound = duration_max / 2 + stride;
461 470
462 int delta, direction; 471 int delta, direction;
463 472
473 /* Search in both directions, closest first. */
464 for (delta = stride; delta < delta_bound; delta += stride) 474 for (delta = stride; delta < delta_bound; delta += stride)
465 for (direction = -1; direction <= 1; direction += 2) 475 for (direction = -1; direction <= 1; direction += 2)
466 { 476 {
467 long_int ot; 477 long_int ot;
468 if (! INT_ADD_WRAPV (t, delta * direction, &ot)) 478 if (! ckd_add (&ot, t, delta * direction))
469 { 479 {
470 struct tm otm; 480 struct tm otm;
471 if (! ranged_convert (convert, &ot, &otm)) 481 if (! ranged_convert (local, &ot, &otm))
472 return -1; 482 return -1;
473 if (! isdst_differ (isdst, otm.tm_isdst)) 483 if (! isdst_differ (isdst, otm.tm_isdst))
474 { 484 {
@@ -478,7 +488,7 @@ __mktime_internal (struct tm *tp,
478 &otm); 488 &otm);
479 if (mktime_min <= gt && gt <= mktime_max) 489 if (mktime_min <= gt && gt <= mktime_max)
480 { 490 {
481 if (convert_time (convert, gt, &tm)) 491 if (__tz_convert (gt, local, &tm))
482 { 492 {
483 t = gt; 493 t = gt;
484 goto offset_found; 494 goto offset_found;
@@ -490,21 +500,16 @@ __mktime_internal (struct tm *tp,
490 } 500 }
491 } 501 }
492 502
493 /* No unusual DST offset was found nearby. Assume one-hour DST. */ 503 /* No probe with the requested tm_isdst was found nearby.
494 t += 60 * 60 * dst_difference; 504 Ignore the requested tm_isdst. */
495 if (mktime_min <= t && t <= mktime_max && convert_time (convert, t, &tm))
496 goto offset_found;
497
498 __set_errno (EOVERFLOW);
499 return -1;
500 } 505 }
501 506
502 offset_found: 507 offset_found:
503 /* Set *OFFSET to the low-order bits of T - T0 - NEGATIVE_OFFSET_GUESS. 508 /* Set *OFFSET to the low-order bits of T - T0 - NEGATIVE_OFFSET_GUESS.
504 This is just a heuristic to speed up the next mktime call, and 509 This is just a heuristic to speed up the next mktime call, and
505 correctness is unaffected if integer overflow occurs here. */ 510 correctness is unaffected if integer overflow occurs here. */
506 INT_SUBTRACT_WRAPV (t, t0, offset); 511 ckd_sub (offset, t, t0);
507 INT_SUBTRACT_WRAPV (*offset, negative_offset_guess, offset); 512 ckd_sub (offset, *offset, negative_offset_guess);
508 513
509 if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec) 514 if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec)
510 { 515 {
@@ -513,13 +518,13 @@ __mktime_internal (struct tm *tp,
513 long_int sec_adjustment = sec == 0 && tm.tm_sec == 60; 518 long_int sec_adjustment = sec == 0 && tm.tm_sec == 60;
514 sec_adjustment -= sec; 519 sec_adjustment -= sec;
515 sec_adjustment += sec_requested; 520 sec_adjustment += sec_requested;
516 if (INT_ADD_WRAPV (t, sec_adjustment, &t) 521 if (ckd_add (&t, t, sec_adjustment)
517 || ! (mktime_min <= t && t <= mktime_max)) 522 || ! (mktime_min <= t && t <= mktime_max))
518 { 523 {
519 __set_errno (EOVERFLOW); 524 __set_errno (EOVERFLOW);
520 return -1; 525 return -1;
521 } 526 }
522 if (! convert_time (convert, t, &tm)) 527 if (! __tz_convert (t, local, &tm))
523 return -1; 528 return -1;
524 } 529 }
525 530
@@ -535,18 +540,19 @@ __mktime_internal (struct tm *tp,
535__time64_t 540__time64_t
536__mktime64 (struct tm *tp) 541__mktime64 (struct tm *tp)
537{ 542{
538 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the 543 __libc_lock_lock (__tzset_lock);
539 time zone names contained in the external variable 'tzname' shall 544 __tzset_unlocked ();
540 be set as if the tzset() function had been called. */
541 __tzset ();
542 545
543# if defined _LIBC || NEED_MKTIME_WORKING 546# if defined _LIBC || NEED_MKTIME_WORKING
544 static mktime_offset_t localtime_offset; 547 static mktime_offset_t localtime_offset;
545 return __mktime_internal (tp, __localtime64_r, &localtime_offset); 548 __time64_t result = __mktime_internal (tp, true, &localtime_offset);
546# else 549# else
547# undef mktime 550# undef mktime
548 return mktime (tp); 551 __time64_t result = mktime (tp);
549# endif 552# endif
553
554 __libc_lock_unlock (__tzset_lock);
555 return result;
550} 556}
551#endif /* _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS */ 557#endif /* _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS */
552 558