summaryrefslogtreecommitdiffstats
path: root/gl/mktime.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl/mktime.c')
-rw-r--r--gl/mktime.c163
1 files changed, 84 insertions, 79 deletions
diff --git a/gl/mktime.c b/gl/mktime.c
index c704f415..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-2024 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
@@ -51,7 +51,6 @@
51#include <string.h> 51#include <string.h>
52 52
53#include <intprops.h> 53#include <intprops.h>
54#include <verify.h>
55 54
56#ifndef NEED_MKTIME_INTERNAL 55#ifndef NEED_MKTIME_INTERNAL
57# define NEED_MKTIME_INTERNAL 0 56# define NEED_MKTIME_INTERNAL 0
@@ -63,6 +62,9 @@
63# define NEED_MKTIME_WORKING 0 62# define NEED_MKTIME_WORKING 0
64#endif 63#endif
65 64
65#ifdef _LIBC
66# include <tzset.h>
67#endif
66#include "mktime-internal.h" 68#include "mktime-internal.h"
67 69
68#if !defined _LIBC && (NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS) 70#if !defined _LIBC && (NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS)
@@ -99,8 +101,8 @@ my_tzset (void)
99 tzset (); 101 tzset ();
100# endif 102# endif
101} 103}
102# undef __tzset 104# undef tzset
103# define __tzset() my_tzset () 105# define tzset() my_tzset ()
104#endif 106#endif
105 107
106#if defined _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL 108#if defined _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL
@@ -119,12 +121,12 @@ my_tzset (void)
119 __time64_t values that mktime can generate even on platforms where 121 __time64_t values that mktime can generate even on platforms where
120 __time64_t is wider than the int components of struct tm. */ 122 __time64_t is wider than the int components of struct tm. */
121 123
122#if INT_MAX <= LONG_MAX / 4 / 366 / 24 / 60 / 60 124# if INT_MAX <= LONG_MAX / 4 / 366 / 24 / 60 / 60
123typedef long int long_int; 125typedef long int long_int;
124#else 126# else
125typedef long long int long_int; 127typedef long long int long_int;
126#endif 128# endif
127verify (INT_MAX <= TYPE_MAXIMUM (long_int) / 4 / 366 / 24 / 60 / 60); 129static_assert (INT_MAX <= TYPE_MAXIMUM (long_int) / 4 / 366 / 24 / 60 / 60);
128 130
129/* 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
130 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
@@ -155,9 +157,9 @@ static long_int const mktime_max
155 = (TYPE_MAXIMUM (long_int) < TYPE_MAXIMUM (__time64_t) 157 = (TYPE_MAXIMUM (long_int) < TYPE_MAXIMUM (__time64_t)
156 ? TYPE_MAXIMUM (long_int) : TYPE_MAXIMUM (__time64_t)); 158 ? TYPE_MAXIMUM (long_int) : TYPE_MAXIMUM (__time64_t));
157 159
158#define EPOCH_YEAR 1970 160# define EPOCH_YEAR 1970
159#define TM_YEAR_BASE 1900 161# define TM_YEAR_BASE 1900
160verify (TM_YEAR_BASE % 100 == 0); 162static_assert (TM_YEAR_BASE % 100 == 0);
161 163
162/* Is YEAR + TM_YEAR_BASE a leap year? */ 164/* Is YEAR + TM_YEAR_BASE a leap year? */
163static bool 165static bool
@@ -172,9 +174,9 @@ leapyear (long_int year)
172} 174}
173 175
174/* How many days come before each month (0-12). */ 176/* How many days come before each month (0-12). */
175#ifndef _LIBC 177# ifndef _LIBC
176static 178static
177#endif 179# endif
178const unsigned short int __mon_yday[2][13] = 180const unsigned short int __mon_yday[2][13] =
179 { 181 {
180 /* Normal years. */ 182 /* Normal years. */
@@ -206,7 +208,7 @@ static long_int
206ydhms_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,
207 int year0, int yday0, int hour0, int min0, int sec0) 209 int year0, int yday0, int hour0, int min0, int sec0)
208{ 210{
209 verify (-1 / 2 == 0); 211 static_assert (-1 / 2 == 0);
210 212
211 /* Compute intervening leap days correctly even if year is negative. 213 /* Compute intervening leap days correctly even if year is negative.
212 Take care to avoid integer overflow here. */ 214 Take care to avoid integer overflow here. */
@@ -251,29 +253,34 @@ tm_diff (long_int year, long_int yday, int hour, int min, int sec,
251 tp->tm_hour, tp->tm_min, tp->tm_sec); 253 tp->tm_hour, tp->tm_min, tp->tm_sec);
252} 254}
253 255
254/* Use CONVERT to convert T to a struct tm value in *TM. T must be in 256#ifndef _LIBC
255 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,
256 failure. */ 258 otherwise gmtime64_r. T must be in range for __time64_t. Return
259 TM if successful, NULL (setting errno) on failure. */
257static struct tm * 260static struct tm *
258convert_time (struct tm *(*convert) (const __time64_t *, struct tm *), 261convert_time (long_int t, bool local, struct tm *tm)
259 long_int t, struct tm *tm)
260{ 262{
261 __time64_t x = t; 263 __time64_t x = t;
262 return convert (&x, tm); 264 if (local)
265 return __localtime64_r (&x, tm);
266 else
267 return __gmtime64_r (&x, tm);
263} 268}
269# define __tz_convert convert_time
270#endif
264 271
265/* 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
266 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
267 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
268 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
269 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. */
270static struct tm * 278static struct tm *
271ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *), 279ranged_convert (bool local, long_int *t, struct tm *tp)
272 long_int *t, struct tm *tp)
273{ 280{
274 long_int t1 = (*t < mktime_min ? mktime_min 281 long_int t1 = (*t < mktime_min ? mktime_min
275 : *t <= mktime_max ? *t : mktime_max); 282 : *t <= mktime_max ? *t : mktime_max);
276 struct tm *r = convert_time (convert, t1, tp); 283 struct tm *r = __tz_convert (t1, local, tp);
277 if (r) 284 if (r)
278 { 285 {
279 *t = t1; 286 *t = t1;
@@ -294,7 +301,7 @@ ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *),
294 long_int mid = long_int_avg (ok, bad); 301 long_int mid = long_int_avg (ok, bad);
295 if (mid == ok || mid == bad) 302 if (mid == ok || mid == bad)
296 break; 303 break;
297 if (convert_time (convert, mid, tp)) 304 if (__tz_convert (mid, local, tp))
298 ok = mid, oktm = *tp; 305 ok = mid, oktm = *tp;
299 else if (errno != EOVERFLOW) 306 else if (errno != EOVERFLOW)
300 return NULL; 307 return NULL;
@@ -310,29 +317,38 @@ ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *),
310} 317}
311 318
312 319
313/* Convert *TP to a __time64_t value, inverting 320/* Convert *TP to a __time64_t value. If LOCAL, the reverse mapping
314 the monotonic and mostly-unit-linear conversion function CONVERT. 321 is performed as if localtime, otherwise as if by gmtime. Use
315 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,
316 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.
317 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
318 If successful, set *TP to the canonicalized struct tm; 325 needed. If successful, set *TP to the canonicalized struct tm;
319 otherwise leave *TP alone, return ((time_t) -1) and set errno. 326 otherwise leave *TP alone, return ((time_t) -1) and set errno.
320 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. */
321__time64_t 330__time64_t
322__mktime_internal (struct tm *tp, 331__mktime_internal (struct tm *tp, bool local, mktime_offset_t *offset)
323 struct tm *(*convert) (const __time64_t *, struct tm *),
324 mktime_offset_t *offset)
325{ 332{
326 struct tm tm; 333 struct tm tm;
327 334
328 /* The maximum number of probes (calls to CONVERT) should be enough 335 /* The maximum number of probes should be enough to handle any
329 to handle any combinations of time zone rule changes, solar time, 336 combinations of time zone rule changes, solar time, leap seconds,
330 leap seconds, and oscillations around a spring-forward gap. 337 and oscillations around a spring-forward gap. POSIX.1 prohibits
331 POSIX.1 prohibits leap seconds, but some hosts have them anyway. */ 338 leap seconds, but some hosts have them anyway. */
332 int remaining_probes = 6; 339 int remaining_probes = 6;
333 340
334 /* Time requested. Copy it in case CONVERT modifies *TP; this can 341#ifndef _LIBC
335 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. */
336 int sec = tp->tm_sec; 352 int sec = tp->tm_sec;
337 int min = tp->tm_min; 353 int min = tp->tm_min;
338 int hour = tp->tm_hour; 354 int hour = tp->tm_hour;
@@ -341,8 +357,8 @@ __mktime_internal (struct tm *tp,
341 int year_requested = tp->tm_year; 357 int year_requested = tp->tm_year;
342 int isdst = tp->tm_isdst; 358 int isdst = tp->tm_isdst;
343 359
344 /* 1 if the previous probe was DST. */ 360 /* True if the previous probe was DST. */
345 int dst2 = 0; 361 bool dst2 = false;
346 362
347 /* Ensure that mon is in range, and set year accordingly. */ 363 /* Ensure that mon is in range, and set year accordingly. */
348 int mon_remainder = mon % 12; 364 int mon_remainder = mon % 12;
@@ -390,7 +406,7 @@ __mktime_internal (struct tm *tp,
390 406
391 while (true) 407 while (true)
392 { 408 {
393 if (! ranged_convert (convert, &t, &tm)) 409 if (! ranged_convert (local, &t, &tm))
394 return -1; 410 return -1;
395 long_int dt = tm_diff (year, yday, hour, min, sec, &tm); 411 long_int dt = tm_diff (year, yday, hour, min, sec, &tm);
396 if (dt == 0) 412 if (dt == 0)
@@ -431,13 +447,10 @@ __mktime_internal (struct tm *tp,
431 447
432 Heuristic: probe the adjacent timestamps in both directions, 448 Heuristic: probe the adjacent timestamps in both directions,
433 looking for the desired isdst. If none is found within a 449 looking for the desired isdst. If none is found within a
434 reasonable duration bound, assume a one-hour DST difference. 450 reasonable duration bound, ignore the disagreement.
435 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
436 database. */ 452 database. */
437 453
438 /* +1 if we wanted standard time but got DST, -1 if the reverse. */
439 int dst_difference = (isdst == 0) - (tm.tm_isdst == 0);
440
441 /* Distance between probes when looking for a DST boundary. In 454 /* Distance between probes when looking for a DST boundary. In
442 tzdata2003a, the shortest period of DST is 601200 seconds 455 tzdata2003a, the shortest period of DST is 601200 seconds
443 (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
@@ -447,21 +460,17 @@ __mktime_internal (struct tm *tp,
447 periods when probing. */ 460 periods when probing. */
448 int stride = 601200; 461 int stride = 601200;
449 462
450 /* In TZDB 2021e, the longest period of DST (or of non-DST), in 463 /* Do not probe too far away from the requested time,
451 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.
452 is 457243209 seconds: e.g., America/Cambridge_Bay with leap 465 This helps avoid unexpected results in (for example) Asia/Kolkata,
453 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
454 double-daylight time (-05) to standard time (-07), and 467 did observe DST long ago. */
455 continuing to 1980-04-27 02:00 in a switch from standard time 468 int year_seconds_bound = 366 * 24 * 60 * 60 + 1;
456 (-07) to daylight time (-06). */ 469 int delta_bound = year_seconds_bound + stride;
457 int duration_max = 457243209;
458
459 /* Search in both directions, so the maximum distance is half
460 the duration; add the stride to avoid off-by-1 problems. */
461 int delta_bound = duration_max / 2 + stride;
462 470
463 int delta, direction; 471 int delta, direction;
464 472
473 /* Search in both directions, closest first. */
465 for (delta = stride; delta < delta_bound; delta += stride) 474 for (delta = stride; delta < delta_bound; delta += stride)
466 for (direction = -1; direction <= 1; direction += 2) 475 for (direction = -1; direction <= 1; direction += 2)
467 { 476 {
@@ -469,7 +478,7 @@ __mktime_internal (struct tm *tp,
469 if (! ckd_add (&ot, t, delta * direction)) 478 if (! ckd_add (&ot, t, delta * direction))
470 { 479 {
471 struct tm otm; 480 struct tm otm;
472 if (! ranged_convert (convert, &ot, &otm)) 481 if (! ranged_convert (local, &ot, &otm))
473 return -1; 482 return -1;
474 if (! isdst_differ (isdst, otm.tm_isdst)) 483 if (! isdst_differ (isdst, otm.tm_isdst))
475 { 484 {
@@ -479,7 +488,7 @@ __mktime_internal (struct tm *tp,
479 &otm); 488 &otm);
480 if (mktime_min <= gt && gt <= mktime_max) 489 if (mktime_min <= gt && gt <= mktime_max)
481 { 490 {
482 if (convert_time (convert, gt, &tm)) 491 if (__tz_convert (gt, local, &tm))
483 { 492 {
484 t = gt; 493 t = gt;
485 goto offset_found; 494 goto offset_found;
@@ -491,13 +500,8 @@ __mktime_internal (struct tm *tp,
491 } 500 }
492 } 501 }
493 502
494 /* No unusual DST offset was found nearby. Assume one-hour DST. */ 503 /* No probe with the requested tm_isdst was found nearby.
495 t += 60 * 60 * dst_difference; 504 Ignore the requested tm_isdst. */
496 if (mktime_min <= t && t <= mktime_max && convert_time (convert, t, &tm))
497 goto offset_found;
498
499 __set_errno (EOVERFLOW);
500 return -1;
501 } 505 }
502 506
503 offset_found: 507 offset_found:
@@ -520,7 +524,7 @@ __mktime_internal (struct tm *tp,
520 __set_errno (EOVERFLOW); 524 __set_errno (EOVERFLOW);
521 return -1; 525 return -1;
522 } 526 }
523 if (! convert_time (convert, t, &tm)) 527 if (! __tz_convert (t, local, &tm))
524 return -1; 528 return -1;
525 } 529 }
526 530
@@ -536,18 +540,19 @@ __mktime_internal (struct tm *tp,
536__time64_t 540__time64_t
537__mktime64 (struct tm *tp) 541__mktime64 (struct tm *tp)
538{ 542{
539 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the 543 __libc_lock_lock (__tzset_lock);
540 time zone names contained in the external variable 'tzname' shall 544 __tzset_unlocked ();
541 be set as if the tzset() function had been called. */
542 __tzset ();
543 545
544# if defined _LIBC || NEED_MKTIME_WORKING 546# if defined _LIBC || NEED_MKTIME_WORKING
545 static mktime_offset_t localtime_offset; 547 static mktime_offset_t localtime_offset;
546 return __mktime_internal (tp, __localtime64_r, &localtime_offset); 548 __time64_t result = __mktime_internal (tp, true, &localtime_offset);
547# else 549# else
548# undef mktime 550# undef mktime
549 return mktime (tp); 551 __time64_t result = mktime (tp);
550# endif 552# endif
553
554 __libc_lock_unlock (__tzset_lock);
555 return result;
551} 556}
552#endif /* _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS */ 557#endif /* _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS */
553 558