diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 3ab3450032abe4..a3537d9aff8f6a 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -2540,7 +2540,7 @@ requires, and these work on all supported platforms. | ``%e`` | The day of the month as a | ␣1, ␣2, ..., 31 | | | | space-padded decimal number. | | | +-----------+--------------------------------+------------------------+-------+ -| ``%F`` | Equivalent to ``%Y-%m-%d``, | 2025-10-11, | \(0) | +| ``%F`` | Equivalent to ``%Y-%m-%d``, | 2025-10-11, | | | | the ISO 8601 format. | 1001-12-30 | | +-----------+--------------------------------+------------------------+-------+ | ``%g`` | Last 2 digits of ISO 8601 year | 00, 01, ..., 99 | \(0) | @@ -2676,7 +2676,7 @@ differences between platforms in handling of unsupported format specifiers. ``%:z`` was added for :meth:`~.datetime.strftime` .. versionadded:: 3.15 - ``%:z`` was added for :meth:`~.datetime.strptime` + ``%:z`` and ``%F`` were added for :meth:`~.datetime.strptime` Technical Detail ^^^^^^^^^^^^^^^^ diff --git a/Lib/_strptime.py b/Lib/_strptime.py index d011ddf8b181c3..8b62ea734b7d11 100644 --- a/Lib/_strptime.py +++ b/Lib/_strptime.py @@ -418,6 +418,7 @@ def __init__(self, locale_time=None): mapping['W'] = mapping['U'].replace('U', 'W') base.__init__(mapping) + base.__setitem__('F', self.pattern('%Y-%m-%d')) base.__setitem__('T', self.pattern('%H:%M:%S')) base.__setitem__('R', self.pattern('%H:%M')) base.__setitem__('r', self.pattern(self.locale_time.LC_time_ampm)) diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 8d39299b3ff442..2d11e92c5337dc 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -1212,6 +1212,20 @@ def test_strptime_leap_year(self): date.strptime('20-03-14', '%y-%m-%d') date.strptime('02-29,2024', '%m-%d,%Y') + def test_strptime_F_format(self): + test_date = "2025-10-26" + self.assertEqual( + datetime.strptime(test_date,"%F"), + datetime.strptime(test_date,"%Y-%m-%d") + ) + + def test_strptime_T_format(self): + test_time = "15:00:00" + self.assertEqual( + datetime.strptime(test_time,"%T"), + datetime.strptime(test_time,"%H:%M:%S") + ) + class SubclassDate(date): sub_var = 1 diff --git a/Lib/test/test_strptime.py b/Lib/test/test_strptime.py index 40e114aada67eb..838ff0bc4af3d5 100644 --- a/Lib/test/test_strptime.py +++ b/Lib/test/test_strptime.py @@ -649,6 +649,20 @@ def test_mar1_comes_after_feb29_even_when_omitting_the_year(self): time.strptime("Feb 29", "%b %d"), time.strptime("Mar 1", "%b %d")) + def test_strptime_F_format(self): + test_date = "2025-10-26" + self.assertEqual( + time.strptime(test_date,"%F"), + time.strptime(test_date,"%Y-%m-%d") + ) + + def test_strptime_T_format(self): + test_time = "15:00:00" + self.assertEqual( + time.strptime(test_time,"%T"), + time.strptime(test_time,"%H:%M:%S") + ) + class Strptime12AMPMTests(unittest.TestCase): """Test a _strptime regression in '%I %p' at 12 noon (12 PM)""" diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index c360f4a64c266b..da0cf494bfa8ad 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -358,8 +358,8 @@ def test_strptime(self): # Should be able to go round-trip from strftime to strptime without # raising an exception. tt = time.gmtime(self.t) - for directive in ('a', 'A', 'b', 'B', 'c', 'd', 'H', 'I', - 'j', 'm', 'M', 'p', 'S', + for directive in ('a', 'A', 'b', 'B', 'c', 'd', 'F', 'H', 'I', + 'j', 'm', 'M', 'p', 'S', 'T', 'U', 'w', 'W', 'x', 'X', 'y', 'Y', 'Z', '%'): format = '%' + directive if directive == 'd': diff --git a/Misc/NEWS.d/next/Library/2025-10-27-00-13-04.gh-issue-140715.WkozE0.rst b/Misc/NEWS.d/next/Library/2025-10-27-00-13-04.gh-issue-140715.WkozE0.rst new file mode 100644 index 00000000000000..c2bb69b894c1dd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-10-27-00-13-04.gh-issue-140715.WkozE0.rst @@ -0,0 +1 @@ +Add ``'%F'`` support to :meth:`~datetime.datetime.strptime`.