[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: <https://mm.icann.org/pipermail/tz/attachments/20210614/b6350a94/attachment-0001.html>
-------------- 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