[tz] [PROPOSED 1/3] Fix leap second bug after last explicit transition

Paul Eggert eggert at cs.ucla.edu
Wed Jan 15 02:23:01 UTC 2020


The client code mishandled timestamps after the last explicit
transition in a TZif file that had both leap seconds and daylight
saving time transitions projected into the indefinite future.
When interpreting the TZ string embedded at the end of the TZif
file, the code neglected to adjust the corresponding DST
transitions for leap seconds, which meant the DST transitions were
calculated to occur too early.  For example, with TZ set to
'.../zoneinfo-leaps/America/Los_Angeles', zdump reported a DST
transition on 2038-03-14 from 01:59:32.999... to 02:59:33 instead
of the correct transition from 01:59:59.999... to 03:00:00.
* NEWS: Mention this.
* localtime.c (tzloadbody): Apply leap second corrections to
transitions derived from the trailing TZ string in a TZif file.
(leapcorr) [!STD_INSPIRED]: Define in this case too, since
tzloadbody now uses it.
---
 NEWS        |  8 ++++++++
 localtime.c | 35 +++++++++++++++++++----------------
 2 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/NEWS b/NEWS
index 961aa08..72e5c04 100644
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,14 @@ Unreleased, experimental changes
 
   Changes to code
 
+    localtime.c no longer mishandles timestamps after the last
+    transition in a TZif file with leap seconds and with daylight
+    saving time transitions projected into the indefinite future.
+    For example, with TZ='America/Los_Angeles' with leap seconds,
+    zdump formerly reported a DST transition on 2038-03-14
+    from 01:59:32.999... to 02:59:33 instead of the correct transition
+    from 01:59:59.999... to 03:00:00.
+
     The configuration macros HAVE_TZNAME and USG_COMPAT should now be
     set to 1 if the system library supports the feature, and 2 if not.
     As before, these macros are nonzero if tzcode should support the
diff --git a/localtime.c b/localtime.c
index d3f8fc7..6623eac 100644
--- a/localtime.c
+++ b/localtime.c
@@ -158,6 +158,7 @@ static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
 			 struct tm *);
 static bool increment_overflow(int *, int);
 static bool increment_overflow_time(time_t *, int_fast32_t);
+static int_fast64_t leapcorr(struct state const *, time_t);
 static bool normalize_overflow32(int_fast32_t *, int *, int);
 static struct tm *timesub(time_t const *, int_fast32_t, struct state const *,
 			  struct tm *);
@@ -641,11 +642,13 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
 
 			    for (i = 0; i < ts->timecnt; i++)
 			      if (sp->timecnt == 0
-				  || sp->ats[sp->timecnt - 1] < ts->ats[i])
+				  || (sp->ats[sp->timecnt - 1]
+				      < ts->ats[i] + leapcorr(sp, ts->ats[i])))
 				break;
 			    while (i < ts->timecnt
 				   && sp->timecnt < TZ_MAX_TIMES) {
-			      sp->ats[sp->timecnt] = ts->ats[i];
+			      sp->ats[sp->timecnt]
+				= ts->ats[i] + leapcorr(sp, ts->ats[i]);
 			      sp->types[sp->timecnt] = (sp->typecnt
 							+ ts->types[i]);
 			      sp->timecnt++;
@@ -2239,20 +2242,6 @@ timeoff(struct tm *tmp, long offset)
 
 #endif /* defined STD_INSPIRED */
 
-/*
-** XXX--is the below the right way to conditionalize??
-*/
-
-#ifdef STD_INSPIRED
-
-/*
-** IEEE Std 1003.1 (POSIX) says that 536457599
-** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
-** is not the case if we are accounting for leap seconds.
-** So, we provide the following conversion routines for use
-** when exchanging timestamps with POSIX conforming systems.
-*/
-
 static int_fast64_t
 leapcorr(struct state const *sp, time_t t)
 {
@@ -2268,6 +2257,20 @@ leapcorr(struct state const *sp, time_t t)
 	return 0;
 }
 
+/*
+** XXX--is the below the right way to conditionalize??
+*/
+
+#ifdef STD_INSPIRED
+
+/*
+** IEEE Std 1003.1 (POSIX) says that 536457599
+** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
+** is not the case if we are accounting for leap seconds.
+** So, we provide the following conversion routines for use
+** when exchanging timestamps with POSIX conforming systems.
+*/
+
 NETBSD_INSPIRED_EXTERN time_t
 time2posix_z(struct state *sp, time_t t)
 {
-- 
2.24.1



More information about the tz mailing list