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);
}