Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit d8b15ee

Browse files
committed
Sync our copy of the timezone library with IANA release tzcode2020a.
This absorbs a leap-second-related bug fix in localtime.c, and teaches zic to handle an expiration marker in the leapseconds file. Neither are of any interest to us (for the foreseeable future anyway), but we need to stay more or less in sync with upstream. Also adjust some over-eager changes in the README from commit 9573384. I have no intention of making changes that require C99 in this code, until such time as all the live back branches require C99. Otherwise back-patching will get too exciting. For the same reason, absorb assorted whitespace and other cosmetic changes from HEAD into the back branches; mostly this reflects use of improved versions of pgindent. All in all then, quite a boring update. But I figured I'd get it done while I was looking at this code.
1 parent 6924c37 commit d8b15ee

File tree

3 files changed

+142
-68
lines changed

3 files changed

+142
-68
lines changed

src/timezone/README

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ match properly on the old version.
5555
Time Zone code
5656
==============
5757

58-
The code in this directory is currently synced with tzcode release 2019b.
58+
The code in this directory is currently synced with tzcode release 2020a.
5959
There are many cosmetic (and not so cosmetic) differences from the
6060
original tzcode library, but diffs in the upstream version should usually
6161
be propagated to our version. Here are some notes about that.
@@ -71,7 +71,14 @@ fixed that.)
7171

7272
* We need the code to follow Postgres' portability conventions; this
7373
includes relying on configure's results rather than hand-hacked
74-
#defines (see private.h).
74+
#defines (see private.h in particular).
75+
76+
* Similarly, avoid relying on <stdint.h> features that may not exist on old
77+
systems. In particular this means using Postgres' definitions of the int32
78+
and int64 typedefs, not int_fast32_t/int_fast64_t. Likewise we use
79+
PG_INT32_MIN/MAX not INT32_MIN/MAX. (Once we desupport all PG versions
80+
that don't require C99, it'd be practical to rely on <stdint.h> and remove
81+
this set of diffs; but that day is not yet.)
7582

7683
* Since Postgres is typically built on a system that has its own copy
7784
of the <time.h> functions, we must avoid conflicting with those. This
@@ -109,6 +116,13 @@ to first run the tzcode source files through a sed filter like this:
109116
-e 's|^\*/| */|' \
110117
-e 's/\bregister[ \t]//g' \
111118
-e 's/\bATTRIBUTE_PURE[ \t]//g' \
119+
-e 's/int_fast32_t/int32/g' \
120+
-e 's/int_fast64_t/int64/g' \
121+
-e 's/intmax_t/int64/g' \
122+
-e 's/INT32_MIN/PG_INT32_MIN/g' \
123+
-e 's/INT32_MAX/PG_INT32_MAX/g' \
124+
-e 's/INTMAX_MIN/PG_INT64_MIN/g' \
125+
-e 's/INTMAX_MAX/PG_INT64_MAX/g' \
112126
-e 's/struct[ \t]+tm\b/struct pg_tm/g' \
113127
-e 's/\btime_t\b/pg_time_t/g' \
114128
-e 's/lineno/lineno_t/g' \

src/timezone/localtime.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ struct rule
9292
static struct pg_tm *gmtsub(pg_time_t const *, int32, struct pg_tm *);
9393
static bool increment_overflow(int *, int);
9494
static bool increment_overflow_time(pg_time_t *, int32);
95+
static int64 leapcorr(struct state const *, pg_time_t);
9596
static struct pg_tm *timesub(pg_time_t const *, int32, struct state const *,
9697
struct pg_tm *);
9798
static bool typesequiv(struct state const *, int, int);
@@ -477,12 +478,14 @@ tzloadbody(char const *name, char *canonname, struct state *sp, bool doextend,
477478

478479
for (i = 0; i < ts->timecnt; i++)
479480
if (sp->timecnt == 0
480-
|| sp->ats[sp->timecnt - 1] < ts->ats[i])
481+
|| (sp->ats[sp->timecnt - 1]
482+
< ts->ats[i] + leapcorr(sp, ts->ats[i])))
481483
break;
482484
while (i < ts->timecnt
483485
&& sp->timecnt < TZ_MAX_TIMES)
484486
{
485-
sp->ats[sp->timecnt] = ts->ats[i];
487+
sp->ats[sp->timecnt]
488+
= ts->ats[i] + leapcorr(sp, ts->ats[i]);
486489
sp->types[sp->timecnt] = (sp->typecnt
487490
+ ts->types[i]);
488491
sp->timecnt++;
@@ -1601,6 +1604,22 @@ increment_overflow_time(pg_time_t *tp, int32 j)
16011604
return false;
16021605
}
16031606

