The bug can be observed when processing the following .zi data, adapted from the current ‘asia’ file: Rule Palestine 2075 max - Mar Sat<=30 2:00 1:00 S Rule Palestine 2075 max - Oct Sat<=30 2:00 0 - Rule Palestine 2076 only - Jul 25 2:00 0 - Rule Palestine 2076 only - Sep 5 2:00 1:00 S Zone Asia/Gaza 2:00 - EET 2012 2:00 Palestine EE%sT Without the fix, zic generates an incorrect TZif file, in which the special-case 2076 transitions are omitted. This causes ‘zdump -ic 2076,2077 Asia/Gaza’ to mistakenly omit the lines: 2076-07-25 01 +02 EET 2076-09-05 03 +03 EEST 1 * zic.c (outzone): Redo algorithm to work even when the effect of a Rule that never ends (TO="max") is interspersed with the effect of a one-shot rule (TO="only"). --- NEWS | 4 ++++ zic.c | 57 +++++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/NEWS b/NEWS index 44ed20f3..115aff7b 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,10 @@ Unreleased, experimental changes transition into a DST regime. Previously, it incorrectly assumed DST was in effect before the transition too. + zic no longer mishandles data for Palestine after the year 2075. + Previously, it incorrectly omitted post-2075 transitions that are + predicted for just before and just after Ramadan. + zic now works again on Linux 2.6.16 and 2.6.17 (2006). (Problem reported by Rune Torgersen.) diff --git a/zic.c b/zic.c index 4293637d..38685f62 100644 --- a/zic.c +++ b/zic.c @@ -2980,6 +2980,10 @@ rule_cmp(struct rule const *a, struct rule const *b) return a->r_dayofmonth - b->r_dayofmonth; } +/* Store into RESULT a POSIX TZ string that represent the future + predictions for the zone ZPFIRST with ZONECOUNT entries. Return a + compatibility indicator (a TZDB release year) if successful, a + negative integer if no such TZ string exissts. */ static int stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) { @@ -3119,7 +3123,8 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) register int compat; register bool do_extend; register char version; - ptrdiff_t lastatmax = -1; + zic_t nonTZlimtime = ZIC_MIN; + int nonTZlimtype = -1; zic_t max_year0; int defaulttype = -1; @@ -3235,7 +3240,6 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) unspecifiedtype = addtype(0, "-00", false, false, false); for (i = 0; i < zonecount; ++i) { - struct rule *prevrp = NULL; /* ** A guess that may well be corrected later. */ @@ -3245,8 +3249,6 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) bool useuntil = i < (zonecount - 1); zic_t stdoff = zp->z_stdoff; zic_t startoff = stdoff; - zic_t prevktime; - INITIALIZE(prevktime); if (useuntil && zp->z_untiltime <= min_time) continue; eat(zp->z_filenum, zp->z_linenum); @@ -3260,6 +3262,10 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) startttisut); if (usestart) { addtt(starttime, type); + if (useuntil && nonTZlimtime < starttime) { + nonTZlimtime = starttime; + nonTZlimtype = type; + } usestart = false; } else defaulttype = type; @@ -3387,23 +3393,16 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) doabbr(ab, zp, rp->r_abbrvar, rp->r_isdst, rp->r_save, false); offset = oadd(zp->z_stdoff, rp->r_save); - if (!want_bloat() && !useuntil && !do_extend - && prevrp && lo_time <= prevktime - && redundant_time <= ktime - && rp->r_hiyear == ZIC_MAX - && prevrp->r_hiyear == ZIC_MAX) - break; type = addtype(offset, ab, rp->r_isdst, rp->r_todisstd, rp->r_todisut); if (defaulttype < 0 && !rp->r_isdst) defaulttype = type; - if (rp->r_hiyear == ZIC_MAX - && ! (0 <= lastatmax - && ktime < attypes[lastatmax].at)) - lastatmax = timecnt; addtt(ktime, type); - prevrp = rp; - prevktime = ktime; + if (nonTZlimtime < ktime + && (useuntil || rp->r_hiyear != ZIC_MAX)) { + nonTZlimtime = ktime; + nonTZlimtype = type; + } } } } @@ -3438,8 +3437,30 @@ error(_("can't determine time zone abbreviation to use just after until time")); } if (defaulttype < 0) defaulttype = 0; - if (0 <= lastatmax) - attypes[lastatmax].dontmerge = true; + if (!do_extend && !want_bloat()) { + /* The earliest transition into a time governed by the TZ string. */ + zic_t TZstarttime = ZIC_MAX; + for (i = 0; i < timecnt; i++) { + zic_t at = attypes[i].at; + if (nonTZlimtime < at && at < TZstarttime) + TZstarttime = at; + } + if (TZstarttime == ZIC_MAX) + TZstarttime = nonTZlimtime; + + /* Omit trailing transitions deducible from the TZ string. */ + for (i = j = 0; i < timecnt; i++) + if (redundant_time <= attypes[i].at + && attypes[i].at <= TZstarttime) { + attypes[j].at = attypes[i].at; + attypes[j].dontmerge = (attypes[i].at == TZstarttime + && (nonTZlimtype != attypes[i].type + || strchr(envvar, ','))); + attypes[j].type = attypes[i].type; + j++; + } + timecnt = j; + } if (do_extend) { /* ** If we're extending the explicitly listed observations -- 2.41.0