support for C99 strftime %F and %z formats, plus Solaris 8 fix

Paul Eggert eggert at twinsun.com
Thu Apr 13 19:16:41 UTC 2000


The new C Standard specifies two new formats for strftime: %F and %z.
Here's a proposed patch to add support for this.  I ran into a Solaris 8
porting problem when debugging this, and enclose a patch for this as well.

===================================================================
RCS file: RCS/Makefile,v
retrieving revision 2000.1
retrieving revision 2000.1.0.1
diff -pu -r2000.1 -r2000.1.0.1
--- Makefile	2000/01/18 14:21:10	2000.1
+++ Makefile	2000/04/13 19:11:13	2000.1.0.1
@@ -88,6 +88,8 @@ LDLIBS=
 # Add the following to the end of the "CFLAGS=" line as needed.
 #  -DHAVE_ADJTIME=0 if `adjtime' does not exist (SVR0?)
 #  -DHAVE_GETTEXT=1 if `gettext' works (GNU, Linux, Solaris); also see LDLIBS
+#  -DHAVE_INCOMPATIBLE_CTIME_R=1 if your system's time.h declares
+#	ctime_r and asctime_r incompatibly with the POSIX standard.
 #  -DHAVE_LONG_DOUBLE=1 if your compiler supports the `long double' type
 #  -DHAVE_SETTIMEOFDAY=0 if settimeofday does not exist (SVR0?)
 #  -DHAVE_SETTIMEOFDAY=1 if settimeofday has just 1 arg (SVR4)
===================================================================
RCS file: RCS/private.h,v
retrieving revision 1999.5
retrieving revision 1999.5.0.1
diff -pu -r1999.5 -r1999.5.0.1
--- private.h	1999/08/17 18:09:09	1999.5
+++ private.h	2000/04/13 19:11:13	1999.5.0.1
@@ -38,6 +38,10 @@ static char	privatehid[] = "@(#)private.
 #define HAVE_GETTEXT		0
 #endif /* !defined HAVE_GETTEXT */
 
+#ifndef HAVE_INCOMPATIBLE_CTIME_R
+#define HAVE_INCOMPATIBLE_CTIME_R	1
+#endif /* !defined INCOMPATIBLE_CTIME_R */
+
 #ifndef HAVE_SETTIMEOFDAY
 #define HAVE_SETTIMEOFDAY	3
 #endif /* !defined HAVE_SETTIMEOFDAY */
@@ -66,6 +70,11 @@ static char	privatehid[] = "@(#)private.
 #define LOCALE_HOME		"/usr/lib/locale"
 #endif /* !defined LOCALE_HOME */
 
+#if HAVE_INCOMPATIBLE_CTIME_R
+#define asctime_r _incompatible_asctime_r
+#define ctime_r _incompatible_ctime_r
+#endif /* HAVE_INCOMPATIBLE_CTIME_R */
+
 /*
 ** Nested includes
 */
@@ -203,6 +212,28 @@ void	icfree P((char * pointer));
 void	ifree P((char * pointer));
 char *	scheck P((const char *string, const char *format));
 
+/*
+** External declarations, possibly renamed to private identifiers.
+*/
+#ifndef USG_COMPAT
+#define timezone _timezone
+#define daylight _daylight
+#endif
+#ifndef ALTZONE
+#define altzone _altzone
+#endif
+/* strftime needs these variables if TM_GMTOFF is not defined.  */
+#ifndef TM_GMTOFF
+#define USG_COMPAT
+#define ALTZONE
+#endif
+#ifdef USG_COMPAT
+extern time_t timezone;
+extern int daylight;
+#endif
+#ifdef ALTZONE
+extern time_t altzone;
+#endif
 
 /*
 ** Finally, some convenience items.
@@ -277,6 +308,13 @@ char *	scheck P((const char *string, con
 #define TZ_DOMAIN "tz"
 #endif /* !defined TZ_DOMAIN */
 
+#if HAVE_INCOMPATIBLE_CTIME_R
+#undef asctime_r
+#undef ctime_r
+char *asctime_r P((struct tm const *, char *));
+char *ctime_r P((time_t const *, char *));
+#endif /* HAVE_INCOMPATIBLE_CTIME_R */
+
 /*
 ** UNIX was a registered trademark of UNIX System Laboratories in 1993.
 */
===================================================================
RCS file: RCS/strftime.c,v
retrieving revision 1999.9
retrieving revision 1999.9.0.1
diff -pu -r1999.9 -r1999.9.0.1
--- strftime.c	1999/11/08 19:54:36	1999.9
+++ strftime.c	2000/04/13 19:11:13	1999.9.0.1
@@ -247,6 +247,9 @@ label:
 			case 'e':
 				pt = _conv(t->tm_mday, "%2d", pt, ptlim);
 				continue;
+			case 'F':
+				pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
+				continue;
 			case 'H':
 				pt = _conv(t->tm_hour, "%02d", pt, ptlim);
 				continue;
@@ -489,10 +492,46 @@ label:
 					pt = _add(t->TM_ZONE, pt, ptlim);
 				else
 #endif /* defined TM_ZONE */
-				if (t->tm_isdst == 0 || t->tm_isdst == 1) {
-					pt = _add(tzname[t->tm_isdst],
+				if (0 <= t->tm_isdst)
+					pt = _add(tzname[t->tm_isdst != 0],
 						pt, ptlim);
-				} else  pt = _add("?", pt, ptlim);
+				continue;
+			case 'z':
+				{
+				int diff;
+				char const *sign;
+				if (t->tm_isdst < 0)
+					continue;
+#ifdef TM_GMTOFF
+				diff = t->TM_GMTOFF;
+#else /* !defined TM_GMTOFF */
+				/*
+				** C99 says that the UTC offset must
+				** be computed by looking only at
+				** tm_isdst.  This requirement is
+				** incorrect, since it means the code
+				** must rely on magic (in this case
+				** altzone and timezone), and the
+				** magic might not have the correct
+				** offset.  Doing things correctly is
+				** tricky and requires disobeying C99;
+				** see GNU C strftime for details.
+				** For now, punt and conform to the
+				** standard, even though it's incorrect.
+				**
+				*/
+				diff = - (t->tm_isdst ? altzone : timezone);
+#endif /* !defined TM_GMTOFF */
+				if (diff < 0) {
+					sign = "-";
+					diff = -diff;
+				} else
+					sign = "+";
+				pt = _add(sign, pt, ptlim);
+				diff /= 60;
+				pt = _conv((diff/60)*100 + diff%60,
+					"%04d", pt, ptlim);
+				}
 				continue;
 			case '+':
 				pt = _fmt(Locale->date_fmt, t, pt, ptlim,



More information about the tz mailing list