Here are some proposed changes to strftime.c: Use ISO standard date format for %x; this is more appropriate than the American date format, which confuses non-Americans. Especially for dates like 01/02/03; the ISO date 2003-01-02 is much clearer for everybody, and it sorts correctly too. _conv fails when n is negative, and it's hard to get it exactly right when n is INT_MIN. Why not let sprintf do the work? The buffer inside _conv might overflow with 64-bit ints. Use `const' when possible, so that the data can be shared in the read-only text segment. Use function prototypes when possible, to keep lint checkers happy. There's a /* in a comment just before `You are understood not to expect this.' Here's a patch. *** draft-strftime.c Tue May 25 10:39:33 1993 --- draft-strftime1.c Tue May 25 11:28:38 1993 *************** *** 1,6 **** #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)strftime.c 7.4"; /* ** Based on the UCB version whose ID appears below. ** This is ANSIish only when time is treated identically in all locales and --- 1,6 ---- #ifndef lint #ifndef NOID ! static const char elsieid[] = "@(#)strftime.c 7.4"; /* ** Based on the UCB version whose ID appears below. ** This is ANSIish only when time is treated identically in all locales and *************** *** 26,64 **** */ #if defined(LIBC_SCCS) && !defined(lint) ! static char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89"; #endif /* LIBC_SCCS and not lint */ ! #include "sys/types.h" ! #include "time.h" #include "tzfile.h" ! static char *afmt[] = { ! "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", }; ! static char *Afmt[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", ! "Saturday", }; ! static char *bfmt[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", ! "Oct", "Nov", "Dec", }; ! static char *Bfmt[] = { "January", "February", "March", "April", "May", "June", "July", ! "August", "September", "October", "November", "December", }; ! static char *_add(); ! static char *_conv(); ! static char *_fmt(); size_t strftime(s, maxsize, format, t) char *s; size_t maxsize; ! char *format; ! struct tm *t; { size_t gsize; --- 26,65 ---- */ #if defined(LIBC_SCCS) && !defined(lint) ! static const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89"; #endif /* LIBC_SCCS and not lint */ ! #include "private.h" #include "tzfile.h" ! static const char * const afmt[] = { ! "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; ! static const char * const Afmt[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", ! "Saturday" }; ! static const char * const bfmt[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", ! "Oct", "Nov", "Dec" }; ! static const char * const Bfmt[] = { "January", "February", "March", "April", "May", "June", "July", ! "August", "September", "October", "November", "December" }; ! static char *_add P((const char *, size_t *, char *)); ! static char *_conv P((int, const char *, size_t *, char *)); ! static char *_fmt P((const char *, const struct tm *, size_t *, char *)); + size_t strftime P((char *, size_t, const char *, const struct tm *)); + size_t strftime(s, maxsize, format, t) char *s; size_t maxsize; ! const char *format; ! const struct tm *t; { size_t gsize; *************** *** 72,79 **** static char * _fmt(format, t, gsizep, pt) ! char *format; ! struct tm *t; size_t *gsizep; char *pt; { --- 73,80 ---- static char * _fmt(format, t, gsizep, pt) ! const char *format; ! const struct tm *t; size_t *gsizep; char *pt; { *************** *** 113,119 **** ** (ado, 5/24/93) */ pt = _conv((t->tm_year + TM_YEAR_BASE) / 100, ! 2, '0', gsizep, pt); continue; case 'D': case 'x': --- 114,120 ---- ** (ado, 5/24/93) */ pt = _conv((t->tm_year + TM_YEAR_BASE) / 100, ! "%02d", gsizep, pt); continue; case 'D': case 'x': *************** *** 126,137 **** ** standard calls for "date, using locale's ** date format," anything goes. Using just ** numbers (as here) makes Quakers happier. ! ** (ado, 5/24/93) */ ! pt = _fmt("%m/%d/%y", t, gsizep, pt); continue; case 'd': ! pt = _conv(t->tm_mday, 2, '0', gsizep, pt); continue; case 'E': case 'O': --- 127,138 ---- ** standard calls for "date, using locale's ** date format," anything goes. Using just ** numbers (as here) makes Quakers happier. ! ** This is the ISO standard date format. */ ! pt = _fmt("%Y-%m-%d", t, gsizep, pt); continue; case 'd': ! pt = _conv(t->tm_mday, "%02d", gsizep, pt); continue; case 'E': case 'O': *************** *** 148,165 **** */ goto label; case 'e': ! pt = _conv(t->tm_mday, 2, ' ', gsizep, pt); continue; case 'H': ! pt = _conv(t->tm_hour, 2, '0', gsizep, pt); continue; case 'I': pt = _conv((t->tm_hour % 12) ? (t->tm_hour % 12) : 12, ! 2, '0', gsizep, pt); continue; case 'j': ! pt = _conv(t->tm_yday + 1, 3, '0', gsizep, pt); continue; case 'k': /* --- 149,166 ---- */ goto label; case 'e': ! pt = _conv(t->tm_mday, "%2d", gsizep, pt); continue; case 'H': ! pt = _conv(t->tm_hour, "%02d", gsizep, pt); continue; case 'I': pt = _conv((t->tm_hour % 12) ? (t->tm_hour % 12) : 12, ! "%02d", gsizep, pt); continue; case 'j': ! pt = _conv(t->tm_yday + 1, "%03d", gsizep, pt); continue; case 'k': /* *************** *** 172,178 **** ** "%l" have been swapped. ** (ado, 5/24/93) */ ! pt = _conv(t->tm_hour, 2, ' ', gsizep, pt); continue; #ifdef KITCHEN_SINK case 'K': --- 173,179 ---- ** "%l" have been swapped. ** (ado, 5/24/93) */ ! pt = _conv(t->tm_hour, "%2d", gsizep, pt); continue; #ifdef KITCHEN_SINK case 'K': *************** *** 194,206 **** */ pt = _conv((t->tm_hour % 12) ? (t->tm_hour % 12) : 12, ! 2, ' ', gsizep, pt); continue; case 'M': ! pt = _conv(t->tm_min, 2, '0', gsizep, pt); continue; case 'm': ! pt = _conv(t->tm_mon + 1, 2, '0', gsizep, pt); continue; case 'n': pt = _add("\n", gsizep, pt); --- 195,207 ---- */ pt = _conv((t->tm_hour % 12) ? (t->tm_hour % 12) : 12, ! "%2d", gsizep, pt); continue; case 'M': ! pt = _conv(t->tm_min, "%02d", gsizep, pt); continue; case 'm': ! pt = _conv(t->tm_mon + 1, "%02d", gsizep, pt); continue; case 'n': pt = _add("\n", gsizep, pt); *************** *** 216,222 **** pt = _fmt("%I:%M:%S %p", t, gsizep, pt); continue; case 'S': ! pt = _conv(t->tm_sec, 2, '0', gsizep, pt); continue; case 'T': case 'X': --- 217,223 ---- pt = _fmt("%I:%M:%S %p", t, gsizep, pt); continue; case 'S': ! pt = _conv(t->tm_sec, "%02d", gsizep, pt); continue; case 'T': case 'X': *************** *** 227,233 **** continue; case 'U': pt = _conv((t->tm_yday + 7 - t->tm_wday) / 7, ! 2, '0', gsizep, pt); continue; case 'u': /* --- 228,234 ---- continue; case 'U': pt = _conv((t->tm_yday + 7 - t->tm_wday) / 7, ! "%02d", gsizep, pt); continue; case 'u': /* *************** *** 237,243 **** ** (ado, 5/24/93) */ pt = _conv((t->tm_wday == 0) ? 7 : t->tm_wday, ! 1, '0', gsizep, pt); continue; case 'V': /* --- 238,244 ---- ** (ado, 5/24/93) */ pt = _conv((t->tm_wday == 0) ? 7 : t->tm_wday, ! "%d", gsizep, pt); continue; case 'V': /* *************** *** 260,266 **** ** 1 falls on a Thursday, are December 29-31 ** of the PREVIOUS year part of week 1??? ** (ado 5/24/93) ! /* ** You are understood not to expect this. */ { --- 261,267 ---- ** 1 falls on a Thursday, are December 29-31 ** of the PREVIOUS year part of week 1??? ** (ado 5/24/93) ! ** ** You are understood not to expect this. */ { *************** *** 269,275 **** i = (t->tm_yday + 10 - (t->tm_wday ? (t->tm_wday - 1) : 6)) / 7; pt = _conv((i == 0) ? 53 : i, ! 2, '0', gsizep, pt); } continue; case 'v': --- 270,276 ---- i = (t->tm_yday + 10 - (t->tm_wday ? (t->tm_wday - 1) : 6)) / 7; pt = _conv((i == 0) ? 53 : i, ! "%02d", gsizep, pt); } continue; case 'v': *************** *** 284,300 **** pt = _conv((t->tm_yday + 7 - (t->tm_wday ? (t->tm_wday - 1) : 6)) / 7, ! 2, '0', gsizep, pt); continue; case 'w': ! pt = _conv(t->tm_wday, 1, '0', gsizep, pt); continue; case 'y': pt = _conv((t->tm_year + TM_YEAR_BASE) % 100, ! 2, '0', gsizep, pt); continue; case 'Y': ! pt = _conv(t->tm_year + TM_YEAR_BASE, 4, '0', gsizep, pt); continue; case 'Z': --- 285,301 ---- pt = _conv((t->tm_yday + 7 - (t->tm_wday ? (t->tm_wday - 1) : 6)) / 7, ! "%02d", gsizep, pt); continue; case 'w': ! pt = _conv(t->tm_wday, "%d", gsizep, pt); continue; case 'y': pt = _conv((t->tm_year + TM_YEAR_BASE) % 100, ! "%02d", gsizep, pt); continue; case 'Y': ! pt = _conv(t->tm_year + TM_YEAR_BASE, "%04d", gsizep, pt); continue; case 'Z': *************** *** 329,356 **** } static char * ! _conv(n, width, fill, gsizep, pt) ! int n, width, fill; size_t *gsizep; char *pt; { ! char *p, *q, buf[12]; ! static char digits[] = "0123456789"; ! p = buf + sizeof buf; ! q = (width >= sizeof buf) ? buf : (p - width - 1); ! *--p = '\0'; ! *--p = digits[n % 10]; ! while (p > buf && (n /= 10) != 0) ! *--p = digits[n % 10]; ! while (p > q) ! *--p = fill; ! return _add(p, gsizep, pt); } static char * _add(str, gsizep, pt) ! char *str; size_t *gsizep; char *pt; { --- 330,350 ---- } static char * ! _conv(n, format, gsizep, pt) ! int n; ! const char *format; size_t *gsizep; char *pt; { ! char buf[21]; /* Room for - 2**63 ("-9223372036854775808") + null. */ ! (void) sprintf(buf, format, n); ! return _add(buf, gsizep, pt); } static char * _add(str, gsizep, pt) ! const char *str; size_t *gsizep; char *pt; {