You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
73 lines
3.1 KiB
73 lines
3.1 KiB
commit 675ba1f361ea424626b48a40cfd24d113dfc1b65 |
|
Author: Paul Eggert <eggert@cs.ucla.edu> |
|
Date: Thu Sep 8 20:08:32 2022 -0500 |
|
|
|
mktime: improve heuristic for ca-1986 Indiana DST |
|
|
|
This patch syncs mktime.c from Gnulib, fixing a |
|
problem reported by Mark Krenz <https://bugs.gnu.org/48085>, |
|
and it should fix BZ#29035 too. |
|
* time/mktime.c (__mktime_internal): Be more generous about |
|
accepting arguments with the wrong value of tm_isdst, by falling |
|
back to a one-hour DST difference if we find no nearby DST that is |
|
unusual. This fixes a problem where "1986-04-28 00:00 EDT" was |
|
rejected when TZ="America/Indianapolis" because the nearest DST |
|
timestamp occurred in 1970, a temporal distance too great for the |
|
old heuristic. This also also narrows the search a bit, which |
|
is a minor performance win. |
|
|
|
(cherry picked from commit 83859e1115269cf56d21669361d4ddbe2687831c) |
|
|
|
diff --git a/time/mktime.c b/time/mktime.c |
|
index 8e78006eea7e693b..74d9bbaa5b375723 100644 |
|
--- a/time/mktime.c |
|
+++ b/time/mktime.c |
|
@@ -429,8 +429,13 @@ __mktime_internal (struct tm *tp, |
|
time with the right value, and use its UTC offset. |
|
|
|
Heuristic: probe the adjacent timestamps in both directions, |
|
- looking for the desired isdst. This should work for all real |
|
- time zone histories in the tz database. */ |
|
+ looking for the desired isdst. If none is found within a |
|
+ reasonable duration bound, assume a one-hour DST difference. |
|
+ This should work for all real time zone histories in the tz |
|
+ database. */ |
|
+ |
|
+ /* +1 if we wanted standard time but got DST, -1 if the reverse. */ |
|
+ int dst_difference = (isdst == 0) - (tm.tm_isdst == 0); |
|
|
|
/* Distance between probes when looking for a DST boundary. In |
|
tzdata2003a, the shortest period of DST is 601200 seconds |
|
@@ -441,12 +446,14 @@ __mktime_internal (struct tm *tp, |
|
periods when probing. */ |
|
int stride = 601200; |
|
|
|
- /* The longest period of DST in tzdata2003a is 536454000 seconds |
|
- (e.g., America/Jujuy starting 1946-10-01 01:00). The longest |
|
- period of non-DST is much longer, but it makes no real sense |
|
- to search for more than a year of non-DST, so use the DST |
|
- max. */ |
|
- int duration_max = 536454000; |
|
+ /* In TZDB 2021e, the longest period of DST (or of non-DST), in |
|
+ which the DST (or adjacent DST) difference is not one hour, |
|
+ is 457243209 seconds: e.g., America/Cambridge_Bay with leap |
|
+ seconds, starting 1965-10-31 00:00 in a switch from |
|
+ double-daylight time (-05) to standard time (-07), and |
|
+ continuing to 1980-04-27 02:00 in a switch from standard time |
|
+ (-07) to daylight time (-06). */ |
|
+ int duration_max = 457243209; |
|
|
|
/* Search in both directions, so the maximum distance is half |
|
the duration; add the stride to avoid off-by-1 problems. */ |
|
@@ -483,6 +490,11 @@ __mktime_internal (struct tm *tp, |
|
} |
|
} |
|
|
|
+ /* No unusual DST offset was found nearby. Assume one-hour DST. */ |
|
+ t += 60 * 60 * dst_difference; |
|
+ if (mktime_min <= t && t <= mktime_max && convert_time (convert, t, &tm)) |
|
+ goto offset_found; |
|
+ |
|
__set_errno (EOVERFLOW); |
|
return -1; |
|
}
|
|
|