Sync our copy of the timezone library with IANA release tzcode2017b.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 30 Apr 2017 19:13:51 +0000 (15:13 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 30 Apr 2017 19:14:06 +0000 (15:14 -0400)
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.

There are assorted cosmetic changes as well, notably relocation
of a bunch of #defines.

src/timezone/README
src/timezone/localtime.c
src/timezone/pgtz.c
src/timezone/private.h
src/timezone/strftime.c
src/timezone/tzfile.h
src/timezone/zic.c

index a82d77c7baf8237617d4a377b5cbb2cf7c1f55e1..2544230c4cd639a8fce67d6f7152566ecfb955e3 100644 (file)
@@ -50,7 +50,7 @@ match properly on the old version.
 Time Zone code
 ==============
 
-The code in this directory is currently synced with tzcode release 2016j.
+The code in this directory is currently synced with tzcode release 2017b.
 There are many cosmetic (and not so cosmetic) differences from the
 original tzcode library, but diffs in the upstream version should usually
 be propagated to our version.  Here are some notes about that.
index ae9c2d23e631e5cff2981f0131a3b72df4319d59..6e0fa10066c4625524fbc445f93ae022ee5cf8aa 100644 (file)
@@ -17,8 +17,9 @@
 #include <fcntl.h>
 
 #include "datatype/timestamp.h"
-#include "private.h"
 #include "pgtz.h"
+
+#include "private.h"
 #include "tzfile.h"
 
 
@@ -414,10 +415,10 @@ tzloadbody(char const * name, char *canonname, struct state * sp, bool doextend,
                {
                        /*
                         * 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 AHDT YST AKDT AKST) and ts->charcnt equals 10 (for
-                        * AKST AKDT).  Reusing means sp->charcnt can stay 42 in 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 40 in this
                         * example.
                         */
                        int                     gotabbr = 0;
@@ -451,6 +452,17 @@ tzloadbody(char const * name, char *canonname, struct state * sp, bool doextend,
                        if (gotabbr == 2)
                        {
                                sp->charcnt = charcnt;
+
+                               /*
+                                * Ignore any trailing, no-op transitions generated by zic as
+                                * they don't help here and can run afoul of bugs in zic 2016j
+                                * or earlier.
+                                */
+                               while (1 < sp->timecnt
+                                          && (sp->types[sp->timecnt - 1]
+                                                  == sp->types[sp->timecnt - 2]))
+                                       sp->timecnt--;
+
                                for (i = 0; i < ts->timecnt; i++)
                                        if (sp->ats[sp->timecnt - 1] < ts->ats[i])
                                                break;
@@ -974,6 +986,8 @@ tzparse(const char *name, struct state * sp, bool lastditch)
                        int                     yearlim;
                        int                     timecnt;
                        pg_time_t       janfirst;
+                       int32           janoffset = 0;
+                       int                     yearbeg;
 
                        ++name;
                        if ((name = getrule(name, &start)) == NULL)
@@ -994,8 +1008,23 @@ 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
+                       {
+                               int32           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++)
                        {
                                int32
                                                        starttime = transtime(year, &start, stdoffset),
@@ -1020,24 +1049,34 @@ tzparse(const char *name, struct state * sp, bool lastditch)
                                {
                                        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->typecnt = 1;        /* Perpetual DST.  */
+                       else if (YEARSPERREPEAT < year - yearbeg)
+                               sp->goback = sp->goahead = true;
                }
                else
                {
index 4fa3d0da89c92335e91b5a26a4e0bf2368cf553c..982fc1fe718aa0db2fcdc3f38dbc053b41663fb7 100644 (file)
@@ -17,6 +17,7 @@
 #include <sys/stat.h>
 #include <time.h>
 
+#include "datatype/timestamp.h"
 #include "miscadmin.h"
 #include "pgtz.h"
 #include "storage/fd.h"
@@ -308,14 +309,14 @@ pg_tzset_offset(long gmtoffset)
        char            tzname[128];
 
        snprintf(offsetstr, sizeof(offsetstr),
-                        "%02ld", absoffset / SECSPERHOUR);
-       absoffset %= SECSPERHOUR;
+                        "%02ld", absoffset / SECS_PER_HOUR);
+       absoffset %= SECS_PER_HOUR;
        if (absoffset != 0)
        {
                snprintf(offsetstr + strlen(offsetstr),
                                 sizeof(offsetstr) - strlen(offsetstr),
-                                ":%02ld", absoffset / SECSPERMIN);
-               absoffset %= SECSPERMIN;
+                                ":%02ld", absoffset / SECS_PER_MINUTE);
+               absoffset %= SECS_PER_MINUTE;
                if (absoffset != 0)
                        snprintf(offsetstr + strlen(offsetstr),
                                         sizeof(offsetstr) - strlen(offsetstr),
index b8533d51e83a299ca9052a45068b8dda7623dbc8..f031b17b7eff0ecab9c55ad04a962679f8c072c3 100644 (file)
@@ -67,14 +67,8 @@ extern int   unlink(const char *filename);
  * Finally, some convenience items.
  */
 
-#ifndef TYPE_BIT
 #define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
-#endif   /* !defined TYPE_BIT */
-
-#ifndef TYPE_SIGNED
 #define TYPE_SIGNED(type) (((type) -1) < 0)
-#endif   /* !defined TYPE_SIGNED */
-
 #define TWOS_COMPLEMENT(t) ((t) ~ (t) 0 < 0)
 
 /*
@@ -88,7 +82,6 @@ extern int    unlink(const char *filename);
 #define MINVAL(t, b)                                           \
   ((t) (TYPE_SIGNED(t) ? - TWOS_COMPLEMENT(t) - MAXVAL(t, b) : 0))
 
-#ifndef INT_STRLEN_MAXIMUM
 /*
  * 302 / 1000 is log10(2.0) rounded up.
  * Subtract one for the sign bit if the type is signed;
@@ -98,7 +91,6 @@ extern int    unlink(const char *filename);
 #define INT_STRLEN_MAXIMUM(type) \
        ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
        1 + TYPE_SIGNED(type))
-#endif   /* !defined INT_STRLEN_MAXIMUM */
 
 /*
  * INITIALIZE(x)
@@ -108,24 +100,70 @@ extern int        unlink(const char *filename);
 #undef _
 #define _(msgid) (msgid)
 
-#ifndef YEARSPERREPEAT
+/* Handy macros that are independent of tzfile implementation.  */
+
 #define YEARSPERREPEAT         400 /* years before a Gregorian repeat */
-#endif   /* !defined YEARSPERREPEAT */
+
+#define SECSPERMIN     60
+#define MINSPERHOUR 60
+#define HOURSPERDAY 24
+#define DAYSPERWEEK 7
+#define DAYSPERNYEAR   365
+#define DAYSPERLYEAR   366
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY     ((int32) SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR 12
+
+#define TM_SUNDAY      0
+#define TM_MONDAY      1
+#define TM_TUESDAY     2
+#define TM_WEDNESDAY   3
+#define TM_THURSDAY 4
+#define TM_FRIDAY      5
+#define TM_SATURDAY 6
+
+#define TM_JANUARY     0
+#define TM_FEBRUARY 1
+#define TM_MARCH       2
+#define TM_APRIL       3
+#define TM_MAY         4
+#define TM_JUNE                5
+#define TM_JULY                6
+#define TM_AUGUST      7
+#define TM_SEPTEMBER   8
+#define TM_OCTOBER     9
+#define TM_NOVEMBER 10
+#define TM_DECEMBER 11
+
+#define TM_YEAR_BASE   1900
+
+#define EPOCH_YEAR     1970
+#define EPOCH_WDAY     TM_THURSDAY
+
+#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
 
 /*
- * The Gregorian year averages 365.2425 days, which is 31556952 seconds.
+ * Since everything in isleap is modulo 400 (or a factor of 400), we know that
+ *     isleap(y) == isleap(y % 400)
+ * and so
+ *     isleap(a + b) == isleap((a + b) % 400)
+ * or
+ *     isleap(a + b) == isleap(a % 400 + b % 400)
+ * This is true even if % means modulo rather than Fortran remainder
+ * (which is allowed by C89 but not C99).
+ * We use this to avoid addition overflow problems.
  */
 
-#ifndef AVGSECSPERYEAR
-#define AVGSECSPERYEAR         31556952L
-#endif   /* !defined AVGSECSPERYEAR */
+#define isleap_sum(a, b)       isleap((a) % 400 + (b) % 400)
 
-#ifndef SECSPERREPEAT
-#define SECSPERREPEAT          ((int64) YEARSPERREPEAT * (int64) AVGSECSPERYEAR)
-#endif   /* !defined SECSPERREPEAT */
 
-#ifndef SECSPERREPEAT_BITS
+/*
+ * The Gregorian year averages 365.2425 days, which is 31556952 seconds.
+ */
+
+#define AVGSECSPERYEAR         31556952L
+#define SECSPERREPEAT \
+  ((int64) YEARSPERREPEAT * (int64) AVGSECSPERYEAR)
 #define SECSPERREPEAT_BITS     34      /* ceil(log2(SECSPERREPEAT)) */
-#endif   /* !defined SECSPERREPEAT_BITS */
 
 #endif   /* !defined PRIVATE_H */
index 4a0a01db651962c8e0b8c074f7a71cb540609107..ab8f60e9c8f36bbcff74e8653c4de6c9b4e96626 100644 (file)
@@ -1,4 +1,4 @@
-/* Convert a broken-down time stamp to a string. */
+/* Convert a broken-down timestamp to a string. */
 
 /*
  * Copyright 1989 The Regents of the University of California.
@@ -44,7 +44,6 @@
 #include <locale.h>
 
 #include "private.h"
-#include "tzfile.h"
 
 
 struct lc_time_T
@@ -452,11 +451,17 @@ _fmt(const char *format, const struct pg_tm * t, char *pt, const char *ptlim,
                                        {
                                                long            diff;
                                                char const *sign;
+                                               bool            negative;
 
                                                if (t->tm_isdst < 0)
                                                        continue;
                                                diff = t->tm_gmtoff;
-                                               if (diff < 0)
+                                               negative = diff < 0;
+                                               if (diff == 0)
+                                               {
+                                                       negative = t->tm_zone[0] == '-';
+                                               }
+                                               if (negative)
                                                {
                                                        sign = "-";
                                                        diff = -diff;
index 32d237b8270ae1960449f096c94adc236eccbbb5..56a5b43472760a127e7e49b296adaf225ad2f5a4 100644 (file)
@@ -100,56 +100,4 @@ struct tzhead
 
 #define TZ_MAX_LEAPS   50              /* Maximum number of leap second corrections */
 
-#define SECSPERMIN     60
-#define MINSPERHOUR 60
-#define HOURSPERDAY 24
-#define DAYSPERWEEK 7
-#define DAYSPERNYEAR   365
-#define DAYSPERLYEAR   366
-#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
-#define SECSPERDAY     ((int32) SECSPERHOUR * HOURSPERDAY)
-#define MONSPERYEAR 12
-
-#define TM_SUNDAY      0
-#define TM_MONDAY      1
-#define TM_TUESDAY     2
-#define TM_WEDNESDAY   3
-#define TM_THURSDAY 4
-#define TM_FRIDAY      5
-#define TM_SATURDAY 6
-
-#define TM_JANUARY     0
-#define TM_FEBRUARY 1
-#define TM_MARCH       2
-#define TM_APRIL       3
-#define TM_MAY         4
-#define TM_JUNE                5
-#define TM_JULY                6
-#define TM_AUGUST      7
-#define TM_SEPTEMBER   8
-#define TM_OCTOBER     9
-#define TM_NOVEMBER 10
-#define TM_DECEMBER 11
-
-#define TM_YEAR_BASE   1900
-
-#define EPOCH_YEAR     1970
-#define EPOCH_WDAY     TM_THURSDAY
-
-#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
-
-/*
- * Since everything in isleap is modulo 400 (or a factor of 400), we know that
- *       isleap(y) == isleap(y % 400)
- * and so
- *       isleap(a + b) == isleap((a + b) % 400)
- * or
- *       isleap(a + b) == isleap(a % 400 + b % 400)
- * This is true even if % means modulo rather than Fortran remainder
- * (which is allowed by C89 but not C99).
- * We use this to avoid addition overflow problems.
- */
-
-#define isleap_sum(a, b)       isleap((a) % 400 + (b) % 400)
-
 #endif   /* !defined TZFILE_H */
index a83cea12ddc196a102519efd49cf79ec177fd2b7..f6beedcab2a58a8819c8e62f02ec027441821c90 100644 (file)
@@ -2672,6 +2672,9 @@ outzone(const struct zone * zpfirst, ptrdiff_t zonecount)
        bool            do_extend;
        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;
@@ -2781,12 +2784,13 @@ outzone(const struct zone * zpfirst, ptrdiff_t zonecount)
        }
 
        /*
-        * For the benefit of older systems, generate data from 1900 through 2037.
+        * For the benefit of older systems, 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)
        {
                /*
@@ -2836,7 +2840,12 @@ outzone(const struct zone * zpfirst, ptrdiff_t zonecount)
                                                year <= rp->r_hiyear &&
                                                yearistype(year, rp->r_yrtype);
                                        if (rp->r_todo)
+                                       {
                                                rp->r_temp = rpytime(rp, year);
+                                               rp->r_todo
+                                                       = (rp->r_temp < y2038_boundary
+                                                          || year <= max_year0);
+                                       }
                                }
                                for (;;)
                                {