1607+
static int64
1608+
leapcorr(struct state const *sp, pg_time_t t)
1609+
{
1610+
struct lsinfo const *lp;
1611+
int i;
1612+
1613+
i = sp->leapcnt;
1614+
while (--i >= 0)
1615+
{
1616+
lp = &sp->lsis[i];
1617+
if (t >= lp->ls_trans)
1618+
return lp->ls_corr;
1619+
}
1620+
return 0;
1621+
}
1622+
16041623
/*
16051624
* Find the next DST transition time in the given zone after the given time
16061625
*

src/timezone/zic.c

Lines changed: 105 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,14 @@ static void warning(const char *string,...) pg_attribute_printf(1, 2);
125125
static void usage(FILE *stream, int status) pg_attribute_noreturn();
126126
static void addtt(zic_t starttime, int type);
127127
static int addtype(zic_t, char const *, bool, bool, bool);
128-
static void leapadd(zic_t, bool, int, int);
128+
static void leapadd(zic_t, int, int);
129129
static void adjleap(void);
130130
static void associate(void);
131131
static void dolink(const char *, const char *, bool);
132132
static char **getfields(char *buf);
133133
static zic_t gethms(const char *string, const char *errstring);
134134
static zic_t getsave(char *, bool *);
135+
static void inexpires(char **, int);
135136
static void infile(const char *filename);
136137
static void inleap(char **fields, int nfields);
137138
static void inlink(char **fields, int nfields);
@@ -202,6 +203,7 @@ static int typecnt;
202203
#define LC_ZONE 1
203204
#define LC_LINK 2
204205
#define LC_LEAP 3
206+
#define LC_EXPIRES 4
205207

206208
/*
207209
* Which fields are which on a Zone line.
@@ -267,6 +269,9 @@ static int typecnt;
267269
#define LP_ROLL 6
268270
#define LEAP_FIELDS 7
269271

272+
/* Expires lines are like Leap lines, except without CORR and ROLL fields. */
273+
#define EXPIRES_FIELDS 5
274+
270275
/*
271276
* Year synonyms.
272277
*/
@@ -312,6 +317,7 @@ static struct lookup const zi_line_codes[] = {
312317
};
313318
static struct lookup const leap_line_codes[] = {
314319
{"Leap", LC_LEAP},
320+
{"Expires", LC_EXPIRES},
315321
{NULL, 0}
316322
};
317323

@@ -584,6 +590,12 @@ static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
584590
static zic_t lo_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
585591
static zic_t hi_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
586592

