[PROPOSED] Don't mistruncate TZif files at leap seconds

Without this fix, zic mishandles the command ‘zic -L leapseconds -r @1706745601 etcetera’ when ‘leapseconds’ is generated from the test data file mentioned in: https://mm.icann.org/pipermail/tz/2021-September/030385.html The resulting, incorrect TZif file causes ‘TZ=Etc/GMT date -r 1706745601’ to output "Thu Feb 1 00:00:01 GMT 2024" instead of the correct "Thu Feb 1 00:00:00 GMT 2024", because localtime misinterprets the leap second entry at 1706745601 to be a positive instead of a negative leap second. * NEWS: Mention the fix. * zic.c (limitrange): When omitting leading leap seconds, do not output a leap second table that starts with a positive leap second with a nonpositive correction (or with a negative leap second with a positive correction) as that will confuse TZif readers into thinking the positive leap second is negative or vice versa. Instead, keep otherwise-unnecessary leading leap seconds to avoid the confusion. --- NEWS | 6 ++++++ zic.c | 14 ++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 62a7ba2..9983f11 100644 --- a/NEWS +++ b/NEWS @@ -137,6 +137,12 @@ Unreleased, experimental changes last time transition disagreed with the TZ string, contrary to Internet RFC 8563 section 3.3. + Fix a bug with 'zic -r @X' when X is a negative leap second that + has a nonnegative correction. Without the fix, the output file + was truncated so that X appeared to be a positive leap second. + Fix a similar, even-less-likely bug when truncating at a positive + leap second that has a nonpositive correction. + zic -r now reports an error if given rolling leap seconds, as this usage has never generally worked and is evidently unused. diff --git a/zic.c b/zic.c index b06ef66..c6feb8b 100644 --- a/zic.c +++ b/zic.c @@ -1972,12 +1972,22 @@ limitrange(struct timerange r, bool locut, zic_t lo, zic_t hi, r.base++; } - /* Omit as many leap seconds < LO as possible, such that the first - leap second in the truncated list is <= LO. */ + /* Omit as many initial leap seconds as possible, such that the + first leap second in the truncated list is <= LO, and is a + positive leap second if and only if it has a positive correction. + This supports common TZif readers that assume that the first leap + second is positive if and only if its correction is positive. */ while (1 < r.leapcount && trans[r.leapbase + 1] <= lo) { r.leapcount--; r.leapbase++; } + while (0 < r.leapbase + && ((corr[r.leapbase - 1] < corr[r.leapbase]) + != (0 < corr[r.leapbase]))) { + r.leapcount++; + r.leapbase--; + } + /* Omit ordinary and leap second transitions greater than HI + 1. */ if (hi < ZIC_MAX) { -- 2.30.2
participants (1)
-
Paul Eggert