From b22d459a367f4d01b10f6f6b4e45c2831fc4e2aa Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 23 May 2014 22:56:18 -0300 Subject: [PATCH] zic: work around GNOME bug by refusing to go back before the Big Bang This works around Gnome bug 730332 . zic 2014c introduced the idea of generating a transition at the minimum time value -2**63, to avoid ambiguities about what to do before the first real transition. Through Glib release 2.40, the interval_end function of Glib's gtimezone.c subtracts one from this, to find the end time of the zeroth interval (i.e., the interval containing all the "early" time stamps); this subtraction typically overflows and wraps around to 2**63 - 1, which causes Glib to go off the rails and assume that all time stamps are "early". For example, Glib computes Sao Paulo time stamps as if Brazil's circa-1913 rules were still in effect. (Thanks to Leonardo Chiquitto for reporting the bug.) Work around the bug by not generating time stamps equal to -2**63. Come to think of it, time stamps before the Big Bang are physically suspect anyway, so don't generate time stamps before the Big Bang. * Makefile (GCC_DEBUG_FLAGS): Add comment re BIG_BANG. * NEWS, zic.8 (NOTES): Document this. * zic.c (BIG_BANG): New macro. (big_bang_time): New constant. (writezone, outzone, addtt): Compare to big_bang_time, not to min_time, when deciding whether to output a time stamp. --- Makefile | 1 + NEWS | 9 +++++++++ zic.8 | 6 ++++++ zic.c | 40 ++++++++++++++++++++++++++++++++++------ 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 3cdd845..a566c64 100644 --- a/Makefile +++ b/Makefile @@ -100,6 +100,7 @@ YEARISTYPE= ./yearistype LDLIBS= # Add the following to the end of the "CFLAGS=" line as needed. +# -DBIG_BANG=-9999999LL if the Big Bang occurred at time -9999999 (see zic.c) # -DHAVE_ADJTIME=0 if `adjtime' does not exist (SVR0?) # -DHAVE_DOS_FILE_NAMES if file names have drive specifiers etc. (MS-DOS) # -DHAVE_GETTEXT=1 if `gettext' works (GNU, Linux, Solaris); also see LDLIBS diff --git a/NEWS b/NEWS index 6f6581b..95db5f9 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,15 @@ News for the tz database +Unreleased, experimental changes + + Changes affecting code + + zic no longer generates files containing time stamps before the Big Bang. + This works around GNOME bug 730332 + . + + Release 2014c - 2014-05-13 07:44:13 -0700 Changes affecting near-future time stamps diff --git a/zic.8 b/zic.8 index ca29fd1..4e0bac8 100644 --- a/zic.8 +++ b/zic.8 @@ -519,6 +519,12 @@ produces a single transition to daylight saving at the new UT offset To get separate transitions use multiple zone continuation lines specifying transition instants using universal time. +.PP +Time stamps before the Big Bang are silently omitted from the output. +This works around bugs in software that mishandles large negative time +stamps. Call it sour grapes, but pre-Big-Bang time stamps are +physically suspect anyway. The estimated time of the Big Bang is +approximate and may change in future versions. .SH FILE /usr/local/etc/zoneinfo standard directory used for created files .SH "SEE ALSO" diff --git a/zic.c b/zic.c index 7e0f97f..6112002 100644 --- a/zic.c +++ b/zic.c @@ -723,6 +723,34 @@ warning(_("hard link failed, symbolic link used")); static const zic_t min_time = (zic_t) -1 << (TIME_T_BITS_IN_FILE - 1); static const zic_t max_time = -1 - ((zic_t) -1 << (TIME_T_BITS_IN_FILE - 1)); +/* Estimated time of the Big Bang, in seconds since the POSIX epoch. + zic does not output time stamps before this, partly because they + are physically suspect, and partly because GNOME mishandles them; see + GNOME bug 730332 . + + The following estimate for the Big Bang time is taken from: + + Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results. + I. Overview of products and scientific results. + arXiv:1303.5062 2013-03-20 20:10:01 UTC + [PDF] + + Page 36, Table 9, row Age/Gyr, column Planck+WP+highL+BAO best fit, + gives the value 13.7965. Multiplying this by 1000000000 and then + by 31557600 (the number of seconds in an astronomical year), yields + 435384428400000000. This estimate intentionally ignores the + difference between the POSIX epoch and the paper's publication + date, as being beneath the paper's precision. + + This estimate is approximate, and may change in future versions. + Please do not rely on its exact value. */ + +#ifndef BIG_BANG +#define BIG_BANG (-435384428400000000LL) +#endif + +static const zic_t big_bang_time = BIG_BANG; + static int itsdir(const char *const name) { @@ -1478,7 +1506,7 @@ writezone(const char *const name, const char *const string, char version) toi = 0; fromi = 0; - while (fromi < timecnt && attypes[fromi].at < min_time) + while (fromi < timecnt && attypes[fromi].at < big_bang_time) ++fromi; for ( ; fromi < timecnt; ++fromi) { if (toi > 1 && ((attypes[fromi].at + @@ -2167,9 +2195,9 @@ outzone(const struct zone * const zpfirst, const int zonecount) */ stdoff = 0; zp = &zpfirst[i]; - usestart = i > 0 && (zp - 1)->z_untiltime > min_time; + usestart = i > 0 && (zp - 1)->z_untiltime > big_bang_time; useuntil = i < (zonecount - 1); - if (useuntil && zp->z_untiltime <= min_time) + if (useuntil && zp->z_untiltime <= big_bang_time) continue; gmtoff = zp->z_gmtoff; eat(zp->z_filename, zp->z_linenum); @@ -2185,7 +2213,7 @@ outzone(const struct zone * const zpfirst, const int zonecount) if (usestart) { addtt(starttime, type); usestart = FALSE; - } else addtt(min_time, type); + } else addtt(big_bang_time, type); } else for (year = min_year; year <= max_year; ++year) { if (useuntil && year > zp->z_untilrule.r_hiyear) break; @@ -2362,8 +2390,8 @@ error(_("can't determine time zone abbreviation to use just after until time")); static void addtt(const zic_t starttime, int type) { - if (starttime <= min_time || - (timecnt == 1 && attypes[0].at < min_time)) { + if (starttime <= big_bang_time || + (timecnt == 1 && attypes[0].at < big_bang_time)) { gmtoffs[0] = gmtoffs[type]; isdsts[0] = isdsts[type]; ttisstds[0] = ttisstds[type];