summaryrefslogtreecommitdiff
path: root/backport-mktime-improve-heuristic-for-ca-1986-Indiana-DST.patch
diff options
context:
space:
mode:
Diffstat (limited to 'backport-mktime-improve-heuristic-for-ca-1986-Indiana-DST.patch')
-rw-r--r--backport-mktime-improve-heuristic-for-ca-1986-Indiana-DST.patch78
1 files changed, 78 insertions, 0 deletions
diff --git a/backport-mktime-improve-heuristic-for-ca-1986-Indiana-DST.patch b/backport-mktime-improve-heuristic-for-ca-1986-Indiana-DST.patch
new file mode 100644
index 0000000..0142918
--- /dev/null
+++ b/backport-mktime-improve-heuristic-for-ca-1986-Indiana-DST.patch
@@ -0,0 +1,78 @@
+From 675ba1f361ea424626b48a40cfd24d113dfc1b65 Mon Sep 17 00:00:00 2001
+From: Paul Eggert <eggert@cs.ucla.edu>
+Date: Thu, 8 Sep 2022 20:08:32 -0500
+Subject: [PATCH] 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)
+---
+ time/mktime.c | 28 ++++++++++++++++++++--------
+ 1 file changed, 20 insertions(+), 8 deletions(-)
+
+diff --git a/time/mktime.c b/time/mktime.c
+index 8e78006eea..74d9bbaa5b 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;
+ }
+--
+2.43.5
+