Proposed strftime.c changes for long years
Paul Eggert
eggert at cs.ucla.edu
Tue Sep 7 20:03:07 UTC 2004
The proposed strftime.c code for the %C conversion uses _lconv, but
the converted value can't possibly fall outside the range
INT_MIN..INT_MAX so it might be a bit more efficient to use _conv.
The %C conversion expression "(t->tm_year + (long) TM_YEAR_BASE) /
100" returns the wrong result in some cases due to overflow, e.g., if
t->tm_year == INT_MAX and INT_MAX==LONG_MAX.
It looks like you've leaning towards having %y generate year%100 even
when the year is negative, but I'd like to present a new arguemnt for
generating year mod 100 instead, on the grounds of preventing buffer
overruns in older code. Most programmers expect strftime %y to
generate exactly two digits, in the range 00-99 as the the C Standard
explicitly requires. Generating strings like "-1" or (especially)
"-99" might cause errors (e.g., buffer overruns) in older code.
The situation for %g is similar.
%C is less straightforward, since here the C Standard requires the
impossible (it says the output range must be 00-99). However, I'd
argue that it's least surprising if %C is consistent with %y, i.e., if
%C is (year - (year mod 100)) / 100.
The following proposed patch addresses the above issues.
===================================================================
RCS file: RCS/strftime.c,v
retrieving revision 2001.4.1.1
retrieving revision 2001.4.0.2
diff -pu -r2001.4.1.1 -r2001.4.0.2
--- strftime.c 2004/09/07 12:21:29 2001.4.1.1
+++ strftime.c 2004/09/07 19:11:35 2001.4.0.2
@@ -211,9 +211,12 @@ label:
** something completely different.
** (ado, 1993-05-24)
*/
- pt = _lconv((t->tm_year +
- (long) TM_YEAR_BASE) / 100,
- "%02ld", pt, ptlim);
+ {
+ int c = (TM_YEAR_BASE / 100
+ + t->tm_year / 100
+ - (t->tm_year % 100 < 0));
+ pt = _conv(c, "%02d", pt, ptlim);
+ }
continue;
case 'c':
{
@@ -439,9 +442,12 @@ label:
pt = _conv(w, "%02d",
pt, ptlim);
else if (*format == 'g') {
+ int g = year % 100;
+ if (g < 0)
+ g += 100;
*warnp = IN_ALL;
- pt = _conv(int(year % 100),
- "%02d", pt, ptlim);
+ pt = _conv(g, "%02d",
+ pt, ptlim);
} else pt = _lconv(year, "%04ld",
pt, ptlim);
}
@@ -479,11 +485,13 @@ label:
}
continue;
case 'y':
+ {
+ int y = t->tm_year % 100;
+ if (y < 0)
+ y += 100;
*warnp = IN_ALL;
- pt = _conv(
- (int) ((t->tm_year +
- (long) TM_YEAR_BASE) % 100),
- "%02d", pt, ptlim);
+ pt = _conv(y, "%02d", pt, ptlim);
+ }
continue;
case 'Y':
pt = _lconv(t->tm_year + (long) TM_YEAR_BASE,
More information about the tz
mailing list