Strftime's %C and %y formats versus wide-ranging tm_year valu es
Paul Eggert
eggert at CS.UCLA.EDU
Mon Sep 27 05:07:02 UTC 2004
"Olson, Arthur David (NIH/NCI)" <olsona at dc37a.nci.nih.gov> writes:
> Absent any objections, ...
I found a bug on 32-bit hosts: it misformats %Y, %y, %C, etc., when
t->tm_year is close to INT_MAX. This is because tm_year + 1900
t->overflows. In the common 32-bit case where 'long' is the
same width as 'int', converting to 'long' first doesn't help.
This bug was present in the old version too, but we might as well fix
it while we're in the neighborhood. I'll send a proposed fix in my
next email, but first I'll give an illustration of the bug. The
following test program (derived from the program you emailed) will
output lines that look like this (modulo white space):
Y-1900 %C %Y %y %G %g
...
2147483647 -21474817 -2147481749 49 -2147481749 49
2147483646 -21474817 -2147481750 50 -2147481750 50
2147483645 -21474817 -2147481751 51 -2147481751 51
2147481748 -21474836 -2147483648 48 -2147483648 48
instead of the correct answers, which look like this:
Y-1900 %C %Y %y %G %g
...
2147483647 21474855 2147485547 47 2147485547 47
2147483646 21474855 2147485546 46 2147485546 46
2147483645 21474855 2147485545 45 2147485545 45
2147481748 21474836 2147483648 48 2147483648 48
#include <limits.h>
#include <stdio.h>
#include <time.h>
static int years[] = {
10001 - 1900, 10000 - 1900, 9999 - 1900,
1001 - 1900, 1000 - 1900, 999 - 1900,
101 - 1900, 100 - 1900, 99 - 1900,
11 - 1900, 10 - 1900, 9 - 1900,
1 - 1900, 0 - 1900, -1 - 1900,
-9 - 1900, -10 - 1900, -11 - 1900,
-99 - 1900, -100 - 1900, -101 - 1900,
-999 - 1900, -1000 - 1900, -1001 - 1900,
-9999 - 1900, -10000 - 1900, -10001 - 1900,
INT_MAX, INT_MAX - 1, INT_MAX - 2,
INT_MAX - 1900 + 1, INT_MAX - 1900, INT_MAX - 1 - 1900,
INT_MIN + 2, INT_MIN + 1, INT_MIN
};
#define NVALUES ((sizeof years) / (sizeof years[0]))
static char *formats[] = { "%C", "%Y", "%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 ("Y-1900");
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];
for (j = 0; j < NFORMATS; ++j)
{
(void) strftime (buf, sizeof buf, formats[j], &tm);
(void) printf ("\t%s", buf);
}
(void) printf ("\n");
}
return 0;
}
More information about the tz
mailing list