[tz] A simple solution to have zones merge into another zone
Alois Treindl
alois at astro.ch
Mon Jun 14 13:48:36 UTC 2021
Just in case anyone is interested, my patch for zic.c (from 25 April
2021) is attached.
It is in the public domain.
On 12.06.21 12:34, Alois Treindl via tz wrote:
>
> I assume the main reason why Paul Eggert wants to merge time zones is
> the fact there is less maintenance work, if for example EU rules
> change not only regarding DST, but regarding the standard time.
>
> If something like this happens, multiple zones have to be updated.
>
> Some years ago I developed my own patch to zic.c to make it
> understand the new keyword 'follow'.
>
> That way, I can represent a zone which deviates from a TZ "standard
> zone" before a certain date, and then say 'follow standard zone' at
> the end
> of the zone data.
>
> I have completed that for several countries, for example to represent
> the deviations from Europe/Berlin within parts of Germany before 1949,
> or to represent the numerous deviations in France from Europe/Paris.
>
> I attach two files which show the application of the 'follow' keyword.
>
> Of course I will be happy to share the patch to zic.c which enables it
> to process the follow keyword.
>
> As it is now, I apply my patch each time an update of zic.c is published.
>
> If the follow keyword is introduced into the main distribution, it
> could be used for zones like
> Europe/Copenhagen
> which instead of being eliminated would become
>
> Zone Europe/Copenhagen 0:50:20 - LMT 1890
> 0:50:20 - CMT 1894 Jan 1 #
> Copenhagen MT
> 1:00 Denmark CE%sT 1942 Nov 2 2:00s
> 1:00 C-Eur CE%sT 1945 Apr 2 2:00
> 1:00 Denmark CE%sT 1950
> 0 follow Europe/Berlin
>
> The information that Copenhagen is the same as Berlin after 1949 would
> be there,
> as well as the original data.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mm.icann.org/pipermail/tz/attachments/20210614/b6350a94/attachment.htm>
-------------- next part --------------
--- /tmp/tz/zic.c 2021-04-25 08:29:47.851564965 +0200
+++ zicx.c 2021-04-25 08:29:07.374324967 +0200
@@ -167,6 +167,7 @@
static bool inzcont(char ** fields, int nfields);
static bool inzone(char ** fields, int nfields);
static bool inzsub(char **, int, bool);
+static bool itsabbr(const char *abbr, const char *word);
static bool itssymlink(char const *);
static bool is_alpha(char a);
static char lowerit(char);
@@ -299,6 +300,17 @@
#define YR_MAXIMUM 1
#define YR_ONLY 2
+/*
+** follow rules, added by Alois Treindl August 2011
+** Zones may end with a line: 0 follow zone_name
+** which the parser will represent with FOLLOW_MARK in z_stdoff,
+** and the zone name in z_rule.
+** Before the call to outzone() the zone and its follow zone will be
+** patched together, so that outzone() sees a regular zone array.
+** To keep zone files readable, follow rules cannot be used recursively.
+*/
+#define FOLLOW_MARK 999999
+
static struct rule * rules;
static ptrdiff_t nrules; /* number of rules */
static ptrdiff_t nrules_alloc;
@@ -891,7 +903,48 @@
*/
for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
continue;
- outzone(&zones[i], j - i);
+ if (zones[j -1].z_stdoff == FOLLOW_MARK) {
+ /* copy zone and follow zone into one new array */
+ int k,n,m, nrows;
+ struct zone *xzones, *zp;
+ nrows = j - i - 1;
+ zp = &zones[j - 1]; /* line with the follow rule */
+ xzones = (struct zone *) (void *) emalloc((int) (nrows * sizeof *xzones));
+ for (k = 0; k < nrows; k++)
+ xzones[k] = zones[i + k];
+ /* now find the follow zone in array zones[] */
+ for (m = 0; m < nzones; m++) {
+ if (zones[m].z_name != NULL && strcmp(zp->z_rule, zones[m].z_name) == 0) break;
+ }
+ if (m == nzones) { /* error, follow zone not found */
+ char *cp;
+ cp = emalloc(80 + strlen(zp->z_rule) + strlen(zones[i].z_name));;
+ sprintf(cp, "For zone %s follow zone %s not found, no zonefile created.", zones[i].z_name, zp->z_rule);
+ eat(zp->z_filename, zp->z_linenum);
+ error(cp);
+ free(cp);
+ free((void *)xzones);
+ }
+ /* now find the next date in the follow zone */
+ for (n = m + 1; n < nzones; n++) {
+ if (zp->z_untiltime < zones[n].z_untiltime) break;
+ }
+ /* missing errorcode for case n == nzones,
+ * assume we are still in same follow zone.
+ * The follow zone part we need starts at zones[n].
+ * Now find where follow zone ends, will be m.
+ */
+ for (m = n; m < nzones && zones[m].z_name == NULL; ++m)
+ continue;
+ xzones = (struct zone *) (void *) erealloc((char *) xzones, (int) ((nrows + m - n) * sizeof *xzones));
+ for (k = 0; k < m - n; k++)
+ xzones[nrows + k] = zones[n + k];
+ nrows += m - n;
+ outzone(&xzones[0], nrows);
+ free((void *) xzones);
+ } else {
+ outzone(&zones[i], j - i);
+ }
}
/*
** Make links.
@@ -1295,7 +1348,7 @@
}
for (i = 0; i < nzones; ++i) {
zp = &zones[i];
- if (zp->z_nrules == 0) {
+ if (zp->z_nrules == 0 && zp->z_stdoff != FOLLOW_MARK) {
/*
** Maybe we have a local standard time offset.
*/
@@ -1596,18 +1649,30 @@
return false;
}
}
- z.z_rule = ecpyalloc(fields[i_rule]);
- z.z_format = cp1 = ecpyalloc(fields[i_format]);
- z.z_format_specifier = cp ? *cp : '\0';
- if (z.z_format_specifier == 'z') {
- if (noise)
- warning(_("format '%s' not handled by pre-2015 versions of zic"),
- z.z_format);
- cp1[cp - fields[i_format]] = 's';
- }
- if (max_format_len < strlen(z.z_format))
- max_format_len = strlen(z.z_format);
- hasuntil = nfields > i_untilyear;
+ /* check for 0 follow zonename
+ ** zonename must contain at least one /, and follow must be
+ * 'follow' or an abbreviation thereof.
+ */
+ if (z.z_stdoff == 0 && strchr(fields[i_format], '/') != NULL
+ && itsabbr(fields[i_rule], "follow")) {
+ z.z_stdoff = FOLLOW_MARK;
+ z.z_rule = ecpyalloc(fields[i_format]);
+ z.z_format = "";
+ hasuntil = false; /* no continue of zone now */
+ } else {
+ z.z_rule = ecpyalloc(fields[i_rule]);
+ z.z_format = cp1 = ecpyalloc(fields[i_format]);
+ z.z_format_specifier = cp ? *cp : '\0';
+ if (z.z_format_specifier == 'z') {
+ if (noise)
+ warning(_("format '%s' not handled by pre-2015 versions of zic"),
+ z.z_format);
+ cp1[cp - fields[i_format]] = 's';
+ }
+ if (max_format_len < strlen(z.z_format))
+ max_format_len = strlen(z.z_format);
+ hasuntil = nfields > i_untilyear;
+ }
if (hasuntil) {
z.z_untilrule.r_filename = filename;
z.z_untilrule.r_linenum = linenum;
More information about the tz
mailing list