Date input of "mmm yyyy" for Feb always returns 03. Flaw exists across all know bsd versions, intel, amd, 64bit, not, etc. Fix: Got me :> How-To-Repeat: > # /bin/date -j -f "%b %Y" "Jan 2007" +%m > 01 > # /bin/date -j -f "%b %Y" "Feb 2007" +%m > 03 > # /bin/date -j -f "%m %Y" "02 2007" +%m > 03 > # /bin/date -j -f "%m %Y" "02 2007" +%m-%b > 03-Mar
Hmmm, not that we are in the 2nd of April, I cannot seem to reproduce this by running /bin/date on the command line, on a 6.2-RELEASE or a 7.0-CURRENT system: $ date -j -f '%b %Y' 'Feb 2007' '+%m' 02 $ As I found out, this happens when the current value of %d when /bin/date runs is larger than the number of days February has. Then date(1) gets the value of %d from the current time, and this overflows from February into March (i.e. if you ran the tests on the same day that you submitted this bug report, the value of %d was 31, which is clearly not a valid %d value for any February). The date utility initializes a `struct tm' structure in setthetime() with the current value of date/time using localtime(). Then strptime() is called with the format specified and it parses *only* the parts which are explicitly mentioned in the format string "%b %Y". The value of the current day-of-the-month should be left untouched by strptime(), and it is. But I think that strptime() tries to rationalize an invalid value, when it finds one. It's easy to reproduce this by setting a breakpoint in setthetime() while /bin/date runs, and tweaking the value of "day of the month" which is returned by localtime() in place: % keramida@kobe:/home/keramida/tmp/date$ gdb date % GNU gdb 6.1.1 [FreeBSD] % Copyright 2004 Free Software Foundation, Inc. % GDB is free software, covered by the GNU General Public License, and you are % welcome to change it and/or distribute copies of it under certain conditions. % Type "show copying" to see the conditions. % There is absolutely no warranty for GDB. Type "show warranty" for details. % This GDB was configured as "i386-marcel-freebsd"...No symbol table is loaded. Use the "file" command. % % (gdb) b setthetime % Breakpoint 1 at 0x8049213: file date.c, line 189. % (gdb) run -j -f "%b %Y" "Feb 2007" +%m % Starting program: /home/keramida/tmp/date/date -j -f "%b %Y" "Feb 2007" +%m % % Breakpoint 1, setthetime (fmt=0xbfbfe9a7 "%b %Y", \ % p=0xbfbfe9ad "Feb 2007", jflag=1, nflag=0) at date.c:189 % 189 if (fmt != NULL) { % (gdb) n % 190 lt = localtime(&tval); % (gdb) % 191 t = strptime(p, fmt, lt); % (gdb) print *lt % $1 = {tm_sec = 12, tm_min = 54, tm_hour = 4, tm_mday = 2, tm_mon = 3, % tm_year = 107, tm_wday = 1, tm_yday = 91, tm_isdst = 1, % tm_gmtoff = 10800, tm_zone = 0x28184270 "EEST"} % (gdb) print lt->tm_mday =31 % $2 = 31 % (gdb) print *lt % $3 = {tm_sec = 12, tm_min = 54, tm_hour = 4, tm_mday = 31, tm_mon = 3, % tm_year = 107, tm_wday = 1, tm_yday = 91, tm_isdst = 1, % tm_gmtoff = 10800, tm_zone = 0x28184270 "EEST"} % (gdb) n % 192 if (t == NULL) { % (gdb) c % Continuing. % 03 % % Program exited normally. % (gdb) By asking strptime() to parse a struct tm which contains tm_mday set to 31 with a format specifier of "%b" and an input string which says "Feb" we get "03" in the output (i.e. "March"). I don't know if strptime() should return an error in this case, instead of trying to "overflow" into the next calendar month. Both cases have, arguably, a logical explanation, but the overflow case is surprising. My own personal preference would be that strptime() returns an error in this case. This will certainly cause a mild disturbance when users run /bin/date in the case you tried and get an error if the current day of the month is more than 28 (or 29 on leap years), but when /bin/date is used without an explicit %d value in both the format string of -j and the input data, it runs with an underspecified input value. Giving input which is underspecified and getting an error is, IMHO, slightly better than getting surprising results. - Giorgos
(In reply to paradox from comment #0) > Date input of "mmm yyyy" for Feb always returns 03. > > Flaw exists across all know bsd versions, intel, amd, 64bit, not, etc. > > Fix: > > Got me :> > How-To-Repeat: > # /bin/date -j -f "%b %Y" "Jan 2007" +%m > > 01 > > # /bin/date -j -f "%b %Y" "Feb 2007" +%m > > 03 > > # /bin/date -j -f "%m %Y" "02 2007" +%m > > 03 > > # /bin/date -j -f "%m %Y" "02 2007" +%m-%b > > 03-Mar I cannot reproduce this on 11-current: $ /bin/date -j -f "%b %Y" "Jan 2007" +%m 01 $ /bin/date -j -f "%b %Y" "Feb 2007" +%m 02 $ /bin/date -j -f "%m %Y" "02 2007" +%m 02 $ /bin/date -j -f "%m %Y" "02 2007" +%m-%b 02-Feb