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

Paul Eggert eggert at cs.ucla.edu
Tue Sep 14 08:34:20 UTC 2021


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



More information about the tz mailing list