From 452b417e34489614b3003b8d08148269096239d5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 18 Jun 2019 11:55:27 -0700 Subject: [PATCH] bpo-34903: Document that some strptime formats only require 1 digit (GH-14149) For datetime.datetime.strptime(), the leading zero for some two-digit formats is optional. This adds a footnote to the strftime/strptime documentation to reflect this fact, and adds some tests to ensure that it is true. bpo-34903 (cherry picked from commit 6b9c204ee77a0de87d6f51a3d4547a18604cef9e) Co-authored-by: Mike Gleen --- Doc/library/datetime.rst | 35 +++++++++++-------- Lib/test/datetimetester.py | 35 +++++++++++++++++++ .../2019-06-17-09-36-46.bpo-34903.r_wGRc.rst | 1 + 3 files changed, 56 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2019-06-17-09-36-46.bpo-34903.r_wGRc.rst diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 15b500f770f..270b2386d71 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -2076,7 +2076,7 @@ format codes. | | where 0 is Sunday and 6 is | | | | | Saturday. | | | +-----------+--------------------------------+------------------------+-------+ -| ``%d`` | Day of the month as a | 01, 02, ..., 31 | | +| ``%d`` | Day of the month as a | 01, 02, ..., 31 | \(9) | | | zero-padded decimal number. | | | +-----------+--------------------------------+------------------------+-------+ | ``%b`` | Month as locale's abbreviated || Jan, Feb, ..., Dec | \(1) | @@ -2089,29 +2089,29 @@ format codes. | | || Januar, Februar, ..., | | | | | Dezember (de_DE) | | +-----------+--------------------------------+------------------------+-------+ -| ``%m`` | Month as a zero-padded | 01, 02, ..., 12 | | +| ``%m`` | Month as a zero-padded | 01, 02, ..., 12 | \(9) | | | decimal number. | | | +-----------+--------------------------------+------------------------+-------+ -| ``%y`` | Year without century as a | 00, 01, ..., 99 | | +| ``%y`` | Year without century as a | 00, 01, ..., 99 | \(9) | | | zero-padded decimal number. | | | +-----------+--------------------------------+------------------------+-------+ | ``%Y`` | Year with century as a decimal | 0001, 0002, ..., 2013, | \(2) | | | number. | 2014, ..., 9998, 9999 | | +-----------+--------------------------------+------------------------+-------+ -| ``%H`` | Hour (24-hour clock) as a | 00, 01, ..., 23 | | +| ``%H`` | Hour (24-hour clock) as a | 00, 01, ..., 23 | \(9) | | | zero-padded decimal number. | | | +-----------+--------------------------------+------------------------+-------+ -| ``%I`` | Hour (12-hour clock) as a | 01, 02, ..., 12 | | +| ``%I`` | Hour (12-hour clock) as a | 01, 02, ..., 12 | \(9) | | | zero-padded decimal number. | | | +-----------+--------------------------------+------------------------+-------+ | ``%p`` | Locale's equivalent of either || AM, PM (en_US); | \(1), | | | AM or PM. || am, pm (de_DE) | \(3) | +-----------+--------------------------------+------------------------+-------+ -| ``%M`` | Minute as a zero-padded | 00, 01, ..., 59 | | +| ``%M`` | Minute as a zero-padded | 00, 01, ..., 59 | \(9) | | | decimal number. | | | +-----------+--------------------------------+------------------------+-------+ -| ``%S`` | Second as a zero-padded | 00, 01, ..., 59 | \(4) | -| | decimal number. | | | +| ``%S`` | Second as a zero-padded | 00, 01, ..., 59 | \(4), | +| | decimal number. | | \(9) | +-----------+--------------------------------+------------------------+-------+ | ``%f`` | Microsecond as a decimal | 000000, 000001, ..., | \(5) | | | number, zero-padded on the | 999999 | | @@ -2125,19 +2125,19 @@ format codes. | ``%Z`` | Time zone name (empty string | (empty), UTC, EST, CST | | | | if the object is naive). | | | +-----------+--------------------------------+------------------------+-------+ -| ``%j`` | Day of the year as a | 001, 002, ..., 366 | | +| ``%j`` | Day of the year as a | 001, 002, ..., 366 | \(9) | | | zero-padded decimal number. | | | +-----------+--------------------------------+------------------------+-------+ -| ``%U`` | Week number of the year | 00, 01, ..., 53 | \(7) | -| | (Sunday as the first day of | | | +| ``%U`` | Week number of the year | 00, 01, ..., 53 | \(7), | +| | (Sunday as the first day of | | \(9) | | | the week) as a zero padded | | | | | decimal number. All days in a | | | | | new year preceding the first | | | | | Sunday are considered to be in | | | | | week 0. | | | +-----------+--------------------------------+------------------------+-------+ -| ``%W`` | Week number of the year | 00, 01, ..., 53 | \(7) | -| | (Monday as the first day of | | | +| ``%W`` | Week number of the year | 00, 01, ..., 53 | \(7), | +| | (Monday as the first day of | | \(9) | | | the week) as a decimal number. | | | | | All days in a new year | | | | | preceding the first Monday | | | @@ -2177,8 +2177,8 @@ incomplete or ambiguous ISO 8601 directives will raise a :exc:`ValueError`. | ``%u`` | ISO 8601 weekday as a decimal | 1, 2, ..., 7 | | | | number where 1 is Monday. | | | +-----------+--------------------------------+------------------------+-------+ -| ``%V`` | ISO 8601 week as a decimal | 01, 02, ..., 53 | \(8) | -| | number with Monday as | | | +| ``%V`` | ISO 8601 week as a decimal | 01, 02, ..., 53 | \(8), | +| | number with Monday as | | \(9) | | | the first day of the week. | | | | | Week 01 is the week containing | | | | | Jan 4. | | | @@ -2274,6 +2274,11 @@ Notes: :meth:`strptime` format string. Also note that ``%G`` and ``%Y`` are not interchangeable. +(9) + When used with the :meth:`strptime` method, the leading zero is optional + for formats ``%d``, ``%m``, ``%H``, ``%I``, ``%M``, ``%S``, ``%J``, ``%U``, + ``%W``, and ``%V``. Format ``%y`` does require a leading zero. + .. rubric:: Footnotes .. [#] If, that is, we ignore the effects of Relativity diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index b9bf49476f1..2f8975d8c07 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -2387,6 +2387,7 @@ class TestDateTime(TestDate): self.assertEqual(expected, got) strptime = self.theclass.strptime + self.assertEqual(strptime("+0002", "%z").utcoffset(), 2 * MINUTE) self.assertEqual(strptime("-0002", "%z").utcoffset(), -2 * MINUTE) self.assertEqual( @@ -2421,6 +2422,40 @@ class TestDateTime(TestDate): with self.assertRaises(ValueError): strptime("-2400", "%z") with self.assertRaises(ValueError): strptime("-000", "%z") + def test_strptime_single_digit(self): + # bpo-34903: Check that single digit dates and times are allowed. + + strptime = self.theclass.strptime + + with self.assertRaises(ValueError): + # %y does require two digits. + newdate = strptime('01/02/3 04:05:06', '%d/%m/%y %H:%M:%S') + dt1 = self.theclass(2003, 2, 1, 4, 5, 6) + dt2 = self.theclass(2003, 1, 2, 4, 5, 6) + dt3 = self.theclass(2003, 2, 1, 0, 0, 0) + dt4 = self.theclass(2003, 1, 25, 0, 0, 0) + inputs = [ + ('%d', '1/02/03 4:5:6', '%d/%m/%y %H:%M:%S', dt1), + ('%m', '01/2/03 4:5:6', '%d/%m/%y %H:%M:%S', dt1), + ('%H', '01/02/03 4:05:06', '%d/%m/%y %H:%M:%S', dt1), + ('%M', '01/02/03 04:5:06', '%d/%m/%y %H:%M:%S', dt1), + ('%S', '01/02/03 04:05:6', '%d/%m/%y %H:%M:%S', dt1), + ('%j', '2/03 04am:05:06', '%j/%y %I%p:%M:%S',dt2), + ('%I', '02/03 4am:05:06', '%j/%y %I%p:%M:%S',dt2), + ('%w', '6/04/03', '%w/%U/%y', dt3), + # %u requires a single digit. + ('%W', '6/4/2003', '%u/%W/%Y', dt3), + ('%V', '6/4/2003', '%u/%V/%G', dt4), + ] + for reason, string, format, target in inputs: + reason = 'test single digit ' + reason + with self.subTest(reason=reason, + string=string, + format=format, + target=target): + newdate = strptime(string, format) + self.assertEqual(newdate, target, msg=reason) + def test_more_timetuple(self): # This tests fields beyond those tested by the TestDate.test_timetuple. t = self.theclass(2004, 12, 31, 6, 22, 33) diff --git a/Misc/NEWS.d/next/Documentation/2019-06-17-09-36-46.bpo-34903.r_wGRc.rst b/Misc/NEWS.d/next/Documentation/2019-06-17-09-36-46.bpo-34903.r_wGRc.rst new file mode 100644 index 00000000000..7e277f4ec1a --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2019-06-17-09-36-46.bpo-34903.r_wGRc.rst @@ -0,0 +1 @@ +Documented that in :meth:`datetime.datetime.strptime()`, the leading zero in some two-digit formats is optional. Patch by Mike Gleen.