summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_time.py42
-rw-r--r--Modules/timemodule.c53
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");