aboutsummaryrefslogtreecommitdiff
path: root/src/timezone/localtime.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/timezone/localtime.c')
-rw-r--r--src/timezone/localtime.c73
1 files changed, 56 insertions, 17 deletions
diff --git a/src/timezone/localtime.c b/src/timezone/localtime.c
index ae9c2d23e63..6e0fa10066c 100644
--- a/src/timezone/localtime.c
+++ b/src/timezone/localtime.c
@@ -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
{