https://github.com/python/cpython/commit/0a29ea5bf60f1bff8b316c735038bc1dc16e4c18
commit: 0a29ea5bf60f1bff8b316c735038bc1dc16e4c18
branch: 3.14
author: tonghuaroot (童话) <[email protected]>
committer: StanFromIreland <[email protected]>
date: 2026-07-08T12:37:11+02:00
summary:

[3.14] gh-152157: Reject empty fractions in 
`_datetime.{date}time.fromisoformat` (GH-152161) (#152765)

(cherry picked from commit 112c69a0514902af2d2f7d0503de6690ca59a10f)

Co-authored-by: tonghuaroot (童话) <[email protected]>
Co-authored-by: Stan Ulbrych <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-06-25-07-08-17.gh-issue-152157.dt5Ef0.rst
M Lib/test/datetimetester.py
M Modules/_datetimemodule.c

diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py
index 0792b14471b937..1b71b71c544c0c 100644
--- a/Lib/test/datetimetester.py
+++ b/Lib/test/datetimetester.py
@@ -3582,6 +3582,10 @@ def test_fromisoformat_fails_datetime(self):
             '2009-04-19T12:30:45.400 ',        # Trailing space (gh-130959)
             '2009-04-19T12:30:45. 400',        # Space before fraction 
(gh-130959)
             '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:
@@ -4838,6 +4842,10 @@ def test_fromisoformat_fails(self):
             '12:30:45.400 +02:30',      # Space between ms and timezone 
(gh-130959)
             '12:30:45.400 ',            # Trailing space (gh-130959)
             '12:30:45. 400',            # Space before fraction (gh-130959)
+            '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
index 00000000000000..00e83b4af6be7a
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-06-25-07-08-17.gh-issue-152157.dt5Ef0.rst
@@ -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.
diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c
index 3122d0196519d5..f81234f39307c6 100644
--- a/Modules/_datetimemodule.c
+++ b/Modules/_datetimemodule.c
@@ -1031,7 +1031,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 == ':')) {
@@ -1040,14 +1049,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
         }
     }

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to