[tz] [PROPOSED PATCH] Fix localtime bug with Anchorage after 2037
Paul Eggert
eggert at cs.ucla.edu
Fri Aug 28 08:19:31 UTC 2015
* NEWS: Document this.
* localtime.c (tzloadbody): Handle America/Anchorage after 2037,
even though the sum of the abbreviations' sizes (42) plus the sum
of the extended abbreviations' sizes (10) exceeds TZ_MAX_CHARS (50).
Do this by reusing existing abbreviations. Thanks to Bradley
White for reporting the bug. Perhaps we should also consider
increasing TZ_MAX_CHARS from its currently-low value.
---
NEWS | 8 +++++++
localtime.c | 71 +++++++++++++++++++++++++++++++++++++++----------------------
2 files changed, 54 insertions(+), 25 deletions(-)
diff --git a/NEWS b/NEWS
index b477250..ffe3fb2 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,13 @@
News for the tz database
+Unreleased, experimental changes
+
+ Changes affecting code
+
+ localtime no longer mishandles America/Anchorage after 2037.
+ (Thanks to Bradley White for reporting the bug.)
+
+
Release 2015f - 2015-08-10 18:06:56 -0700
Changes affecting future time stamps
diff --git a/localtime.c b/localtime.c
index ded8f7b..ac34e5d 100644
--- a/localtime.c
+++ b/localtime.c
@@ -569,31 +569,52 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
up->buf[nread - 1] = '\0';
if (tzparse(&up->buf[1], ts, false)
- && ts->typecnt == 2
- && sp->charcnt + ts->charcnt <= TZ_MAX_CHARS) {
- for (i = 0; i < 2; ++i)
- ts->ttis[i].tt_abbrind +=
- sp->charcnt;
- for (i = 0; i < ts->charcnt; ++i)
- sp->chars[sp->charcnt++] =
- ts->chars[i];
- i = 0;
- while (i < ts->timecnt &&
- ts->ats[i] <=
- sp->ats[sp->timecnt - 1])
- ++i;
- while (i < ts->timecnt &&
- sp->timecnt < TZ_MAX_TIMES) {
- sp->ats[sp->timecnt] =
- ts->ats[i];
- sp->types[sp->timecnt] =
- sp->typecnt +
- ts->types[i];
- ++sp->timecnt;
- ++i;
- }
- sp->ttis[sp->typecnt++] = ts->ttis[0];
- sp->ttis[sp->typecnt++] = ts->ttis[1];
+ && ts->typecnt == 2) {
+
+ /* 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 example. */
+ int gotabbr = 0;
+ int charcnt = sp->charcnt;
+ for (i = 0; i < 2; i++) {
+ char *tsabbr = ts->chars + ts->ttis[i].tt_abbrind;
+ int j;
+ for (j = 0; j < charcnt; j++)
+ if (strcmp(sp->chars + j, tsabbr) == 0) {
+ ts->ttis[i].tt_abbrind = j;
+ gotabbr++;
+ break;
+ }
+ if (! (j < charcnt)) {
+ int tsabbrlen = strlen(tsabbr);
+ if (j + tsabbrlen < TZ_MAX_CHARS) {
+ strcpy(sp->chars + j, tsabbr);
+ charcnt = j + tsabbrlen + 1;
+ ts->ttis[i].tt_abbrind = j;
+ gotabbr++;
+ }
+ }
+ }
+ if (gotabbr == 2) {
+ sp->charcnt = charcnt;
+ for (i = 0; i < ts->timecnt; i++)
+ if (sp->ats[sp->timecnt - 1] < ts->ats[i])
+ break;
+ while (i < ts->timecnt
+ && sp->timecnt < TZ_MAX_TIMES) {
+ sp->ats[sp->timecnt] = ts->ats[i];
+ sp->types[sp->timecnt] = (sp->typecnt
+ + ts->types[i]);
+ sp->timecnt++;
+ i++;
+ }
+ sp->ttis[sp->typecnt++] = ts->ttis[0];
+ sp->ttis[sp->typecnt++] = ts->ttis[1];
+ }
}
}
if (sp->timecnt > 1) {
--
2.1.4
More information about the tz
mailing list