593+
/* The time specified by an Expires line, or negative if no such line. */
594+
static zic_t leapexpires = -1;
595+
596+
/* The time specified by an #expires comment, or negative if no such line. */
597+
static zic_t comment_leapexpires = -1;
598+
587599
/* Set the time range of the output to TIMERANGE.
588600
Return true if successful. */
589601
static bool
@@ -1279,7 +1291,8 @@ infile(const char *name)
12791291
}
12801292
if (nfields == 0)
12811293
{
1282-
/* nothing to do */
1294+
if (name == leapsec && *buf == '#')
1295+
sscanf(buf, "#expires " INT64_FORMAT, &comment_leapexpires);
12831296
}
12841297
else if (wantcont)
12851298
{
@@ -1311,6 +1324,10 @@ infile(const char *name)
13111324
inleap(fields, nfields);
13121325
wantcont = false;
13131326
break;
1327+
case LC_EXPIRES:
1328+
inexpires(fields, nfields);
1329+
wantcont = false;
1330+
break;
13141331
default: /* "cannot happen" */
13151332
fprintf(stderr,
13161333
_("%s: panic: Invalid l_value %d\n"),
@@ -1634,8 +1651,8 @@ inzsub(char **fields, int nfields, bool iscont)
16341651
return hasuntil;
16351652
}
16361653

1637-
static void
1638-
inleap(char **fields, int nfields)
1654+
static zic_t
1655+
getleapdatetime(char **fields, int nfields, bool expire_line)
16391656
{
16401657
const char *cp;
16411658
const struct lookup *lp;
@@ -1651,11 +1668,6 @@ inleap(char **fields, int nfields)
16511668
zic_t t;
16521669
char xs;
16531670

1654-
if (nfields != LEAP_FIELDS)
1655-
{
1656-
error(_("wrong number of fields on Leap line"));
1657-
return;
1658-
}
16591671
dayoff = 0;
16601672
cp = fields[LP_YEAR];
16611673
if (sscanf(cp, "%d%c", &year, &xs) != 1)
@@ -1664,13 +1676,16 @@ inleap(char **fields, int nfields)
16641676
* Leapin' Lizards!
16651677
*/
16661678
error(_("invalid leaping year"));
1667-
return;
1679+
return -1;
1680+
}
1681+
if (!expire_line)
1682+
{
1683+
if (!leapseen || leapmaxyear < year)
1684+
leapmaxyear = year;
1685+
if (!leapseen || leapminyear > year)
1686+
leapminyear = year;
1687+
leapseen = true;
16681688
}
1669-
if (!leapseen || leapmaxyear < year)
1670-
leapmaxyear = year;
1671-
if (!leapseen || leapminyear > year)
1672-
leapminyear = year;
1673-
leapseen = true;
16741689
j = EPOCH_YEAR;
16751690
while (j != year)
16761691
{
@@ -1689,7 +1704,7 @@ inleap(char **fields, int nfields)
16891704
if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL)
16901705
{
16911706
error(_("invalid month name"));
1692-
return;
1707+
return -1;
16931708
}
16941709
month = lp->l_value;
16951710
j = TM_JANUARY;
@@ -1704,56 +1719,70 @@ inleap(char **fields, int nfields)
17041719
day <= 0 || day > len_months[isleap(year)][month])
17051720
{
17061721
error(_("invalid day of month"));
1707-
return;
1722+
return -1;
17081723
}
17091724
dayoff = oadd(dayoff, day - 1);
17101725
if (dayoff < min_time / SECSPERDAY)
17111726
{
17121727
error(_("time too small"));
1713-
return;
1728+
return -1;
17141729
}
17151730
if (dayoff > max_time / SECSPERDAY)
17161731
{
17171732
error(_("time too large"));
1718-
return;
1733+
return -1;
17191734
}
17201735
t = dayoff * SECSPERDAY;
17211736
tod = gethms(fields[LP_TIME], _("invalid time of day"));
1722-
cp = fields[LP_CORR];
1737+
t = tadd(t, tod);
1738+
if (t < 0)
1739+
error(_("leap second precedes Epoch"));
1740+
return t;
1741+
}
1742+
1743+
static void
1744+
inleap(char **fields, int nfields)
1745+
{
1746+
if (nfields != LEAP_FIELDS)
1747+
error(_("wrong number of fields on Leap line"));
1748+
else
17231749
{
1724-
bool positive;
1725-
int count;
1750+
zic_t t = getleapdatetime(fields, nfields, false);
17261751

1727-
if (strcmp(cp, "") == 0)
1728-
{ /* infile() turns "-" into "" */
1729-
positive = false;
1730-
count = 1;
1731-
}
1732-
else if (strcmp(cp, "+") == 0)
1752+
if (0 <= t)
17331753
{
1734-
positive = true;
1735-
count = 1;
1736-
}
1737-
else
1738-
{
1739-
error(_("illegal CORRECTION field on Leap line"));
1740-
return;
1741-
}
1742-
if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL)
1743-
{
1744-
error(_("illegal Rolling/Stationary field on Leap line"));
1745-
return;
1746-
}
1747-
t = tadd(t, tod);
1748-
if (t < 0)
1749-
{
1750-
error(_("leap second precedes Epoch"));
1751-
return;
1754+
struct lookup const *lp = byword(fields[LP_ROLL], leap_types);
1755+
1756+
if (!lp)
1757+
error(_("invalid Rolling/Stationary field on Leap line"));
1758+
else
1759+
{
1760+
int correction = 0;
1761+
1762+
if (!fields[LP_CORR][0]) /* infile() turns "-" into "". */
1763+
correction = -1;
1764+
else if (strcmp(fields[LP_CORR], "+") == 0)
1765+
correction = 1;
1766+
else
1767+
error(_("invalid CORRECTION field on Leap line"));
1768+
if (correction)
1769+
leapadd(t, correction, lp->l_value);
1770+
}
17521771
}
1753-
leapadd(t, positive, lp->l_value, count);
17541772
}
17551773
}
17561774

