Skip to content

Commit bc10219

Browse files
committed
Make pg_interpret_timezone_abbrev() check sp->defaulttype too.
This omission caused it to not recognize the furthest-back zone abbreviation when working with timezone data compiled with relatively recent zic (2018f or newer). Older versions of zic produced a dummy DST transition at the Big Bang, so that the oldest abbreviation could always be found in the sp->types[] array; but newer versions don't do that, so that we must examine defaulttype as well as the types[] array to be sure of seeing all the abbreviations. While this has been broken for six or so years, we'd managed not to notice for two reasons: (1) many platforms are still using ancient zic for compatibility reasons, so that the issue did not manifest in builds using --with-system-tzdata; (2) the oldest zone abbreviation is almost always "LMT", which we weren't supporting anyway (but an upcoming patch will accept that). While at it, update pg_next_dst_boundary() to use sp->defaulttype as the time type for non-DST zones and times before the oldest DST transition. The existing code there predates upstream's invention of the sp->defaulttype field, and its heuristic for finding the oldest time type has now been subsumed into the code that sets sp->defaulttype. Possibly this should be back-patched, but I'm not currently aware of any visible consequences of this bug in released branches. Per report from Aleksander Alekseev and additional investigation. Discussion: https://postgr.es/m/CAJ7c6TOATjJqvhnYsui0=CO5XFMF4dvTGH+skzB--jNhqSQu5g@mail.gmail.com
1 parent 901bd4a commit bc10219

File tree

1 file changed

+20
-20
lines changed

1 file changed

+20
-20
lines changed

src/timezone/localtime.c

+20-20
Original file line numberDiff line numberDiff line change
@@ -1624,15 +1624,8 @@ pg_next_dst_boundary(const pg_time_t *timep,
16241624
sp = &tz->state;
16251625
if (sp->timecnt == 0)
16261626
{
1627-
/* non-DST zone, use lowest-numbered standard type */
1628-
i = 0;
1629-
while (sp->ttis[i].tt_isdst)
1630-
if (++i >= sp->typecnt)
1631-
{
1632-
i = 0;
1633-
break;
1634-
}
1635-
ttisp = &sp->ttis[i];
1627+
/* non-DST zone, use the defaulttype */
1628+
ttisp = &sp->ttis[sp->defaulttype];
16361629
*before_gmtoff = ttisp->tt_utoff;
16371630
*before_isdst = ttisp->tt_isdst;
16381631
return 0;
@@ -1692,15 +1685,8 @@ pg_next_dst_boundary(const pg_time_t *timep,
16921685
}
16931686
if (t < sp->ats[0])
16941687
{
1695-
/* For "before", use lowest-numbered standard type */
1696-
i = 0;
1697-
while (sp->ttis[i].tt_isdst)
1698-
if (++i >= sp->typecnt)
1699-
{
1700-
i = 0;
1701-
break;
1702-
}
1703-
ttisp = &sp->ttis[i];
1688+
/* For "before", use the defaulttype */
1689+
ttisp = &sp->ttis[sp->defaulttype];
17041690
*before_gmtoff = ttisp->tt_utoff;
17051691
*before_isdst = ttisp->tt_isdst;
17061692
*boundary = sp->ats[0];
@@ -1793,7 +1779,9 @@ pg_interpret_timezone_abbrev(const char *abbrev,
17931779
* abbreviation should get us what we want, since extrapolation would just
17941780
* be repeating the newest or oldest meanings.
17951781
*
1796-
* Use binary search to locate the first transition > cutoff time.
1782+
* Use binary search to locate the first transition > cutoff time. (Note
1783+
* that sp->timecnt could be zero, in which case this loop does nothing
1784+
* and only the defaulttype entry will be checked.)
17971785
*/
17981786
{
17991787
int lo = 0;
@@ -1827,7 +1815,19 @@ pg_interpret_timezone_abbrev(const char *abbrev,
18271815
}
18281816

18291817
/*
1830-
* Not there, so scan forwards to find the first one after.
1818+
* Not found yet; check the defaulttype, which is notionally the era
1819+
* before any of the entries in sp->types[].
1820+
*/
1821+
ttisp = &sp->ttis[sp->defaulttype];
1822+
if (ttisp->tt_desigidx == abbrind)
1823+
{
1824+
*gmtoff = ttisp->tt_utoff;
1825+
*isdst = ttisp->tt_isdst;
1826+
return true;
1827+
}
1828+
1829+
/*
1830+
* Not there, so scan forwards to find the first one after the cutoff.
18311831
*/
18321832
for (i = cutoff; i < sp->timecnt; i++)
18331833
{

0 commit comments

Comments
 (0)