Issue #11930: Remove year >= 1000 limitation from datetime.strftime.
Patch by Victor Stinner.
diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst
index c637f6a..2eb5ea0 100644
--- a/Doc/library/datetime.rst
+++ b/Doc/library/datetime.rst
@@ -1750,8 +1750,7 @@
| | decimal number [00,99]. | |
+-----------+--------------------------------+-------+
| ``%Y`` | Year with century as a decimal | \(5) |
-| | number [0001,9999] (strptime), | |
-| | [1000,9999] (strftime). | |
+| | number [0001,9999]. | |
+-----------+--------------------------------+-------+
| ``%z`` | UTC offset in the form +HHMM | \(6) |
| | or -HHMM (empty string if the | |
@@ -1785,10 +1784,7 @@
calculations when the day of the week and the year are specified.
(5)
- For technical reasons, :meth:`strftime` method does not support
- dates before year 1000: ``t.strftime(format)`` will raise a
- :exc:`ValueError` when ``t.year < 1000`` even if ``format`` does
- not contain ``%Y`` directive. The :meth:`strptime` method can
+ The :meth:`strptime` method can
parse years in the full [1, 9999] range, but years < 1000 must be
zero-filled to 4-digit width.
diff --git a/Lib/datetime.py b/Lib/datetime.py
index 1ae7cb5..1f8c8f7 100644
--- a/Lib/datetime.py
+++ b/Lib/datetime.py
@@ -172,10 +172,6 @@
# Correctly substitute for %z and %Z escapes in strftime formats.
def _wrap_strftime(object, format, timetuple):
- year = timetuple[0]
- if year < 1000:
- raise ValueError("year=%d is before 1000; the datetime strftime() "
- "methods require year >= 1000" % year)
# Don't call utcoffset() or tzname() unless actually needed.
freplace = None # the string to use for %f
zreplace = None # the string to use for %z
diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py
index 38f3b8f..4a62bd4 100644
--- a/Lib/test/datetimetester.py
+++ b/Lib/test/datetimetester.py
@@ -1289,12 +1289,10 @@
self.assertTrue(self.theclass.min)
self.assertTrue(self.theclass.max)
- def test_strftime_out_of_range(self):
- # For nasty technical reasons, we can't handle years before 1000.
- cls = self.theclass
- self.assertEqual(cls(1000, 1, 1).strftime("%Y"), "1000")
- for y in 1, 49, 51, 99, 100, 999:
- self.assertRaises(ValueError, cls(y, 1, 1).strftime, "%Y")
+ def test_strftime_y2k(self):
+ for y in (1, 49, 70, 99, 100, 999, 1000, 1970):
+ self.assertEqual(self.theclass(y, 1, 1).strftime("%Y"),
+ '%04d' % y)
def test_replace(self):
cls = self.theclass
diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c
index a19c0c3..747be45 100644
--- a/Modules/_datetimemodule.c
+++ b/Modules/_datetimemodule.c
@@ -1166,31 +1166,6 @@
if (!pin)
return NULL;
- /* Give up if the year is before 1000.
- * Python strftime() plays games with the year, and different
- * games depending on whether envar PYTHON2K is set. This makes
- * years before 1000 a nightmare, even if the platform strftime
- * supports them (and not all do).
- * We could get a lot farther here by avoiding Python's strftime
- * wrapper and calling the C strftime() directly, but that isn't
- * an option in the Python implementation of this module.
- */
- {
- long year;
- PyObject *pyyear = PySequence_GetItem(timetuple, 0);
- if (pyyear == NULL) return NULL;
- assert(PyLong_Check(pyyear));
- year = PyLong_AsLong(pyyear);
- Py_DECREF(pyyear);
- if (year < 1000) {
- PyErr_Format(PyExc_ValueError, "year=%ld is before "
- "1000; the datetime strftime() "
- "methods require year >= 1000",
- year);
- return NULL;
- }
- }
-
/* Scan the input format, looking for %z/%Z/%f escapes, building
* a new format. Since computing the replacements for those codes
* is expensive, don't unless they're actually used.