From 00c96cbb21bfeb37f9b8ec13de37b2cefb999fba Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 2 May 2024 10:09:53 -0700 Subject: [PROPOSED] Conform to RFC 8536 section 3.2 for default type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove a heuristic for reading TZif files that were generated by tzcode 2018e and earlier. The heuristic was designed to work around problems with these TZif files, which caused localtime in some cases to misbehave for early timestamps before the first transition. Although helpful for reading nonstandard old data, the heuristic causes localtime to fail to conform to Internet RFC 8536 section 3.2, which says “Local time for timestamps before the first transition is specified by the first time type (time type 0).” Nowadays it is safe to assume tzcode 2018f or later, so there is no need for this nonstandard heuristic. * NEWS: Mention this. * localtime.c (struct state): Remove defaulttype member. All uses removed, and replaced by 0. --- NEWS | 13 ++++++++++++ localtime.c | 61 +---------------------------------------------------- 2 files changed, 14 insertions(+), 60 deletions(-) diff --git a/NEWS b/NEWS index 0d6a1513..5c2cd1e5 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ Unreleased, experimental changes Briefly: The main data form now uses %z. + The code now conforms to RFC 8536 for early timestamps. Improve historical data for Portugal and possessions. Changes to data @@ -25,6 +26,18 @@ Unreleased, experimental changes has been removed, as it now agrees with America/Nuuk due to its 2024-03-31 time zone change. + Changes to code + + localtime.c now always uses a TZif file's time type 0 to handle + timestamps before the file's first transition. Formerly, + localtime.c sometimes inferred a different time type, in order to + handle problematic data generated by zic 2018e or earlier. As it + is now safe to assume more recent versions of zic, there is no + longer a pressing need to fail to conform RFC 8536 section 3.2, + which requires using time type 0 in this situation. This change + does not affect behavior when reading TZif files generated by zic + 2018f and later. + Release 2024a - 2024-02-01 09:28:56 -0800 diff --git a/localtime.c b/localtime.c index 265c0535..6d8030cd 100644 --- a/localtime.c +++ b/localtime.c @@ -130,11 +130,6 @@ struct state { char chars[max(max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof "UTC"), 2 * (TZNAME_MAXIMUM + 1))]; struct lsinfo lsis[TZ_MAX_LEAPS]; - - /* The time type to use for early times or if no transitions. - It is always zero for recent tzdb releases. - It might be nonzero for data from tzdb 2018e or earlier. */ - int defaulttype; }; enum r_type { @@ -710,58 +705,6 @@ tzloadbody(char const *name, struct state *sp, bool doextend, if (sp->typecnt == 0) return EINVAL; - /* Infer sp->defaulttype from the data. Although this default - type is always zero for data from recent tzdb releases, - things are trickier for data from tzdb 2018e or earlier. - - The first set of heuristics work around bugs in 32-bit data - generated by tzdb 2013c or earlier. The workaround is for - zones like Australia/Macquarie where timestamps before the - first transition have a time type that is not the earliest - standard-time type. See: - https://mm.icann.org/pipermail/tz/2013-May/019368.html */ - /* - ** If type 0 does not specify local time, or is unused in transitions, - ** it's the type to use for early times. - */ - for (i = 0; i < sp->timecnt; ++i) - if (sp->types[i] == 0) - break; - i = i < sp->timecnt && ! ttunspecified(sp, 0) ? -1 : 0; - /* - ** Absent the above, - ** if there are transition times - ** and the first transition is to a daylight time - ** find the standard type less than and closest to - ** the type of the first transition. - */ - if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) { - i = sp->types[0]; - while (--i >= 0) - if (!sp->ttis[i].tt_isdst) - break; - } - /* The next heuristics are for data generated by tzdb 2018e or - earlier, for zones like EST5EDT where the first transition - is to DST. */ - /* - ** If no result yet, find the first standard type. - ** If there is none, punt to type zero. - */ - if (i < 0) { - i = 0; - while (sp->ttis[i].tt_isdst) - if (++i >= sp->typecnt) { - i = 0; - break; - } - } - /* A simple 'sp->defaulttype = 0;' would suffice here if we - didn't have to worry about 2018e-or-earlier data. Even - simpler would be to remove the defaulttype member and just - use 0 in its place. */ - sp->defaulttype = i; - return 0; } @@ -1344,7 +1287,6 @@ tzparse(const char *name, struct state *sp, struct state const *basep) sp->timecnt = 0; init_ttinfo(&sp->ttis[0], -stdoffset, false, 0); } - sp->defaulttype = 0; sp->charcnt = charcnt; cp = sp->chars; memcpy(cp, stdname, stdlen); @@ -1380,7 +1322,6 @@ zoneinit(struct state *sp, char const *name) sp->goback = sp->goahead = false; init_ttinfo(&sp->ttis[0], 0, false, 0); strcpy(sp->chars, utc); - sp->defaulttype = 0; return 0; } else { int err = tzload(name, sp, true); @@ -1555,7 +1496,7 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname, return result; } if (sp->timecnt == 0 || t < sp->ats[0]) { - i = sp->defaulttype; + i = 0; } else { register int lo = 1; register int hi = sp->timecnt; -- 2.44.0