revised proposed time zone abbreviation changes

Arthur David Olson olsona at lecserver.nci.nih.gov
Mon Jun 6 15:22:42 UTC 2005


Thanks to folks for feedback on time zone abbreviation changes.
Below find revised changes reflecting the feedback.
The changes are relative to what's now available in the ftp directory.
The revisions:
1.	the set of characters allowed in time zone abbreviations has been
	expanded to include '.' (as in "E.S.T.") and '_'
	(on general principles).
2.	the character substituted for those outside the approved set has been
	changed to '_' (a character which does not appear in any of the
	abbreviations that currently appear in the time zone data files).
Regarding abbreviation lengths: I agree that some folks might want to use
abbreviations shorter than three letters (in particular the old-style
single-letter names for zones), so localtime.c is set up to allow fewer than
three. It also allows up to 16 (covering abbreviations such as
"XSTDST+hh:mm:ss" that Sun accepts). However, since the data files generated
by zic might end up being used on systems with stricter requirements, it seems
prudent to issue warnings (note: not errors) regarding short and long
abbreviations.

				--ado

diff -r -c old/Makefile new/Makefile
*** old/Makefile	Mon Apr  4 11:24:31 2005
--- new/Makefile	Thu May 26 12:42:13 2005
***************
*** 1,4 ****
! # @(#)Makefile	7.108
  
  # Change the line below for your time zone (after finding the zone you want in
  # the time zone files, or adding it to a time zone file).
--- 1,4 ----
! # @(#)Makefile	7.109
  
  # Change the line below for your time zone (after finding the zone you want in
  # the time zone files, or adding it to a time zone file).
***************
*** 111,117 ****
  #  -DNO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU=1
  #	if you do not want run time warnings about formats that may cause
  #	year 2000 grief
! #
  GCC_DEBUG_FLAGS = -Dlint -g -O -fno-common \
  	-Wall -Wcast-qual -Wconversion -Wmissing-prototypes \
  	-Wnested-externs -Wpointer-arith -Wshadow \
--- 111,119 ----
  #  -DNO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU=1
  #	if you do not want run time warnings about formats that may cause
  #	year 2000 grief
! #  -DZIC_MAX_ABBR_LEN_WO_WARN=3
! #	(or some other number) to set the maximum time zone abbreviation length
! #	that zic will accept without a warning (the default is 6)
  GCC_DEBUG_FLAGS = -Dlint -g -O -fno-common \
  	-Wall -Wcast-qual -Wconversion -Wmissing-prototypes \
  	-Wnested-externs -Wpointer-arith -Wshadow \
diff -r -c old/localtime.c new/localtime.c
*** old/localtime.c	Mon Apr  4 11:24:32 2005
--- new/localtime.c	Mon Jun  6 11:12:54 2005
***************
*** 5,11 ****
  
  #ifndef lint
  #ifndef NOID
! static char	elsieid[] = "@(#)localtime.c	7.91";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
--- 5,11 ----
  
  #ifndef lint
  #ifndef NOID
! static char	elsieid[] = "@(#)localtime.c	7.94";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
***************
*** 22,27 ****
--- 22,40 ----
  #include "fcntl.h"
  #include "float.h"	/* for FLT_MAX and DBL_MAX */
  
+ #ifndef TZ_ABBR_MAX_LEN
+ #define TZ_ABBR_MAX_LEN	16
+ #endif /* !defined TZ_ABBR_MAX_LEN */
+ 
+ #ifndef TZ_ABBR_CHAR_SET
+ #define TZ_ABBR_CHAR_SET \
+ 	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
+ #endif /* !defined TZ_ABBR_CHAR_SET */
+ 
+ #ifndef TZ_ABBR_ERR_CHAR
+ #define TZ_ABBR_ERR_CHAR	'_'
+ #endif /* !defined TZ_ABBR_ERR_CHAR */
+ 
  /*
  ** SunOS 4.1.1 headers lack O_BINARY.
  */
***************
*** 124,129 ****
--- 137,143 ----
  
  static long		detzcode P((const char * codep));
  static const char *	getzname P((const char * strp));
+ static const char *	getqzname P((const char * strp, const char delim));
  static const char *	getnum P((const char * strp, int * nump, int min,
  				int max));
  static const char *	getsecs P((const char * strp, long * secsp));
***************
*** 269,274 ****
--- 283,306 ----
  		tzname[ttisp->tt_isdst] =
  			&sp->chars[ttisp->tt_abbrind];
  	}
+ 	/*
+ 	** Finally, scrub the abbreviations.
+ 	** First, replace bogus characters.
+ 	*/
+ 	for (i = 0; i < sp->charcnt; ++i)
+ 		if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
+ 			sp->chars[i] = TZ_ABBR_ERR_CHAR;
+ 	/*
+ 	** Second, truncate long abbreviations.
+ 	*/
+ 	for (i = 0; i < sp->typecnt; ++i) {
+ 		register const struct ttinfo * const	ttisp = &sp->ttis[i];
+ 		register char *				cp = &sp->chars[ttisp->tt_abbrind];
+ 
+ 		if (strlen(cp) > TZ_ABBR_MAX_LEN &&
+ 			strcmp(cp, GRANDPARENTED) != 0)
+ 				*(cp + TZ_ABBR_MAX_LEN) = '\0';
+ 	}
  }
  
  static int
***************
*** 470,475 ****
--- 502,528 ----
  }
  
  /*
+ ** Given a pointer into an extended time zone string, scan until the ending
+ ** delimiter of the zone name is located.   Return a pointer to the delimiter.
+ **
+ ** As with getzname above, the legal character set is actually quite
+ ** restricted, with other characters producing undefined results.
+ ** We choose not to care - allowing almost anything to be in the zone abbrev.
+ */
+ 
+ static const char *
+ getqzname(strp, delim)
+ register const char *	strp;
+ const char		delim;
+ {
+ 	register char	c;
+ 
+ 	while ((c = *strp) != '\0' && c != delim)
+ 		++strp;
+ 	return strp;
+ }
+ 
+ /*
  ** Given a pointer into a time zone string, extract a number from that string.
  ** Check that the number is within a specified range; if it is not, return
  ** NULL.
***************
*** 753,760 ****
  			stdlen = (sizeof sp->chars) - 1;
  		stdoffset = 0;
  	} else {
! 		name = getzname(name);
! 		stdlen = name - stdname;
  		if (stdlen < 3)
  			return -1;
  		if (*name == '\0')
--- 806,823 ----
  			stdlen = (sizeof sp->chars) - 1;
  		stdoffset = 0;
  	} else {
! 		if (*name == '<') {
! 			name++;
! 			stdname = name;
! 			name = getqzname(name, '>');
! 			if (*name != '>')
! 				return (-1);
! 			stdlen = name - stdname;
! 			name++;
! 		} else {
! 			name = getzname(name);
! 			stdlen = name - stdname;
! 		}
  		if (stdlen < 3)
  			return -1;
  		if (*name == '\0')
***************
*** 767,775 ****
  	if (load_result != 0)
  		sp->leapcnt = 0;		/* so, we're off a little */
  	if (*name != '\0') {
! 		dstname = name;
! 		name = getzname(name);
! 		dstlen = name - dstname;	/* length of DST zone name */
  		if (dstlen < 3)
  			return -1;
  		if (*name != '\0' && *name != ',' && *name != ';') {
--- 830,847 ----
  	if (load_result != 0)
  		sp->leapcnt = 0;		/* so, we're off a little */
  	if (*name != '\0') {
! 		if (*name == '<') {
! 			dstname = ++name;
! 			name = getqzname(name, '>');
! 			if (*name != '>')
! 				return -1;
! 			dstlen = name - dstname;
! 			name++;
! 		} else {
! 			dstname = name;
! 			name = getzname(name);
! 			dstlen = name - dstname; /* length of DST zone name */
! 		}
  		if (dstlen < 3)
  			return -1;
  		if (*name != '\0' && *name != ',' && *name != ';') {
diff -r -c old/private.h new/private.h
*** old/private.h	Mon Apr  4 11:24:32 2005
--- new/private.h	Thu May 26 14:54:07 2005
***************
*** 25,30 ****
--- 25,32 ----
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
+ #define GRANDPARENTED	"Local time zone must be set--see zic manual page"
+ 
  /*
  ** Defaults for preprocessor symbols.
  ** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
diff -r -c old/solar87 new/solar87
*** old/solar87	Thu Apr 21 15:04:16 2005
--- new/solar87	Thu May 26 12:42:35 2005
***************
*** 1,4 ****
! # @(#)solar87	7.3
  
  # So much for footnotes about Saudi Arabia.
  # Apparent noon times below are for Riyadh; your mileage will vary.
--- 1,4 ----
! # @(#)solar87	7.4
  
  # So much for footnotes about Saudi Arabia.
  # Apparent noon times below are for Riyadh; your mileage will vary.
***************
*** 381,388 ****
  # Before and after 1987, we'll operate on local mean solar time.
  
  # Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
! Zone	Asia/Riyadh87	3:07:04	-		??	1987
! 			3:07:04	sol87		??	1988
! 			3:07:04	-		??
  # For backward compatibility...
  Link	Asia/Riyadh87	Mideast/Riyadh87
--- 381,388 ----
  # Before and after 1987, we'll operate on local mean solar time.
  
  # Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
! Zone	Asia/Riyadh87	3:07:04	-		zzz	1987
! 			3:07:04	sol87		zzz	1988
! 			3:07:04	-		zzz
  # For backward compatibility...
  Link	Asia/Riyadh87	Mideast/Riyadh87
diff -r -c old/solar88 new/solar88
*** old/solar88	Thu Apr 21 15:04:16 2005
--- new/solar88	Thu May 26 12:42:35 2005
***************
*** 1,4 ****
! # @(#)solar88	7.3
  
  # Apparent noon times below are for Riyadh; they're a bit off for other places.
  # Times were computed using formulas in the U.S. Naval Observatory's
--- 1,4 ----
! # @(#)solar88	7.4
  
  # Apparent noon times below are for Riyadh; they're a bit off for other places.
  # Times were computed using formulas in the U.S. Naval Observatory's
***************
*** 381,388 ****
  # Before and after 1988, we'll operate on local mean solar time.
  
  # Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
! Zone	Asia/Riyadh88	3:07:04	-		??	1988
! 			3:07:04	sol88		??	1989
! 			3:07:04	-		??
  # For backward compatibility...
  Link	Asia/Riyadh88	Mideast/Riyadh88
--- 381,388 ----
  # Before and after 1988, we'll operate on local mean solar time.
  
  # Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
! Zone	Asia/Riyadh88	3:07:04	-		zzz	1988
! 			3:07:04	sol88		zzz	1989
! 			3:07:04	-		zzz
  # For backward compatibility...
  Link	Asia/Riyadh88	Mideast/Riyadh88
diff -r -c old/solar89 new/solar89
*** old/solar89	Thu Apr 21 15:04:16 2005
--- new/solar89	Thu May 26 12:42:35 2005
***************
*** 1,4 ****
! # @(#)solar89	7.4
  
  # Apparent noon times below are for Riyadh; they're a bit off for other places.
  # Times were computed using a formula provided by the U. S. Naval Observatory:
--- 1,4 ----
! # @(#)solar89	7.5
  
  # Apparent noon times below are for Riyadh; they're a bit off for other places.
  # Times were computed using a formula provided by the U. S. Naval Observatory:
***************
*** 386,393 ****
  # Before and after 1989, we'll operate on local mean solar time.
  
  # Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
! Zone	Asia/Riyadh89	3:07:04	-		??	1989
! 			3:07:04	sol89		??	1990
! 			3:07:04	-		??
  # For backward compatibility...
  Link	Asia/Riyadh89	Mideast/Riyadh89
--- 386,393 ----
  # Before and after 1989, we'll operate on local mean solar time.
  
  # Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
! Zone	Asia/Riyadh89	3:07:04	-		zzz	1989
! 			3:07:04	sol89		zzz	1990
! 			3:07:04	-		zzz
  # For backward compatibility...
  Link	Asia/Riyadh89	Mideast/Riyadh89
diff -r -c old/zdump.c new/zdump.c
*** old/zdump.c	Mon Apr  4 11:24:32 2005
--- new/zdump.c	Thu May 26 12:48:56 2005
***************
*** 1,4 ****
! static char	elsieid[] = "@(#)zdump.c	7.64";
  
  /*
  ** This code has been made independent of the rest of the time
--- 1,4 ----
! static char	elsieid[] = "@(#)zdump.c	7.65";
  
  /*
  ** This code has been made independent of the rest of the time
***************
*** 144,151 ****
--- 144,153 ----
  static time_t	absolute_max_time;
  static size_t	longest;
  static char *	progname;
+ static int	warned;
  
  static char *	abbr P((struct tm * tmp));
+ static void	abbrok P((const char * abbr, const char * zone));
  static long	delta P((struct tm * newp, struct tm * oldp));
  static void	dumptime P((const struct tm * tmp));
  static time_t	hunt P((char * name, time_t lot, time_t	hit));
***************
*** 191,196 ****
--- 193,236 ----
  }
  #endif /* !defined TYPECHECK */
  
+ static void
+ abbrok(abbr, zone)
+ const char * const	abbr;
+ const char * const	zone;
+ {
+ 	register int		i;
+ 	register const char *	cp;
+ 	register char *		wp;
+ 
+ 	if (warned)
+ 		return;
+ 	cp = abbr;
+ 	wp = NULL;
+ 	while (isascii(*cp) && isalpha(*cp))
+ 		++cp;
+ 	if (cp - abbr == 0)
+ 		wp = _("lacks alphabetic at start");
+ 	if (cp - abbr < 3)
+ 		wp = _("has fewer than 3 alphabetics");
+ 	if (cp - abbr > 6)
+ 		wp = _("has more than 6 alphabetics");
+ 	if (wp == NULL && (*cp == '+' || *cp == '-')) {
+ 		++cp;
+ 		if (isascii(*cp) && isdigit(*cp))
+ 			if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
+ 				++cp;
+ 	}
+ 	if (*cp != '\0')
+ 		wp = _("differs from POSIX standard");
+ 	if (wp == NULL)
+ 		return;
+ 	(void) fflush(stdout);
+ 	(void) fprintf(stderr,
+ 		"%s: warning: zone \"%s\" abbreviation \"%s\" %s\n",
+ 		progname, zone, abbr, wp);
+ 	warned = TRUE;
+ }
+ 
  int
  main(argc, argv)
  int	argc;
***************
*** 297,302 ****
--- 337,343 ----
  			show(argv[i], now, FALSE);
  			continue;
  		}
+ 		warned = FALSE;
  		t = absolute_min_time;
  		show(argv[i], t, TRUE);
  		t += SECSPERHOUR * HOURSPERDAY;
***************
*** 527,532 ****
--- 568,575 ----
  		}
  	}
  	(void) printf("\n");
+ 	if (tmp != NULL && *abbr(tmp) != '\0')
+ 		abbrok(abbr(tmp), zone);
  }
  
  static char *
diff -r -c old/zic.c new/zic.c
*** old/zic.c	Mon Apr  4 11:24:32 2005
--- new/zic.c	Thu May 26 14:54:07 2005
***************
*** 1,4 ****
! static char	elsieid[] = "@(#)zic.c	7.122";
  
  /*
  ** Regardless of the type of time_t, we do our work using this type.
--- 1,4 ----
! static char	elsieid[] = "@(#)zic.c	7.124";
  
  /*
  ** Regardless of the type of time_t, we do our work using this type.
***************
*** 10,15 ****
--- 10,19 ----
  #include "locale.h"
  #include "tzfile.h"
  
+ #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
+ #define ZIC_MAX_ABBR_LEN_WO_WARN	6
+ #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
+ 
  #if HAVE_SYS_STAT_H
  #include "sys/stat.h"
  #endif
***************
*** 2196,2201 ****
--- 2200,2240 ----
  {
  	register int	i;
  
+ 	if (strcmp(string, GRANDPARENTED) != 0) {
+ 		register const char *	cp;
+ 		register char *		wp;
+ 
+ 		/*
+ 		** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
+ 		** optionally followed by a + or - and a number from 1 to 14.
+ 		*/
+ 		cp = string;
+ 		wp = NULL;
+ 		while (isascii(*cp) && isalpha(*cp))
+ 			++cp;
+ 		if (cp - string == 0)
+ wp = _("time zone abbreviation lacks alphabetic at start");
+ 		if (noise && cp - string > 3)
+ wp = _("time zone abbreviation has more than 3 alphabetics");
+ 		if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
+ wp = _("time zone abbreviation has too many alphabetics");
+ 		if (wp == NULL && (*cp == '+' || *cp == '-')) {
+ 			++cp;
+ 			if (isascii(*cp) && isdigit(*cp))
+ 				if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
+ 					++cp;
+ 		}
+ 		if (*cp != '\0')
+ wp = _("time zone abbreviation differs from POSIX standard");
+ 		if (wp != NULL) {
+ 			wp = ecpyalloc(wp);
+ 			wp = ecatalloc(wp, " (");
+ 			wp = ecatalloc(wp, string);
+ 			wp = ecatalloc(wp, ")");
+ 			warning(wp);
+ 			ifree(wp);
+ 		}
+ 	}
  	i = strlen(string) + 1;
  	if (charcnt + i > TZ_MAX_CHARS) {
  		error(_("too many, or too long, time zone abbreviations"));



More information about the tz mailing list