diff options
-rw-r--r-- | Lib/test/test_time.py | 42 | ||||
-rw-r--r-- | Modules/timemodule.c | 53 |
2 files changed, 60 insertions, 35 deletions
diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index d6de54b..af0a960 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -263,8 +263,48 @@ class TestLocale(unittest.TestCase): # This should not cause an exception time.strftime("%B", (2009,2,1,0,0,0,0,0,0)) +class TestAccept2Year(unittest.TestCase): + accept2dyear = 1 + def setUp(self): + self.saved_accept2dyear = time.accept2dyear + time.accept2dyear = self.accept2dyear + + def tearDown(self): + time.accept2dyear = self.saved_accept2dyear + + def yearstr(self, y): + return time.strftime('%Y', (y,) + (0,) * 8) + + def test_2dyear(self): + self.assertEqual(self.yearstr(0), '2000') + self.assertEqual(self.yearstr(69), '1969') + self.assertEqual(self.yearstr(68), '2068') + self.assertEqual(self.yearstr(99), '1999') + + def test_invalid(self): + self.assertRaises(ValueError, self.yearstr, 1899) + self.assertRaises(ValueError, self.yearstr, 100) + self.assertRaises(ValueError, self.yearstr, -1) + +class TestAccept2YearBool(TestAccept2Year): + accept2dyear = True + +class TestDontAccept2Year(TestAccept2Year): + accept2dyear = 0 + def test_2dyear(self): + self.assertRaises(ValueError, self.yearstr, 0) + self.assertRaises(ValueError, self.yearstr, 69) + self.assertRaises(ValueError, self.yearstr, 68) + self.assertRaises(ValueError, self.yearstr, 99) + +class TestDontAccept2YearBool(TestDontAccept2Year): + accept2dyear = False + + def test_main(): - support.run_unittest(TimeTestCase, TestLocale) + support.run_unittest(TimeTestCase, TestLocale, + TestAccept2Year, TestAccept2YearBool, + TestDontAccept2Year, TestDontAccept2YearBool) if __name__ == "__main__": test_main() diff --git a/Modules/timemodule.c b/Modules/timemodule.c index ebc2b81..c1f656b 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -217,29 +217,6 @@ tmtotuple(struct tm *p) } static PyObject * -structtime_totuple(PyObject *t) -{ - PyObject *x = NULL; - unsigned int i; - PyObject *v = PyTuple_New(9); - if (v == NULL) - return NULL; - - for (i=0; i<9; i++) { - x = PyStructSequence_GET_ITEM(t, i); - Py_INCREF(x); - PyTuple_SET_ITEM(v, i, x); - } - - if (PyErr_Occurred()) { - Py_XDECREF(v); - return NULL; - } - - return v; -} - -static PyObject * time_convert(double when, struct tm * (*function)(const time_t *)) { struct tm *p; @@ -328,9 +305,6 @@ gettmarg(PyObject *args, struct tm *p) t = args; Py_INCREF(t); } - else if (Py_TYPE(args) == &StructTimeType) { - t = structtime_totuple(args); - } else { PyErr_SetString(PyExc_TypeError, "Tuple or struct_time argument required"); @@ -352,19 +326,30 @@ gettmarg(PyObject *args, struct tm *p) } Py_DECREF(t); + /* XXX: Why 1900? If the goal is to interpret 2-digit years as those in + * 20th / 21st century according to the POSIX standard, we can just treat + * 0 <= y < 100 as special. Year 100 is probably too ambiguous and should + * be rejected, but years 101 through 1899 can be passed through. + */ if (y < 1900) { PyObject *accept = PyDict_GetItemString(moddict, "accept2dyear"); - if (accept == NULL || !PyLong_CheckExact(accept) || - !PyObject_IsTrue(accept)) { - PyErr_SetString(PyExc_ValueError, - "year >= 1900 required"); + int acceptval = accept != NULL && PyObject_IsTrue(accept); + if (acceptval == -1) return 0; + if (acceptval) { + if (69 <= y && y <= 99) + y += 1900; + else if (0 <= y && y <= 68) + y += 2000; + else { + PyErr_SetString(PyExc_ValueError, + "year out of range"); + return 0; + } } - if (69 <= y && y <= 99) - y += 1900; - else if (0 <= y && y <= 68) - y += 2000; + /* XXX: When accept2dyear is false, we don't have to reject y < 1900. + * Consider removing the following else-clause. */ else { PyErr_SetString(PyExc_ValueError, "year out of range"); |