1
0
mirror of https://frontier.innolan.net/rainlance/amiga-tz.git synced 2026-05-07 01:49:04 +00:00

Support time stamps past 2038 in zones like America/Santiago.

This implements a suggestion by Arthur David Olson.
Without this change, zic -v diagnoses problems with several zones
where it cannot compute a POSIX-equivalent TZ setting for time
stamps past 2038, which means these time stamps may be mishandled.
This entails a minor change to the binary tz file format, to allow
a minor extension to the POSIX TZ setting in the binary file,
instead of requiring a pure POSIX TZ setting.  The zones fixed by
this change are America/Godthab, America/Santiago, Antarctica/Palmer,
Asia/Gaza, Asia/Hebron, Asia/Jerusalem, Pacific/Easter, and
Pacific/Fiji.  The only zone that remains unfixed is
Asia/Tehran, which schedules clock transitions via the
Iranian calendar, something that even the extended TZ
setting cannot represent.
* localtime.c (getrule): Allow transition times to be signed.
* newtzset.3: Describe the extensions to POSIX TZ strings.
Some of these extensions (e.g., hours == 26) were already
implemented but were not documented.  Give examples.
* tzfile.5: Document the relaxed restriction on the stored TZ
string; its hours component can be in the range -167..167 rather
than the POSIX-required 0..24.  Refer to newtzset(5).
* zic.c (stringoffset): Allow hours to go up to 167.
(stringrule): Be willing to generate hours in the range -167
through 167.
This commit is contained in:
Paul Eggert
2013-09-05 18:19:12 -07:00
parent bd3e920d0e
commit 07351e0248
4 changed files with 54 additions and 18 deletions

27
zic.c
View File

@@ -1776,7 +1776,7 @@ stringoffset(char *result, zic_t offset)
minutes = offset % MINSPERHOUR;
offset /= MINSPERHOUR;
hours = offset;
if (hours > HOURSPERDAY) {
if (hours >= HOURSPERDAY * DAYSPERWEEK) {
result[0] = '\0';
return -1;
}
@@ -1793,7 +1793,7 @@ static int
stringrule(char *result, const struct rule *const rp, const zic_t dstoff,
const zic_t gmtoff)
{
register zic_t tod;
register zic_t tod = rp->r_tod;
result = end(result);
if (rp->r_dycode == DC_DOM) {
@@ -1807,32 +1807,33 @@ stringrule(char *result, const struct rule *const rp, const zic_t dstoff,
(void) sprintf(result, "J%d", total + rp->r_dayofmonth);
} else {
register int week;
register int wday = rp->r_wday;
register int wdayoff;
if (rp->r_dycode == DC_DOWGEQ) {
if ((rp->r_dayofmonth % DAYSPERWEEK) != 1)
return -1;
week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
wday -= wdayoff;
tod += wdayoff * SECSPERDAY;
week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
} else if (rp->r_dycode == DC_DOWLEQ) {
if (rp->r_dayofmonth == len_months[1][rp->r_month])
week = 5;
else {
if ((rp->r_dayofmonth % DAYSPERWEEK) != 0)
return -1;
wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
wday -= wdayoff;
tod += wdayoff * SECSPERDAY;
week = rp->r_dayofmonth / DAYSPERWEEK;
}
} else return -1; /* "cannot happen" */
if (wday < 0)
wday += DAYSPERWEEK;
(void) sprintf(result, "M%d.%d.%d",
rp->r_month + 1, week, rp->r_wday);
rp->r_month + 1, week, wday);
}
tod = rp->r_tod;
if (rp->r_todisgmt)
tod += gmtoff;
if (rp->r_todisstd && rp->r_stdoff == 0)
tod += dstoff;
if (tod < 0) {
result[0] = '\0';
return -1;
}
if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
(void) strcat(result, "/");
if (stringoffset(end(result), tod) != 0)