1775+
static void
1776+
inexpires(char **fields, int nfields)
1777+
{
1778+
if (nfields != EXPIRES_FIELDS)
1779+
error(_("wrong number of fields on Expires line"));
1780+
else if (0 <= leapexpires)
1781+
error(_("multiple Expires lines"));
1782+
else
1783+
leapexpires = getleapdatetime(fields, nfields, true);
1784+
}
1785+
17571786
static void
17581787
inlink(char **fields, int nfields)
17591788
{
@@ -3369,32 +3398,25 @@ addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
33693398
}
33703399

33713400
static void
3372-
leapadd(zic_t t, bool positive, int rolling, int count)
3401+
leapadd(zic_t t, int correction, int rolling)
33733402
{
3374-
int i,
3375-
j;
3403+
int i;
33763404

3377-
if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS)
3405+
if (TZ_MAX_LEAPS <= leapcnt)
33783406
{
33793407
error(_("too many leap seconds"));
33803408
exit(EXIT_FAILURE);
33813409
}
33823410
for (i = 0; i < leapcnt; ++i)
33833411
if (t <= trans[i])
33843412
break;
3385-
do
3386-
{
3387-
for (j = leapcnt; j > i; --j)
3388-
{
3389-
trans[j] = trans[j - 1];
3390-
corr[j] = corr[j - 1];
3391-
roll[j] = roll[j - 1];
3392-
}
3393-
trans[i] = t;
3394-
corr[i] = positive ? 1 : -count;
3395-
roll[i] = rolling;
3396-
++leapcnt;
3397-
} while (positive && --count != 0);
3413+
memmove(&trans[i + 1], &trans[i], (leapcnt - i) * sizeof *trans);
3414+
memmove(&corr[i + 1], &corr[i], (leapcnt - i) * sizeof *corr);
3415+
memmove(&roll[i + 1], &roll[i], (leapcnt - i) * sizeof *roll);
3416+
trans[i] = t;
3417+
corr[i] = correction;
3418+
roll[i] = rolling;
3419+
++leapcnt;
33983420
}
33993421

34003422
static void
@@ -3418,6 +3440,25 @@ adjleap(void)
34183440
trans[i] = tadd(trans[i], last);
34193441
last = corr[i] += last;
34203442
}
3443+
3444+
if (leapexpires < 0)
3445+
{
3446+
leapexpires = comment_leapexpires;
3447+
if (0 <= leapexpires)
3448+
warning(_("\"#expires\" is obsolescent; use \"Expires\""));
3449+
}
3450+
3451+
if (0 <= leapexpires)
3452+
{
3453+
leapexpires = oadd(leapexpires, last);
3454+
if (!(leapcnt == 0 || (trans[leapcnt - 1] < leapexpires)))
3455+
{
3456+
error(_("last Leap time does not precede Expires time"));
3457+
exit(EXIT_FAILURE);
3458+
}
3459+
if (leapexpires <= hi_time)
3460+
hi_time = leapexpires - 1;
3461+
}
34213462
}
34223463

34233464
static char *

0 commit comments

Comments
 (0)