[tz] question about mktime_tzname()

Paul Eggert eggert at cs.ucla.edu
Thu Jan 12 16:41:38 UTC 2017


On 01/11/2017 02:06 PM, Arthur David Olson wrote:
> > Unfortunately now that I think of it, I see that this can't work on
> > hosts with 32-bit time_t, as they can't cover the 400-year span.  So the
> > code is still broken on 32-bit hosts. Is there a better way to fix
> the code?
>
> Since 32-bit time_t values can only cover (about) 140 years, not
> covering a 400-year span's not a bug, it's a given.-)

Yes, but unfortunately the code in localtime.c filled in the table only
for the years 1970-2038, and this the 68-year filled-in period was not
enough to make the goback code work correctly (it needs 400 years). I
installed the attached patch to try to fix this; it handles Kees
Dekker's test case correctly on hosts with 32-bit time_t.

-------------- next part --------------
From 11d493ae597f7f3e41afa441b93848aa2281209c Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert at cs.ucla.edu>
Date: Thu, 12 Jan 2017 08:34:21 -0800
Subject: [PATCH] Fix bug for pre-1970 POSIX DST, 32-bit time_t
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* localtime.c (tzparse): Fill in the table before 1970, if
POSIX DST is specified.  This is needed on 32-bit platforms,
since they don’t have the time_t space for a 400-year repeat.
This finishes the fix for the problem reported by Kees Dekker in:
http://mm.icann.org/pipermail/tz/2017-January/024736.html
---
 localtime.c | 50 +++++++++++++++++++++++++++++++++++---------------
 1 file changed, 35 insertions(+), 15 deletions(-)

diff --git a/localtime.c b/localtime.c
index 5f63801..3967e90 100644
--- a/localtime.c
+++ b/localtime.c
@@ -1080,6 +1080,8 @@ tzparse(const char *name, struct state *sp, bool lastditch)
 			register int	yearlim;
 			register int	timecnt;
 			time_t		janfirst;
+			int_fast32_t janoffset = 0;
+			int yearbeg;
 
 			++name;
 			if ((name = getrule(name, &start)) == NULL)
@@ -1099,8 +1101,20 @@ tzparse(const char *name, struct state *sp, bool lastditch)
 			sp->defaulttype = 0;
 			timecnt = 0;
 			janfirst = 0;
-			yearlim = EPOCH_YEAR + YEARSPERREPEAT;
-			for (year = EPOCH_YEAR; year < yearlim; year++) {
+			yearbeg = EPOCH_YEAR;
+
+			do {
+			  int_fast32_t yearsecs
+			    = year_lengths[isleap(yearbeg - 1)] * SECSPERDAY;
+			  yearbeg--;
+			  if (increment_overflow_time(&janfirst, -yearsecs)) {
+			    janoffset = -yearsecs;
+			    break;
+			  }
+			} while (EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg);
+
+			yearlim = yearbeg + YEARSPERREPEAT + 1;
+			for (year = yearbeg; year < yearlim; year++) {
 				int_fast32_t
 				  starttime = transtime(year, &start, stdoffset),
 				  endtime = transtime(year, &end, dstoffset);
@@ -1120,26 +1134,32 @@ tzparse(const char *name, struct state *sp, bool lastditch)
 					       + (stdoffset - dstoffset))))) {
 					if (TZ_MAX_TIMES - 2 < timecnt)
 						break;
-					yearlim = year + YEARSPERREPEAT + 1;
 					sp->ats[timecnt] = janfirst;
-					if (increment_overflow_time
-					    (&sp->ats[timecnt], starttime))
-						break;
-					sp->types[timecnt++] = reversed;
+					if (! increment_overflow_time
+					    (&sp->ats[timecnt],
+					     janoffset + starttime))
+					  sp->types[timecnt++] = reversed;
+					else if (janoffset)
+					  sp->defaulttype = reversed;
 					sp->ats[timecnt] = janfirst;
-					if (increment_overflow_time
-					    (&sp->ats[timecnt], endtime))
-						break;
-					sp->types[timecnt++] = !reversed;
+					if (! increment_overflow_time
+					    (&sp->ats[timecnt],
+					     janoffset + endtime)) {
+					  sp->types[timecnt++] = !reversed;
+					  yearlim = year + YEARSPERREPEAT + 1;
+					} else if (janoffset)
+					  sp->defaulttype = !reversed;
 				}
-				if (increment_overflow_time(&janfirst, yearsecs))
+				if (increment_overflow_time
+				    (&janfirst, janoffset + yearsecs))
 					break;
+				janoffset = 0;
 			}
 			sp->timecnt = timecnt;
-			if (timecnt)
-				sp->goback = sp->goahead = true;
-			else
+			if (! timecnt)
 				sp->typecnt = 1;	/* Perpetual DST.  */
+			else if (YEARSPERREPEAT < year - yearbeg)
+				sp->goback = sp->goahead = true;
 		} else {
 			register int_fast32_t	theirstdoffset;
 			register int_fast32_t	theirdstoffset;
-- 
2.9.3


More information about the tz mailing list