From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1211) id 3F7B13858436; Fri, 9 Sep 2022 03:56:20 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3F7B13858436 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1662695780; bh=HYHkAxGTQ6gql4c2rmJldyWPZzlY5ir4M14Tp5LjOMQ=; h=From:To:Subject:Date:From; b=a5xQc8uhBovw++eTcKxCwgnrYk7FQGN344PIY7RcZ5JjBks8ivz81kgm5dmG6+TnL UmCCZhfvAzgLiKyhW9cnt2gB+iHlQcGTXdg9Yq/jIVeXL2rfovXfuOqeHe5VBQPG+5 RjK9eu93nqiz6qgDEW3h5a6LRhoGE97hiIPODhzc= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Paul Eggert To: glibc-cvs@sourceware.org Subject: [glibc] mktime: improve heuristic for ca-1986 Indiana DST X-Act-Checkin: glibc X-Git-Author: Paul Eggert X-Git-Refname: refs/heads/master X-Git-Oldrev: 82a1ec851025ccae54dea43149915707f890746b X-Git-Newrev: 83859e1115269cf56d21669361d4ddbe2687831c Message-Id: <20220909035620.3F7B13858436@sourceware.org> Date: Fri, 9 Sep 2022 03:56:20 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=83859e1115269cf56d21669361d4ddbe2687831c commit 83859e1115269cf56d21669361d4ddbe2687831c Author: Paul Eggert 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 , 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. Diff: --- time/mktime.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/time/mktime.c b/time/mktime.c index aa12e28e16..7dc9d67ef9 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; }