>From 9c32443c5d2a40542c637030323728abb6c350c4 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Wed, 4 Jan 2017 23:26:06 -0800
Subject: [PROPOSED] Fix bug in workaround for QTBUG-53071

Problem reported by Bradley White in:
http://mm.icann.org/pipermail/tz/2017-January/024724.html
* NEWS: Document this.
* localtime.c (tzloadbody): Ignore transitions generated due to
WORK_AROUND_QTBUG_53071 in zic.c, since they don't help us
and may hurt if it is zic 2016j or earlier.
* zic.c (outzone): Fill out transitions in 2038, too,
so long as they precede the 2**31 boundary.
---
 NEWS        |  6 ++++++
 localtime.c | 17 +++++++++++++----
 zic.c       | 16 ++++++++++++----
 3 files changed, 31 insertions(+), 8 deletions(-)

diff --git a/NEWS b/NEWS
index 1bd1914..ec1437a 100644
--- a/NEWS
+++ b/NEWS
@@ -64,6 +64,12 @@ Unreleased, experimental changes
 
   Changes to code
 
+    zic no longer mishandles some transitions in January 2038 when it
+    attempts to work around Qt bug 53071.  This fixes a bug affecting
+    Pacific/Tongatapu that was introduced in zic 2016e.  localtime.c
+    now contains a workaround, useful when loading a file generated by
+    a buggy zic.  (Problem reported by Bradley White.)
+
     zdump -i now outputs non-hour numeric time zone abbreviations
     without a colon, e.g., "+0530" rather than "+05:30".  This agrees
     with zic %z and with common practice, and simplifies auditing of
diff --git a/localtime.c b/localtime.c
index 3edd1b3..1568aac 100644
--- a/localtime.c
+++ b/localtime.c
@@ -568,12 +568,12 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
 			    && ts->typecnt == 2) {
 
 			  /* Attempt to reuse existing abbreviations.
-			     Without this, America/Anchorage would stop
-			     working after 2037 when TZ_MAX_CHARS is 50, as
-			     sp->charcnt equals 42 (for LMT CAT CAWT CAPT AHST
+			     Without this, America/Anchorage would be right on
+			     the edge after 2037 when TZ_MAX_CHARS is 50, as
+			     sp->charcnt equals 40 (for LMT AST AWT APT AHST
 			     AHDT YST AKDT AKST) and ts->charcnt equals 10
 			     (for AKST AKDT).  Reusing means sp->charcnt can
-			     stay 42 in this example.  */
+			     stay 40 in this example.  */
 			  int gotabbr = 0;
 			  int charcnt = sp->charcnt;
 			  for (i = 0; i < 2; i++) {
@@ -597,6 +597,15 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
 			  }
 			  if (gotabbr == 2) {
 			    sp->charcnt = charcnt;
+
+			    /* Ignore any transition that was almost surely
+			       generated because of WORK_AROUND_QTBUG_53071 in
+			       zic.c, as it doesn't help here and can run
+			       afoul of bugs in zic 2016j or earlier.  */
+			    if (1 < sp->timecnt
+				&& sp->ats[sp->timecnt - 1] == 0x7fffffff)
+			      sp->timecnt--;
+
 			    for (i = 0; i < ts->timecnt; i++)
 			      if (sp->ats[sp->timecnt - 1] < ts->ats[i])
 				break;
diff --git a/zic.c b/zic.c
index 47c68f9..04798f4 100644
--- a/zic.c
+++ b/zic.c
@@ -2368,6 +2368,9 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
 	register bool			do_extend;
 	register char			version;
 	ptrdiff_t lastatmax = -1;
+	zic_t one = 1;
+	zic_t y2038_boundary = one << 31;
+	zic_t max_year0;
 
 	max_abbr_len = 2 + max_format_len + max_abbrvar_len;
 	max_envvar_len = 2 * max_abbr_len + 5 * 9;
@@ -2463,12 +2466,13 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
 	}
 	/*
 	** For the benefit of older systems,
-	** generate data from 1900 through 2037.
+	** generate data from 1900 through 2038.
 	*/
 	if (min_year > 1900)
 		min_year = 1900;
-	if (max_year < 2037)
-		max_year = 2037;
+	max_year0 = max_year;
+	if (max_year < 2038)
+		max_year = 2038;
 	for (i = 0; i < zonecount; ++i) {
 		/*
 		** A guess that may well be corrected later.
@@ -2507,8 +2511,12 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
 				rp->r_todo = year >= rp->r_loyear &&
 						year <= rp->r_hiyear &&
 						yearistype(year, rp->r_yrtype);
-				if (rp->r_todo)
+				if (rp->r_todo) {
 					rp->r_temp = rpytime(rp, year);
+					rp->r_todo
+					  = (rp->r_temp < y2038_boundary
+					     || year <= max_year0);
+				}
 			}
 			for ( ; ; ) {
 				register ptrdiff_t k;
-- 
2.7.4

