At the end of this message you'll find proposed changes to strftime.c to do the right thing for wide-ranging years. I compiled it with this quick-and-dirty source code... #include "stdio.h" #include "sys/types.h" #include "time.h" static int years[] = { 10001, 10000, 9999, 1001, 1000, 999, 101, 100, 99, 11, 10, 9, 1, 0, -1, -9, -10, -11, -99, -100, -101, -999, -1000, -1001, -9999, -10000, -10001 }; #define NVALUES ((sizeof years) / (sizeof years[0])) static char * formats[] = { "%C", "%y", "%G", "%g" }; #define NFORMATS ((sizeof formats) / (sizeof formats[0])) #define TM_BASE_YEAR 1900 main() { static struct tm tm; int i; int j; char buf[1024]; tm.tm_mon = 0; /* months since January => January */ tm.tm_mday = 8; /* day of the month */ tm.tm_yday = 7; /* days since January 1 */ (void) printf("YEAR"); for (j = 0; j < NFORMATS; ++j) { (void) printf("\t%s", formats[j]); } (void) printf("\n"); for (i = 0; i < NVALUES; ++i) { (void) printf("%d", years[i]); tm.tm_year = years[i] - TM_BASE_YEAR; for (j = 0; j < NFORMATS; ++j) { (void) strftime(buf, sizeof buf, formats[j], &tm); (void) printf("\t%s", buf); } (void) printf("\n"); } return 0; } ...and got these results... YEAR %C %y %G %g 10001 100 01 10001 01 10000 100 00 10000 00 9999 99 99 9999 99 1001 10 01 1001 01 1000 10 00 1000 00 999 09 99 0999 99 101 01 01 0101 01 100 01 00 0100 00 99 00 99 0099 99 11 00 11 0011 11 10 00 10 0010 10 9 00 09 0009 09 1 00 01 0001 01 0 00 00 0000 00 -1 -0 01 -001 01 -9 -0 09 -009 09 -10 -0 10 -010 10 -11 -0 11 -011 11 -99 -0 99 -099 99 -100 -1 00 -100 00 -101 -1 01 -101 01 -999 -9 99 -999 99 -1000 -10 00 -1000 00 -1001 -10 01 -1001 01 -9999 -99 99 -9999 99 -10000 -100 00 -10000 00 -10001 -100 01 -10001 01 Absent any objections, I'll promulgate these changes next week (along with Paul Eggert's revised update to tz-link.htm). --ado ------- strftime.c ------- *** /tmp/geta12949 Thu Sep 23 15:27:03 2004 --- /tmp/getb12949 Thu Sep 23 15:27:03 2004 *************** *** 1,12 **** - /* - ** XXX To do: figure out correct (as distinct from standard-mandated) - ** output for "two digits of year" and "century" formats when - ** the year is negative or less than 100. --ado, 2004-09-09 - */ - #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)strftime.c 7.67"; /* ** Based on the UCB version with the ID appearing below. ** This is ANSIish only when "multibyte character == plain character". --- 1,6 ---- #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)strftime.c 7.69"; /* ** Based on the UCB version with the ID appearing below. ** This is ANSIish only when "multibyte character == plain character". *************** *** 217,225 **** ** something completely different. ** (ado, 1993-05-24) */ ! pt = _conv((int) ((t->tm_year + ! (long) TM_YEAR_BASE) / 100), ! "%02d", pt, ptlim); continue; case 'c': { --- 211,230 ---- ** something completely different. ** (ado, 1993-05-24) */ ! { ! long year; ! int top; ! ! year = t->tm_year; ! year += TM_YEAR_BASE; ! top = year / 100; ! if (top == 0 && year < 0) { ! pt = _add("-0", pt, ptlim); ! } else { ! pt = _conv(top, "%02d", ! pt, ptlim); ! } ! } continue; case 'c': { *************** *** 445,453 **** pt = _conv(w, "%02d", pt, ptlim); else if (*format == 'g') { *warnp = IN_ALL; ! pt = _conv(int(year % 100), ! "%02d", pt, ptlim); } else pt = _lconv(year, "%04ld", pt, ptlim); } --- 450,464 ---- pt = _conv(w, "%02d", pt, ptlim); else if (*format == 'g') { + int i; + *warnp = IN_ALL; ! i = year % 100; ! if (i < 0) { ! i = -i; ! } ! pt = _conv(i, "%02d", ! pt, ptlim); } else pt = _lconv(year, "%04ld", pt, ptlim); } *************** *** 486,494 **** continue; case 'y': *warnp = IN_ALL; ! pt = _conv((int) ((t->tm_year + ! (long) TM_YEAR_BASE) % 100), ! "%02d", pt, ptlim); continue; case 'Y': pt = _lconv(t->tm_year + (long) TM_YEAR_BASE, --- 497,512 ---- continue; case 'y': *warnp = IN_ALL; ! { ! int i; ! ! i = (t->tm_year + ! (long) TM_YEAR_BASE) % 100; ! if (i < 0) { ! i = -i; ! } ! pt = _conv(i, "%02d", pt, ptlim); ! } continue; case 'Y': pt = _lconv(t->tm_year + (long) TM_YEAR_BASE, *************** *** 556,564 **** diff = -diff; } else sign = "+"; pt = _add(sign, pt, ptlim); ! diff /= 60; ! pt = _conv((diff/60)*100 + diff%60, ! "%04d", pt, ptlim); } continue; case '+': --- 574,583 ---- diff = -diff; } else sign = "+"; pt = _add(sign, pt, ptlim); ! diff /= SECSPERMIN; ! diff = (diff / MINSPERHOUR) * 100 + ! (diff % MINSPERHOUR); ! pt = _conv(diff, "%04d", pt, ptlim); } continue; case '+':