[tz] [PROPOSED 3/4] Fix zic bug with Palestine after 2075
Paul Eggert
eggert at cs.ucla.edu
Sun Oct 15 20:10:51 UTC 2023
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
More information about the tz
mailing list