]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-140715: Add %t and %n format codes support to strptime() (GH-144896)
authorJason Yalim, PhD <4813268+jyalim@users.noreply.github.com>
Fri, 13 Mar 2026 13:00:39 +0000 (06:00 -0700)
committerGitHub <noreply@github.com>
Fri, 13 Mar 2026 13:00:39 +0000 (14:00 +0100)
Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
Doc/library/datetime.rst
Lib/_strptime.py
Lib/test/datetimetester.py
Lib/test/test_strptime.py
Lib/test/test_time.py
Misc/NEWS.d/next/Library/2026-02-17-03-43-07.gh-issue-140715.twmcM_.rst [new file with mode: 0644]

index 73217136f1447299e78015fef2e8a4969a32ff3e..8993049a720b1c8e6580dce86a879c795ab14250 100644 (file)
@@ -2611,8 +2611,10 @@ requires, and these work on all supported platforms.
 |  ``%M``   | Minute as a zero-padded        | 00, 01, ..., 59        | \(9)  |
 |           | decimal number.                |                        |       |
 +-----------+--------------------------------+------------------------+-------+
-|  ``%n``   | The newline character          | ``\n``                 | \(0)  |
-|           | (``'\n'``).                    |                        |       |
+|  ``%n``   | The newline character          | ``\n``                 |       |
+|           | (``'\n'``). For                |                        |       |
+|           | :meth:`!strptime`, zero or     |                        |       |
+|           | more whitespace.               |                        |       |
 +-----------+--------------------------------+------------------------+-------+
 |  ``%p``   | Locale's equivalent of either  || AM, PM (en_US);       | \(1), |
 |           | AM or PM.                      || am, pm (de_DE)        | \(3)  |
@@ -2625,8 +2627,9 @@ requires, and these work on all supported platforms.
 |  ``%S``   | Second as a zero-padded        | 00, 01, ..., 59        | \(4), |
 |           | decimal number.                |                        | \(9)  |
 +-----------+--------------------------------+------------------------+-------+
-|  ``%t``   | The tab character              | ``\t``                 | \(0)  |
-|           | (``'\t'``).                    |                        |       |
+|  ``%t``   | The tab character (``'\t'``).  | ``\t``                 |       |
+|           | For :meth:`!strptime`,         |                        |       |
+|           | zero or more whitespace.       |                        |       |
 +-----------+--------------------------------+------------------------+-------+
 |  ``%T``   | ISO 8601 time format,          | 10:01:59               |       |
 |           | equivalent to ``%H:%M:%S``.    |                        |       |
@@ -2717,7 +2720,8 @@ differences between platforms in handling of unsupported format specifiers.
    ``%:z`` was added for :meth:`~.datetime.strftime`.
 
 .. versionadded:: 3.15
-   ``%:z``, ``%F``, and ``%D`` were added for :meth:`~.datetime.strptime`.
+   ``%D``, ``%F``, ``%n``, ``%t``, and ``%:z`` were added for
+   :meth:`~.datetime.strptime`.
 
 
 Technical detail
index 0d81ff6765e1edded86f8c346cf927bb9359ac96..3367ac485a590c0b25e157ba5010aa65ee070528 100644 (file)
@@ -382,7 +382,10 @@ class TimeRE(dict):
             'Z': self.__seqToRE((tz for tz_names in self.locale_time.timezone
                                         for tz in tz_names),
                                 'Z'),
-            '%': '%'}
+            'n': r'\s*',
+            't': r'\s*',
+            '%': '%',
+        }
         if self.locale_time.LC_alt_digits is None:
             for d in 'dmyCHIMS':
                 mapping['O' + d] = r'(?P<%s>\d\d|\d| \d)' % d
index 97eec618932aa56624d473565916a584336f9508..e264433ca590bf7b5165e5961f604476840ead35 100644 (file)
@@ -2207,6 +2207,20 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase):
             self.theclass.strptime(test_date, "%m/%d/%y")
         )
 
+    def test_strptime_n_and_t_format(self):
+        format_directives = ('%n', '%t', '%n%t', '%t%n')
+        whitespaces = ('', ' ', '\t', '\r', '\v', '\n', '\f')
+        for fd in format_directives:
+            for ws in (*whitespaces, ''.join(whitespaces)):
+                with self.subTest(format_directive=fd, whitespace=ws):
+                    self.assertEqual(
+                        self.theclass.strptime(
+                            f"2026{ws}02{ws}03",
+                            f"%Y{fd}%m{fd}%d",
+                        ),
+                        self.theclass(2026, 2, 3),
+                    )
+
 
 #############################################################################
 # datetime tests
index fd8525feb88d53373efec035e37a6a6e5c16e30e..dfc8ef6d2c5b7ee70469a625bd968ef3205758b2 100644 (file)
@@ -670,6 +670,23 @@ class StrptimeTests(unittest.TestCase):
             time.strptime(test_date, "%m/%d/%y")
         )
 
+    def test_strptime_n_and_t_format(self):
+        format_directives = ('%n', '%t', '%n%t', '%t%n')
+        whitespaces = ('', ' ', '\t', '\r', '\v', '\n', '\f')
+        for fd in format_directives:
+            for ws in (*whitespaces, ''.join(whitespaces)):
+                with self.subTest(format_directive=fd, whitespace=ws):
+                    self.assertEqual(
+                        time.strptime(
+                            f"2026{ws}02{ws}03",
+                            f"%Y{fd}%m{fd}%d",
+                        ),
+                        time.strptime(
+                            f'2026-02-03',
+                            "%Y-%m-%d",
+                        ),
+                    )
+
 class Strptime12AMPMTests(unittest.TestCase):
     """Test a _strptime regression in '%I %p' at 12 noon (12 PM)"""
 
index da5fd16b8b62910c1ff9185fd4a06e2cab603296..be8f6b057654c2816fb8f4251dc74fa6fb48852e 100644 (file)
@@ -359,7 +359,7 @@ class TimeTestCase(unittest.TestCase):
         # raising an exception.
         tt = time.gmtime(self.t)
         for directive in ('a', 'A', 'b', 'B', 'c', 'd', 'D', 'F', 'H', 'I',
-                          'j', 'm', 'M', 'p', 'S', 'T',
+                          'j', 'm', 'M', 'n', 'p', 'S', 't', 'T',
                           'U', 'w', 'W', 'x', 'X', 'y', 'Y', 'Z', '%'):
             format = '%' + directive
             if directive == 'd':
diff --git a/Misc/NEWS.d/next/Library/2026-02-17-03-43-07.gh-issue-140715.twmcM_.rst b/Misc/NEWS.d/next/Library/2026-02-17-03-43-07.gh-issue-140715.twmcM_.rst
new file mode 100644 (file)
index 0000000..3bebc66
--- /dev/null
@@ -0,0 +1 @@
+Add ``%n`` and ``%t`` support to :meth:`~datetime.datetime.strptime`.