diff options
-rw-r--r-- | Doc/lib/libtime.tex | 2 | ||||
-rw-r--r-- | Lib/test/test_time.py | 32 | ||||
-rw-r--r-- | Misc/NEWS | 6 | ||||
-rw-r--r-- | Modules/timemodule.c | 32 |
4 files changed, 56 insertions, 16 deletions
diff --git a/Doc/lib/libtime.tex b/Doc/lib/libtime.tex index b39b650..0e83400 100644 --- a/Doc/lib/libtime.tex +++ b/Doc/lib/libtime.tex @@ -226,6 +226,8 @@ if any field in \var{t} is outside of the allowed range. \versionchanged[Allowed \var{t} to be omitted]{2.1} \versionchanged[\exception{ValueError} raised if a field in \var{t} is out of range]{2.4} +\versionchanged[0 is now a legal argument for any position in the time tuple; +if it is normally illegal the value is forced to a correct one.]{2.5} The following directives can be embedded in the \var{format} string. diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index 94bbcca..f4be759 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -39,9 +39,9 @@ class TimeTestCase(unittest.TestCase): def test_strftime_bounds_checking(self): # Make sure that strftime() checks the bounds of the various parts - #of the time tuple. + #of the time tuple (0 is valid for *all* values). - # Check year + # Check year [1900, max(int)] self.assertRaises(ValueError, time.strftime, '', (1899, 1, 1, 0, 0, 0, 0, 1, -1)) if time.accept2dyear: @@ -49,27 +49,27 @@ class TimeTestCase(unittest.TestCase): (-1, 1, 1, 0, 0, 0, 0, 1, -1)) self.assertRaises(ValueError, time.strftime, '', (100, 1, 1, 0, 0, 0, 0, 1, -1)) - # Check month + # Check month [1, 12] + zero support self.assertRaises(ValueError, time.strftime, '', - (1900, 0, 1, 0, 0, 0, 0, 1, -1)) + (1900, -1, 1, 0, 0, 0, 0, 1, -1)) self.assertRaises(ValueError, time.strftime, '', (1900, 13, 1, 0, 0, 0, 0, 1, -1)) - # Check day of month + # Check day of month [1, 31] + zero support self.assertRaises(ValueError, time.strftime, '', - (1900, 1, 0, 0, 0, 0, 0, 1, -1)) + (1900, 1, -1, 0, 0, 0, 0, 1, -1)) self.assertRaises(ValueError, time.strftime, '', (1900, 1, 32, 0, 0, 0, 0, 1, -1)) - # Check hour + # Check hour [0, 23] self.assertRaises(ValueError, time.strftime, '', (1900, 1, 1, -1, 0, 0, 0, 1, -1)) self.assertRaises(ValueError, time.strftime, '', (1900, 1, 1, 24, 0, 0, 0, 1, -1)) - # Check minute + # Check minute [0, 59] self.assertRaises(ValueError, time.strftime, '', (1900, 1, 1, 0, -1, 0, 0, 1, -1)) self.assertRaises(ValueError, time.strftime, '', (1900, 1, 1, 0, 60, 0, 0, 1, -1)) - # Check second + # Check second [0, 61] self.assertRaises(ValueError, time.strftime, '', (1900, 1, 1, 0, 0, -1, 0, 1, -1)) # C99 only requires allowing for one leap second, but Python's docs say @@ -82,17 +82,25 @@ class TimeTestCase(unittest.TestCase): # modulo. self.assertRaises(ValueError, time.strftime, '', (1900, 1, 1, 0, 0, 0, -2, 1, -1)) - # Check day of the year + # Check day of the year [1, 366] + zero support self.assertRaises(ValueError, time.strftime, '', - (1900, 1, 1, 0, 0, 0, 0, 0, -1)) + (1900, 1, 1, 0, 0, 0, 0, -1, -1)) self.assertRaises(ValueError, time.strftime, '', (1900, 1, 1, 0, 0, 0, 0, 367, -1)) - # Check daylight savings flag + # Check daylight savings flag [-1, 1] self.assertRaises(ValueError, time.strftime, '', (1900, 1, 1, 0, 0, 0, 0, 1, -2)) self.assertRaises(ValueError, time.strftime, '', (1900, 1, 1, 0, 0, 0, 0, 1, 2)) + def test_default_values_for_zero(self): + # Make sure that using all zeros uses the proper default values. + # No test for daylight savings since strftime() does not change output + # based on its value. + expected = "2000 01 01 00 00 00 1 001" + result = time.strftime("%Y %m %d %H %M %S %w %j", (0,)*9) + self.assertEquals(expected, result) + def test_strptime(self): tt = time.gmtime(self.t) for directive in ('a', 'A', 'b', 'B', 'c', 'd', 'H', 'I', @@ -27,6 +27,12 @@ Core and builtins Library ------- +- Bug #1520914: Change time.strftime() to accept a zero for any position in its + argument tuple. For arguments where zero is illegal, the value is forced to + the minimum value that is correct. This is to support an undocumented but + common way people used to fill in inconsequential information in the time + tuple pre-2.4. + - Patch #1220874: Update the binhex module for Mach-O. Extension Modules diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 402e349..eb279fc9 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -406,13 +406,35 @@ time_strftime(PyObject *self, PyObject *args) indexing blindly into some array for a textual representation by some bad index (fixes bug #897625). - No check for year since handled in gettmarg(). + Also support values of zero from Python code for arguments in which + that is out of range by forcing that value to the lowest value that + is valid (fixed bug #XXX). + + Valid ranges based on what is allowed in struct tm: + + - tm_year: [0, max(int)] (1) + - tm_mon: [0, 11] (2) + - tm_mday: [1, 31] + - tm_hour: [0, 23] + - tm_min: [0, 59] + - tm_sec: [0, 60] + - tm_wday: [0, 6] (1) + - tm_yday: [0, 365] (2) + - tm_isdst: [-max(int), max(int)] + + (1) gettmarg() handles bounds-checking. + (2) Python's acceptable range is one greater than the range in C, + thus need to check against automatic decrement by gettmarg(). */ - if (buf.tm_mon < 0 || buf.tm_mon > 11) { + if (buf.tm_mon == -1) + buf.tm_mon = 0; + else if (buf.tm_mon < 0 || buf.tm_mon > 11) { PyErr_SetString(PyExc_ValueError, "month out of range"); return NULL; } - if (buf.tm_mday < 1 || buf.tm_mday > 31) { + if (buf.tm_mday == 0) + buf.tm_mday = 1; + else if (buf.tm_mday < 0 || buf.tm_mday > 31) { PyErr_SetString(PyExc_ValueError, "day of month out of range"); return NULL; } @@ -434,7 +456,9 @@ time_strftime(PyObject *self, PyObject *args) PyErr_SetString(PyExc_ValueError, "day of week out of range"); return NULL; } - if (buf.tm_yday < 0 || buf.tm_yday > 365) { + if (buf.tm_yday == -1) + buf.tm_yday = 0; + else if (buf.tm_yday < 0 || buf.tm_yday > 365) { PyErr_SetString(PyExc_ValueError, "day of year out of range"); return NULL; } |