diff options
Diffstat (limited to 'gl/mktime.c')
| -rw-r--r-- | gl/mktime.c | 163 |
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 |
| 123 | typedef long int long_int; | 125 | typedef long int long_int; |
| 124 | #else | 126 | # else |
| 125 | typedef long long int long_int; | 127 | typedef long long int long_int; |
| 126 | #endif | 128 | # endif |
| 127 | verify (INT_MAX <= TYPE_MAXIMUM (long_int) / 4 / 366 / 24 / 60 / 60); | 129 | static_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 |
| 160 | verify (TM_YEAR_BASE % 100 == 0); | 162 | static_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? */ |
| 163 | static bool | 165 | static 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 |
| 176 | static | 178 | static |
| 177 | #endif | 179 | # endif |
| 178 | const unsigned short int __mon_yday[2][13] = | 180 | const unsigned short int __mon_yday[2][13] = |
| 179 | { | 181 | { |
| 180 | /* Normal years. */ | 182 | /* Normal years. */ |
| @@ -206,7 +208,7 @@ static long_int | |||
| 206 | ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1, | 208 | ydhms_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. */ | ||
| 257 | static struct tm * | 260 | static struct tm * |
| 258 | convert_time (struct tm *(*convert) (const __time64_t *, struct tm *), | 261 | convert_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. */ | ||
| 270 | static struct tm * | 278 | static struct tm * |
| 271 | ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *), | 279 | ranged_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 | ||
