Commit e18b2c48 authored by Tom Lane's avatar Tom Lane

Sync our copy of the timezone library with IANA release tzcode2017b.

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.
parent 12d11432
...@@ -50,7 +50,7 @@ match properly on the old version. ...@@ -50,7 +50,7 @@ match properly on the old version.
Time Zone code 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 There are many cosmetic (and not so cosmetic) differences from the
original tzcode library, but diffs in the upstream version should usually original tzcode library, but diffs in the upstream version should usually
be propagated to our version. Here are some notes about that. be propagated to our version. Here are some notes about that.
......
...@@ -17,8 +17,9 @@ ...@@ -17,8 +17,9 @@
#include <fcntl.h> #include <fcntl.h>
#include "datatype/timestamp.h" #include "datatype/timestamp.h"
#include "private.h"
#include "pgtz.h" #include "pgtz.h"
#include "private.h"
#include "tzfile.h" #include "tzfile.h"
...@@ -414,10 +415,10 @@ tzloadbody(char const * name, char *canonname, struct state * sp, bool doextend, ...@@ -414,10 +415,10 @@ tzloadbody(char const * name, char *canonname, struct state * sp, bool doextend,
{ {
/* /*
* Attempt to reuse existing abbreviations. Without this, * Attempt to reuse existing abbreviations. Without this,
* America/Anchorage would stop working after 2037 when * America/Anchorage would be right on the edge after 2037 when
* TZ_MAX_CHARS is 50, as sp->charcnt equals 42 (for LMT CAT CAWT * TZ_MAX_CHARS is 50, as sp->charcnt equals 40 (for LMT AST AWT
* CAPT AHST AHDT YST AKDT AKST) and ts->charcnt equals 10 (for * APT AHST AHDT YST AKDT AKST) and ts->charcnt equals 10 (for
* AKST AKDT). Reusing means sp->charcnt can stay 42 in this * AKST AKDT). Reusing means sp->charcnt can stay 40 in this
* example. * example.
*/ */
int gotabbr = 0; int gotabbr = 0;
...@@ -451,6 +452,17 @@ tzloadbody(char const * name, char *canonname, struct state * sp, bool doextend, ...@@ -451,6 +452,17 @@ tzloadbody(char const * name, char *canonname, struct state * sp, bool doextend,
if (gotabbr == 2) if (gotabbr == 2)
{ {
sp->charcnt = charcnt; 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++) for (i = 0; i < ts->timecnt; i++)
if (sp->ats[sp->timecnt - 1] < ts->ats[i]) if (sp->ats[sp->timecnt - 1] < ts->ats[i])
break; break;
...@@ -974,6 +986,8 @@ tzparse(const char *name, struct state * sp, bool lastditch) ...@@ -974,6 +986,8 @@ tzparse(const char *name, struct state * sp, bool lastditch)
int yearlim; int yearlim;
int timecnt; int timecnt;
pg_time_t janfirst; pg_time_t janfirst;
int32 janoffset = 0;
int yearbeg;
++name; ++name;
if ((name = getrule(name, &start)) == NULL) if ((name = getrule(name, &start)) == NULL)
...@@ -994,8 +1008,23 @@ tzparse(const char *name, struct state * sp, bool lastditch) ...@@ -994,8 +1008,23 @@ tzparse(const char *name, struct state * sp, bool lastditch)
sp->defaulttype = 0; sp->defaulttype = 0;
timecnt = 0; timecnt = 0;
janfirst = 0; janfirst = 0;
yearlim = EPOCH_YEAR + YEARSPERREPEAT; yearbeg = EPOCH_YEAR;
for (year = EPOCH_YEAR; year < yearlim; 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 int32
starttime = transtime(year, &start, stdoffset), starttime = transtime(year, &start, stdoffset),
...@@ -1020,24 +1049,34 @@ tzparse(const char *name, struct state * sp, bool lastditch) ...@@ -1020,24 +1049,34 @@ tzparse(const char *name, struct state * sp, bool lastditch)
{ {
if (TZ_MAX_TIMES - 2 < timecnt) if (TZ_MAX_TIMES - 2 < timecnt)
break; break;
yearlim = year + YEARSPERREPEAT + 1;
sp->ats[timecnt] = janfirst; sp->ats[timecnt] = janfirst;
if (increment_overflow_time if (!increment_overflow_time
(&sp->ats[timecnt], starttime)) (&sp->ats[timecnt],
break; janoffset + starttime))
sp->types[timecnt++] = reversed; sp->types[timecnt++] = reversed;
else if (janoffset)
sp->defaulttype = reversed;
sp->ats[timecnt] = janfirst; sp->ats[timecnt] = janfirst;
if (increment_overflow_time if (!increment_overflow_time
(&sp->ats[timecnt], endtime)) (&sp->ats[timecnt],
break; janoffset + endtime))
sp->types[timecnt++] = !reversed; {
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; break;
janoffset = 0;
} }
sp->timecnt = timecnt; sp->timecnt = timecnt;
if (!timecnt) if (!timecnt)
sp->typecnt = 1; /* Perpetual DST. */ sp->typecnt = 1; /* Perpetual DST. */
else if (YEARSPERREPEAT < year - yearbeg)
sp->goback = sp->goahead = true;
} }
else else
{ {
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <time.h> #include <time.h>
#include "datatype/timestamp.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "pgtz.h" #include "pgtz.h"
#include "storage/fd.h" #include "storage/fd.h"
...@@ -308,14 +309,14 @@ pg_tzset_offset(long gmtoffset) ...@@ -308,14 +309,14 @@ pg_tzset_offset(long gmtoffset)
char tzname[128]; char tzname[128];
snprintf(offsetstr, sizeof(offsetstr), snprintf(offsetstr, sizeof(offsetstr),
"%02ld", absoffset / SECSPERHOUR); "%02ld", absoffset / SECS_PER_HOUR);
absoffset %= SECSPERHOUR; absoffset %= SECS_PER_HOUR;
if (absoffset != 0) if (absoffset != 0)
{ {
snprintf(offsetstr + strlen(offsetstr), snprintf(offsetstr + strlen(offsetstr),
sizeof(offsetstr) - strlen(offsetstr), sizeof(offsetstr) - strlen(offsetstr),
":%02ld", absoffset / SECSPERMIN); ":%02ld", absoffset / SECS_PER_MINUTE);
absoffset %= SECSPERMIN; absoffset %= SECS_PER_MINUTE;
if (absoffset != 0) if (absoffset != 0)
snprintf(offsetstr + strlen(offsetstr), snprintf(offsetstr + strlen(offsetstr),
sizeof(offsetstr) - strlen(offsetstr), sizeof(offsetstr) - strlen(offsetstr),
......
...@@ -67,14 +67,8 @@ extern int unlink(const char *filename); ...@@ -67,14 +67,8 @@ extern int unlink(const char *filename);
* Finally, some convenience items. * Finally, some convenience items.
*/ */
#ifndef TYPE_BIT
#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT) #define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
#endif /* !defined TYPE_BIT */
#ifndef TYPE_SIGNED
#define TYPE_SIGNED(type) (((type) -1) < 0) #define TYPE_SIGNED(type) (((type) -1) < 0)
#endif /* !defined TYPE_SIGNED */
#define TWOS_COMPLEMENT(t) ((t) ~ (t) 0 < 0) #define TWOS_COMPLEMENT(t) ((t) ~ (t) 0 < 0)
/* /*
...@@ -88,7 +82,6 @@ extern int unlink(const char *filename); ...@@ -88,7 +82,6 @@ extern int unlink(const char *filename);
#define MINVAL(t, b) \ #define MINVAL(t, b) \
((t) (TYPE_SIGNED(t) ? - TWOS_COMPLEMENT(t) - MAXVAL(t, b) : 0)) ((t) (TYPE_SIGNED(t) ? - TWOS_COMPLEMENT(t) - MAXVAL(t, b) : 0))
#ifndef INT_STRLEN_MAXIMUM
/* /*
* 302 / 1000 is log10(2.0) rounded up. * 302 / 1000 is log10(2.0) rounded up.
* Subtract one for the sign bit if the type is signed; * Subtract one for the sign bit if the type is signed;
...@@ -98,7 +91,6 @@ extern int unlink(const char *filename); ...@@ -98,7 +91,6 @@ extern int unlink(const char *filename);
#define INT_STRLEN_MAXIMUM(type) \ #define INT_STRLEN_MAXIMUM(type) \
((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \ ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
1 + TYPE_SIGNED(type)) 1 + TYPE_SIGNED(type))
#endif /* !defined INT_STRLEN_MAXIMUM */
/* /*
* INITIALIZE(x) * INITIALIZE(x)
...@@ -108,24 +100,70 @@ extern int unlink(const char *filename); ...@@ -108,24 +100,70 @@ extern int unlink(const char *filename);
#undef _ #undef _
#define _(msgid) (msgid) #define _(msgid) (msgid)
#ifndef YEARSPERREPEAT /* Handy macros that are independent of tzfile implementation. */
#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */ #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 isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
#define AVGSECSPERYEAR 31556952L
#endif /* !defined AVGSECSPERYEAR */
#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)) */ #define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */
#endif /* !defined SECSPERREPEAT_BITS */
#endif /* !defined PRIVATE_H */ #endif /* !defined PRIVATE_H */
/* 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. * Copyright 1989 The Regents of the University of California.
...@@ -43,7 +43,6 @@ ...@@ -43,7 +43,6 @@
#include <fcntl.h> #include <fcntl.h>
#include "private.h" #include "private.h"
#include "tzfile.h"
struct lc_time_T struct lc_time_T
...@@ -451,11 +450,17 @@ _fmt(const char *format, const struct pg_tm * t, char *pt, const char *ptlim, ...@@ -451,11 +450,17 @@ _fmt(const char *format, const struct pg_tm * t, char *pt, const char *ptlim,
{ {
long diff; long diff;
char const *sign; char const *sign;
bool negative;
if (t->tm_isdst < 0) if (t->tm_isdst < 0)
continue; continue;
diff = t->tm_gmtoff; diff = t->tm_gmtoff;
if (diff < 0) negative = diff < 0;
if (diff == 0)
{
negative = t->tm_zone[0] == '-';
}
if (negative)
{ {
sign = "-"; sign = "-";
diff = -diff; diff = -diff;
......
...@@ -100,56 +100,4 @@ struct tzhead ...@@ -100,56 +100,4 @@ struct tzhead
#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ #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 */ #endif /* !defined TZFILE_H */
...@@ -2671,6 +2671,9 @@ outzone(const struct zone * zpfirst, ptrdiff_t zonecount) ...@@ -2671,6 +2671,9 @@ outzone(const struct zone * zpfirst, ptrdiff_t zonecount)
bool do_extend; bool do_extend;
char version; char version;
ptrdiff_t lastatmax = -1; 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_abbr_len = 2 + max_format_len + max_abbrvar_len;
max_envvar_len = 2 * max_abbr_len + 5 * 9; max_envvar_len = 2 * max_abbr_len + 5 * 9;
...@@ -2780,12 +2783,13 @@ outzone(const struct zone * zpfirst, ptrdiff_t zonecount) ...@@ -2780,12 +2783,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) if (min_year > 1900)
min_year = 1900; min_year = 1900;
if (max_year < 2037) max_year0 = max_year;
max_year = 2037; if (max_year < 2038)
max_year = 2038;
for (i = 0; i < zonecount; ++i) for (i = 0; i < zonecount; ++i)
{ {
/* /*
...@@ -2835,7 +2839,12 @@ outzone(const struct zone * zpfirst, ptrdiff_t zonecount) ...@@ -2835,7 +2839,12 @@ outzone(const struct zone * zpfirst, ptrdiff_t zonecount)
year <= rp->r_hiyear && year <= rp->r_hiyear &&
yearistype(year, rp->r_yrtype); yearistype(year, rp->r_yrtype);
if (rp->r_todo) if (rp->r_todo)
{
rp->r_temp = rpytime(rp, year); rp->r_temp = rpytime(rp, year);
rp->r_todo
= (rp->r_temp < y2038_boundary
|| year <= max_year0);
}
} }
for (;;) for (;;)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment