Proposed asctime-related changes

Olson, Arthur David (NIH/NCI) olsona at dc37a.nci.nih.gov
Thu Aug 5 16:04:29 UTC 2004


Below are proposed asctime-related changes to the time zone package; in
particular, documentation and Makefile changes are now included.
I hope to roll out new versions of tzcode and tzdata incorporating these
changes in about a week; I'll then tackle other suggested changes that have
been circulated on the time zone mailing list of late.

				--ado

diff -c -r old/Makefile new/Makefile
*** old/Makefile	Mon Jul 19 14:33:20 2004
--- new/Makefile	Thu Aug  5 10:59:53 2004
***************
*** 1,4 ****
! # @(#)Makefile	7.92
  
  # 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.94
  
  # 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).
***************
*** 103,108 ****
--- 103,110 ----
  #  -DLOCALE_HOME=\"path\" if locales are in "path", not "/usr/lib/locale"
  #  -DHAVE_UNISTD_H=0 if your compiler lacks a "unistd.h" (Microsoft C++
7?)
  #  -DHAVE_UTMPX_H=1 if your compiler has a "utmpx.h"
+ #  -DSTRICTLY_STANDARD_ASCTIME=1 if you want a strictly standard (and
arguably
+ #	broken) version of asctime (see asctime.c for details)	
  #  -DTZDEFRULESTRING=\",date/time,date/time\" to default to the specified
  #	DST transitions if the time zone files cannot be accessed
  #  -DTZ_DOMAIN=\"foo\" to use "foo" for gettext domain name; default is
"tz"
***************
*** 244,251 ****
  
  TZCSRCS=	zic.c localtime.c asctime.c scheck.c ialloc.c
  TZCOBJS=	zic.o localtime.o asctime.o scheck.o ialloc.o
! TZDSRCS=	zdump.c localtime.c asctime.c ialloc.c
! TZDOBJS=	zdump.o localtime.o asctime.o ialloc.o
  DATESRCS=	date.c localtime.c logwtmp.c strftime.c asctime.c
  DATEOBJS=	date.o localtime.o logwtmp.o strftime.o asctime.o
  LIBSRCS=	localtime.c asctime.c difftime.c
--- 246,253 ----
  
  TZCSRCS=	zic.c localtime.c asctime.c scheck.c ialloc.c
  TZCOBJS=	zic.o localtime.o asctime.o scheck.o ialloc.o
! TZDSRCS=	zdump.c localtime.c ialloc.c
! TZDOBJS=	zdump.o localtime.o ialloc.o
  DATESRCS=	date.c localtime.c logwtmp.c strftime.c asctime.c
  DATEOBJS=	date.o localtime.o logwtmp.o strftime.o asctime.o
  LIBSRCS=	localtime.c asctime.c difftime.c
diff -c -r old/asctime.c new/asctime.c
*** old/asctime.c	Mon Jul 19 14:33:22 2004
--- new/asctime.c	Thu Aug  5 10:21:02 2004
***************
*** 5,11 ****
  
  #ifndef lint
  #ifndef NOID
! static char	elsieid[] = "@(#)asctime.c	7.9";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
--- 5,11 ----
  
  #ifndef lint
  #ifndef NOID
! static char	elsieid[] = "@(#)asctime.c	7.19";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
***************
*** 14,23 ****
  #include "private.h"
  #include "tzfile.h"
  
  /*
! ** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, Second Edition, 1996-07-12.
  */
  
  char *
  asctime_r(timeptr, buf)
  register const struct tm *	timeptr;
--- 14,65 ----
  #include "private.h"
  #include "tzfile.h"
  
+ #if STRICTLY_STANDARD_ASCTIME
+ #define ASCTIME_FMT	"%.3s %.3s%3d %.2d:%.2d:%.2d %ld\n"
+ #define ASCTIME_FMT_B	ASCTIME_FMT
+ #else /* !STRICTLY_STANDARD_ASCTIME */
  /*
! ** Some systems only handle "%.2d"; others only handle "%02d";
! ** "%02.2d" makes (most) everybody happy.
! ** At least some versions of gcc warn about the %02.2d; ignore the
warning.
  */
+ /*
+ ** All years associated with 32-bit time_t values are exactly four digits
long;
+ ** some years associated with 64-bit time_t values are not.
+ ** Vintage programs are coded for years that are always four digits long
+ ** and may assume that the newline always lands in the same place.
+ ** For years that are less than four digits, we pad the output with
+ ** spaces before the newline to get the newline in the traditional place.
+ */
+ #define ASCTIME_FMT	"%.3s %.3s%3d %02.2d:%02.2d:%02.2d %-4ld\n"
+ /*
+ ** For years that are more than four digits we put extra spaces before the
year
+ ** so that code trying to overwrite the newline won't end up overwriting
+ ** a digit within a year and truncating the year (operating on the
assumption
+ ** that no output is better than wrong output).
+ */
+ #define ASCTIME_FMT_B	"%.3s %.3s%3d %02.2d:%02.2d:%02.2d     %ld\n"
+ #endif /* !STRICTLY_STANDARD_ASCTIME */
  
+ #define STD_ASCTIME_BUF_SIZE	26
+ /*
+ ** Big enough for something such as
+ ** ??? ???-2147483648 -2147483648:-2147483648:-2147483648
-2147483648\n
+ ** (two three-character abbreviations, five strings denoting integers,
+ ** seven explicit spaces, two explicit colons, a newline,
+ ** and a trailing ASCII nul).
+ ** The values above are for systems where an int is 32 bits and are
provided
+ ** as an example; the define below calculates the maximum for the system
at
+ ** hand.
+ */
+ #define MAX_ASCTIME_BUF_SIZE	(2*3+5*INT_STRLEN_MAXIMUM(int)+7+2+1+1)
+ 
+ static char	buf_asctime[MAX_ASCTIME_BUF_SIZE];
+ 
+ /*
+ ** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, 2004 Edition.
+ */
+ 
  char *
  asctime_r(timeptr, buf)
  register const struct tm *	timeptr;
***************
*** 32,37 ****
--- 74,81 ----
  	};
  	register const char *	wn;
  	register const char *	mn;
+ 	long			year;
+ 	char			result[MAX_ASCTIME_BUF_SIZE];
  
  	if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)
  		wn = "???";
***************
*** 39,59 ****
  	if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
  		mn = "???";
  	else	mn = mon_name[timeptr->tm_mon];
  	/*
! 	** The X3J11-suggested format is
! 	**	"%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n"
! 	** Since the .2 in 02.2d is ignored, we drop it.
  	*/
! 	(void) sprintf(buf, "%.3s %.3s%3d %02d:%02d:%02d %d\n",
  		wn, mn,
  		timeptr->tm_mday, timeptr->tm_hour,
  		timeptr->tm_min, timeptr->tm_sec,
! 		TM_YEAR_BASE + timeptr->tm_year);
! 	return buf;
  }
  
  /*
! ** A la X3J11, with core dump avoidance.
  */
  
  char *
--- 83,113 ----
  	if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
  		mn = "???";
  	else	mn = mon_name[timeptr->tm_mon];
+ 	year = timeptr->tm_year + (long) TM_YEAR_BASE;
  	/*
! 	** We avoid using snprintf since it's not available on all systems.
  	*/
! 	(void) sprintf(result,
! 		((year >= -999 && year <= 9999) ? ASCTIME_FMT :
ASCTIME_FMT_B),
  		wn, mn,
  		timeptr->tm_mday, timeptr->tm_hour,
  		timeptr->tm_min, timeptr->tm_sec,
! 		year);
! 	if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime) {
! 		(void) strcpy(buf, result);
! 		return buf;
! 	} else {
! #ifdef EOVERFLOW
! 		errno = EOVERFLOW;
! #else /* !defined EOVERFLOW */
! 		errno = EINVAL;
! #endif /* !defined EOVERFLOW */
! 		return NULL;
! 	}
  }
  
  /*
! ** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, 2004 Edition.
  */
  
  char *
***************
*** 60,74 ****
  asctime(timeptr)
  register const struct tm *	timeptr;
  {
! 	/*
! 	** Big enough for something such as
! 	** ??? ???-2147483648 -2147483648:-2147483648:-2147483648
-2147483648\n
! 	** (two three-character abbreviations, five strings denoting
integers,
! 	** three explicit spaces, two explicit colons, a newline,
! 	** and a trailing ASCII nul).
! 	*/
! 	static char		result[3 * 2 + 5 * INT_STRLEN_MAXIMUM(int) +
! 					3 + 2 + 1 + 1];
! 
! 	return asctime_r(timeptr, result);
  }
--- 114,118 ----
  asctime(timeptr)
  register const struct tm *	timeptr;
  {
! 	return asctime_r(timeptr, buf_asctime);
  }
diff -c -r old/newctime.3 new/newctime.3
*** old/newctime.3	Mon Jul 19 14:33:21 2004
--- new/newctime.3	Thu Aug  5 11:49:18 2004
***************
*** 39,53 ****
  representing the time in seconds since
  00:00:00 UTC, 1970-01-01,
  and returns a pointer to a
! 26-character string
! of the form
  .br
  .ce
  .eo
  Thu Nov 24 18:22:48 1986\n\0
  .ec
  .br
! All the fields have constant width.
  .PP
  .IR Localtime\^
  and
--- 39,59 ----
  representing the time in seconds since
  00:00:00 UTC, 1970-01-01,
  and returns a pointer to a
! string of the form
  .br
  .ce
  .eo
  Thu Nov 24 18:22:48 1986\n\0
+ .br
+ .ce
  .ec
+ For years longer than four characters, the string is of the form
  .br
! .ce
! .eo
! Thu Nov 24 18:22:48     81986\n\0
! .ec
! .br
  .PP
  .IR Localtime\^
  and
***************
*** 72,81 ****
  .PP
  .I Asctime\^
  converts a time value contained in a
! ``tm'' structure to a 26-character string,
  as shown in the above example,
! and returns a pointer
! to the string.
  .PP
  .I Mktime\^
  converts the broken-down time,
--- 78,86 ----
  .PP
  .I Asctime\^
  converts a time value contained in a
! ``tm'' structure to a string,
  as shown in the above example,
! and returns a pointer to the string.
  .PP
  .I Mktime\^
  converts the broken-down time,
***************
*** 211,214 ****
  Avoid using out-of-range values with
  .I mktime
  when setting up lunch with promptness sticklers in Riyadh.
! .\" @(#)newctime.3	7.14
--- 216,219 ----
  Avoid using out-of-range values with
  .I mktime
  when setting up lunch with promptness sticklers in Riyadh.
! .\" @(#)newctime.3	7.15
diff -c -r old/newctime.3.txt new/newctime.3.txt
*** old/newctime.3.txt	Mon Jul 19 14:33:34 2004
--- new/newctime.3.txt	Thu Aug  5 11:49:27 2004
***************
*** 36,45 ****
  DESCRIPTION
       Ctime converts a long integer, pointed to by clock,
       representing the time in seconds since 00:00:00 UTC, 1970-
!      01-01, and returns a pointer to a 26-character string of the
!      form
                       Thu Nov 24 18:22:48 1986\n\0
!      All the fields have constant width.
  
       Localtime and gmtime return pointers to ``tm'' structures,
       described below.  Localtime corrects for the time zone and
--- 36,45 ----
  DESCRIPTION
       Ctime converts a long integer, pointed to by clock,
       representing the time in seconds since 00:00:00 UTC, 1970-
!      01-01, and returns a pointer to a string of the form
                       Thu Nov 24 18:22:48 1986\n\0
!      For years longer than four characters, the string is of the form
!                   Thu Nov 24 18:22:48     81986\n\0
  
       Localtime and gmtime return pointers to ``tm'' structures,
       described below.  Localtime corrects for the time zone and
***************
*** 52,59 ****
       Gmtime converts to Coordinated Universal Time.
  
       Asctime converts a time value contained in a ``tm''
!      structure to a 26-character string, as shown in the above
!      example, and returns a pointer to the string.
  
       Mktime converts the broken-down time, expressed as local
       time, in the structure pointed to by tm into a calendar time
--- 52,59 ----
       Gmtime converts to Coordinated Universal Time.
  
       Asctime converts a time value contained in a ``tm''
!      structure to a string, as shown in the above example, and
!      returns a pointer to the string.
  
       Mktime converts the broken-down time, expressed as local
       time, in the structure pointed to by tm into a calendar time
diff -c -r old/zdump.c new/zdump.c
*** old/zdump.c	Mon Jul 19 14:33:22 2004
--- new/zdump.c	Thu Aug  5 10:48:37 2004
***************
*** 1,4 ****
! static char	elsieid[] = "@(#)zdump.c	7.33";
  
  /*
  ** This code has been made independent of the rest of the time
--- 1,4 ----
! static char	elsieid[] = "@(#)zdump.c	7.34";
  
  /*
  ** This code has been made independent of the rest of the time
***************
*** 129,134 ****
--- 129,135 ----
  static size_t	longest;
  static char *	progname;
  static void	show P((char * zone, time_t t, int v));
+ static void	dumptime P((const struct tm * tmp));
  
  int
  main(argc, argv)
***************
*** 343,352 ****
  	struct tm *	tmp;
  
  	(void) printf("%-*s  ", (int) longest, zone);
! 	if (v)
! 		(void) printf("%.24s UTC = ", asctime(gmtime(&t)));
  	tmp = localtime(&t);
! 	(void) printf("%.24s", asctime(tmp));
  	if (*abbr(tmp) != '\0')
  		(void) printf(" %s", abbr(tmp));
  	if (v) {
--- 344,355 ----
  	struct tm *	tmp;
  
  	(void) printf("%-*s  ", (int) longest, zone);
! 	if (v) {
! 		dumptime(gmtime(&t));
! 		(void) printf(" UTC = ");
! 	}
  	tmp = localtime(&t);
! 	dumptime(tmp);
  	if (*abbr(tmp) != '\0')
  		(void) printf(" %s", abbr(tmp));
  	if (v) {
***************
*** 369,372 ****
--- 372,404 ----
  		return &nada;
  	result = tzname[tmp->tm_isdst];
  	return (result == NULL) ? &nada : result;
+ }
+ 
+ static void
+ dumptime(timeptr)
+ register const struct tm *	timeptr;
+ {
+ 	static const char	wday_name[][3] = {
+ 		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ 	};
+ 	static const char	mon_name[][3] = {
+ 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ 	};
+ 	register const char *	wn;
+ 	register const char *	mn;
+ 
+ 	if (timeptr->tm_wday < 0 ||
+ 		timeptr->tm_wday >= sizeof wday_name / sizeof wday_name[0])
+ 			wn = "???";
+ 	else		wn = wday_name[timeptr->tm_wday];
+ 	if (timeptr->tm_mon < 0 ||
+ 		timeptr->tm_mon >= sizeof mon_name / sizeof mon_name[0])
+ 			mn = "???";
+ 	else		mn = mon_name[timeptr->tm_mon];
+ 	(void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d %ld",
+ 		wn, mn,
+ 		timeptr->tm_mday, timeptr->tm_hour,
+ 		timeptr->tm_min, timeptr->tm_sec,
+ 		timeptr->tm_year + (long) TM_YEAR_BASE);
  }



More information about the tz mailing list