]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-152157: Reject empty fractions in `_datetime.{date}time.fromisoformat` (#152161)
authortonghuaroot (童话) <tonghuaroot@gmail.com>
Wed, 1 Jul 2026 09:54:02 +0000 (17:54 +0800)
committerGitHub <noreply@github.com>
Wed, 1 Jul 2026 09:54:02 +0000 (11:54 +0200)
Co-authored-by: Stan Ulbrych <stan@python.org>
Lib/test/datetimetester.py
Misc/NEWS.d/next/Library/2026-06-25-07-08-17.gh-issue-152157.dt5Ef0.rst [new file with mode: 0644]
Modules/_datetimemodule.c

index 192b22ff7540034ef89ade524da7eb5f9013a4d4..c11e9c068bed3bd29e372b0e1b780c064e21df60 100644 (file)
@@ -3758,6 +3758,10 @@ class TestDateTime(TestDate):
             '2009-04-19T12:30:45-00:90:00', # Time zone field out from range
             '2009-04-19T12:30:45-00:00:90', # Time zone field out from range
             '2020-2020',                    # Ambiguous 9-char date portion
+            '2009-04-19T12:30:45.+05:00',   # Empty fraction before offset
+            '2009-04-19T12:30:45.-05:00',   # Empty fraction before offset
+            '2009-04-19T12:30:45.Z',        # Empty fraction before Z
+            '2009-04-19T12:30:45,+05:00',   # Empty fraction (comma) before offset
         ]
 
         for bad_str in bad_strs:
@@ -5034,6 +5038,10 @@ class TestTimeTZ(TestTime, TZInfoBase, unittest.TestCase):
             '24:01:00.000000',          # Has non-zero minutes on 24:00
             '12:30:45+00:90:00',        # Time zone field out from range
             '12:30:45+00:00:90',        # Time zone field out from range
+            '12:30:45.+05:00',          # Empty fraction before offset
+            '12:30:45.-05:00',          # Empty fraction before offset
+            '12:30:45.Z',               # Empty fraction before Z
+            '12:30:45,+05:00',          # Empty fraction (comma) before offset
         ]
 
         for bad_str in bad_strs:
diff --git a/Misc/NEWS.d/next/Library/2026-06-25-07-08-17.gh-issue-152157.dt5Ef0.rst b/Misc/NEWS.d/next/Library/2026-06-25-07-08-17.gh-issue-152157.dt5Ef0.rst
new file mode 100644 (file)
index 0000000..00e83b4
--- /dev/null
@@ -0,0 +1,3 @@
+The C implementations of :meth:`~datetime.datetime.fromisoformat` and :meth:`~datetime.time.fromisoformat`
+now reject a decimal separator that is not followed by any
+fractional digit before a timezone designator.
index fd8d95d05c933e056eb6b468981e623132eee22b..cd02b298b406e6a230f3b5be3b6988d9bbf2ed8e 100644 (file)
@@ -1034,7 +1034,16 @@ parse_hh_mm_ss_ff(const char *tstr, const char *tstr_end, int *hour,
             has_separator = (c == ':');
         }
 
-        if (p >= p_end) {
+        if (c == '.' || c == ',') {
+            if (i < 2) {
+                return -3;  // Decimal mark on hour or minute
+            }
+            if (p >= p_end) {
+                return -3;  // Decimal mark not followed by any digit
+            }
+            break;
+        }
+        else if (p >= p_end) {
             return c != '\0';
         }
         else if (has_separator && (c == ':')) {
@@ -1043,14 +1052,10 @@ parse_hh_mm_ss_ff(const char *tstr, const char *tstr_end, int *hour,
             }
             continue;
         }
-        else if (c == '.' || c == ',') {
-            if (i < 2) {
-                return -3; // Decimal mark on hour or minute
-            }
-            break;
-        } else if (!has_separator) {
+        else if (!has_separator) {
             --p;
-        } else {
+        }
+        else {
             return -4;  // Malformed time separator
         }
     }