summaryrefslogtreecommitdiff
path: root/src/timezone/localtime.c
diff options
context:
space:
mode:
authorPavan Deolasee2017-06-14 05:42:18 +0000
committerPavan Deolasee2017-06-14 05:42:18 +0000
commit15dd5274c323fb93e4e3ea9ad2185aaaec10f79c (patch)
tree9dafb4c7f735d9429ea461dc792933af87493c33 /src/timezone/localtime.c
parentdfbb88e3bbb526dcb204b456b9e5cfd9d10d0d0a (diff)
parentd5cb3bab564e0927ffac7c8729eacf181a12dd40 (diff)
Merge from PG master upto d5cb3bab564e0927ffac7c8729eacf181a12dd40
This is the result of the "git merge remotes/PGSQL/master" upto the said commit point. We have done some basic analysis, fixed compilation problems etc, but bulk of the logical problems in conflict resolution etc will be handled by subsequent commits.
Diffstat (limited to 'src/timezone/localtime.c')
-rw-r--r--src/timezone/localtime.c103
1 files changed, 81 insertions, 22 deletions
diff --git a/src/timezone/localtime.c b/src/timezone/localtime.c
index a14215d6bd..a2faa82ac8 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"
@@ -54,6 +55,13 @@ static const pg_time_t time_t_min = MINVAL(pg_time_t, TYPE_BIT(pg_time_t));
static const pg_time_t time_t_max = MAXVAL(pg_time_t, TYPE_BIT(pg_time_t));
/*
+ * We cache the result of trying to load the TZDEFRULES zone here.
+ * tzdefrules_loaded is 0 if not tried yet, +1 if good, -1 if failed.
+ */
+static struct state tzdefrules_s;
+static int tzdefrules_loaded = 0;
+
+/*
* The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
* We default to US rules as of 1999-08-17.
* POSIX 1003.1 section 8.1.1 says that the default DST rules are
@@ -414,10 +422,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 +459,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;
@@ -489,7 +508,7 @@ tzloadbody(char const * name, char *canonname, struct state * sp, bool doextend,
}
/*
- * If type 0 is is unused in transitions, it's the type to use for early
+ * If type 0 is unused in transitions, it's the type to use for early
* times.
*/
for (i = 0; i < sp->timecnt; ++i)
@@ -930,7 +949,21 @@ tzparse(const char *name, struct state * sp, bool lastditch)
charcnt = stdlen + 1;
if (sizeof sp->chars < charcnt)
return false;
- load_ok = tzload(TZDEFRULES, NULL, sp, false) == 0;
+
+ /*
+ * This bit also differs from the IANA code, which doesn't make any
+ * attempt to avoid repetitive loadings of the TZDEFRULES zone.
+ */
+ if (tzdefrules_loaded == 0)
+ {
+ if (tzload(TZDEFRULES, NULL, &tzdefrules_s, false) == 0)
+ tzdefrules_loaded = 1;
+ else
+ tzdefrules_loaded = -1;
+ }
+ load_ok = (tzdefrules_loaded > 0);
+ if (load_ok)
+ memcpy(sp, &tzdefrules_s, sizeof(struct state));
}
if (!load_ok)
sp->leapcnt = 0; /* so, we're off a little */
@@ -974,6 +1007,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 +1029,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 +1070,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
{
@@ -1280,9 +1340,8 @@ gmtsub(pg_time_t const * timep, int32 offset, struct pg_tm * tmp)
result = timesub(timep, offset, gmtptr, tmp);
/*
- * Could get fancy here and deliver something such as "UT+xxxx" or
- * "UT-xxxx" if offset is non-zero, but this is no time for a treasure
- * hunt.
+ * Could get fancy here and deliver something such as "+xx" or "-xx" if
+ * offset is non-zero, but this is no time for a treasure hunt.
*/
if (offset != 0)
tmp->tm_zone = wildabbr;