[tz] [PATCH 1/7] localtime.c is less finicky about leap seconds

Paul Eggert eggert at cs.ucla.edu
Wed Mar 17 01:45:59 UTC 2021


* localtime.c (tzloadbody): Do not reject a TZif file merely
because its leap second table contains adjacent entries with
equal corrections, or contains a first entry with a correction
value other than +1 or -1.
* NEWS: Mention this.
---
 NEWS        |  5 +++++
 localtime.c | 13 ++++++++++---
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/NEWS b/NEWS
index 0de05f3..d8676e6 100644
--- a/NEWS
+++ b/NEWS
@@ -39,6 +39,11 @@ Unreleased, experimental changes
     seconds error than with an hour error, so zic -L no longer
     truncates output in this way.
 
+    The TZif reader now allows the leap second table to begin with a
+    correction other than -1 or +1, and to contain adjacent
+    transitions with equal corrections.  This supports possible
+    future extensions to the TZif format.
+
     Fix bug that caused 'localtime' etc. to crash when TZ was
     set to a all-year DST string like "EST5EDT4,0/0,J365/25" that does
     not conform to POSIX but does conform to Internet RFC 8536.
diff --git a/localtime.c b/localtime.c
index 6627ff2..a086d4d 100644
--- a/localtime.c
+++ b/localtime.c
@@ -445,7 +445,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
 		int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
 		int_fast32_t ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt);
 		int_fast64_t prevtr = 0;
-		int_fast32_t prevcorr = 0;
+		int_fast32_t prevcorr;
 		int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt);
 		int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt);
 		int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt);
@@ -542,9 +542,16 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
 		       and UTC months are at least 28 days long (minus 1
 		       second for a negative leap second).  Each leap second's
 		       correction must differ from the previous one's by 1
-		       second.  */
+		       second or less, except that the first correction can be
+		       any value; these requirements are more generous than
+		       RFC 8536, to allow future RFC extensions.  */
 		    if (tr - prevtr < 28 * SECSPERDAY - 1
-			|| (corr != prevcorr - 1 && corr != prevcorr + 1))
+			|| ((timecnt == 0 || sp->ats[0] < tr)
+			    && ! (i == 0
+				  || (prevcorr < corr
+				      ? corr == prevcorr + 1
+				      : (corr == prevcorr
+					 || corr == prevcorr - 1)))))
 		      return EINVAL;
 		    sp->lsis[leapcnt].ls_trans = prevtr = tr;
 		    sp->lsis[leapcnt].ls_corr = prevcorr = corr;
-- 
2.27.0



More information about the tz mailing list