https://github.com/python/cpython/commit/9f8f8d95bd846321ba934cd81dce33e12413f611 commit: 9f8f8d95bd846321ba934cd81dce33e12413f611 branch: main author: rajorin <[email protected]> committer: gpshead <[email protected]> date: 2026-10-22T00:43:53Z summary:
gh-158501: Reject stray text before a UTC offset in fromisoformat (GH-159224) The C parser treated the timezone designator as leftover input, then ignored that leftover whenever an offset was present. Strings such as '12:30x+05:00' were accepted even though the pure-Python implementation rejects them. --------- Co-authored-by: Gregory P. Smith <[email protected]> files: A Misc/NEWS.d/next/Library/2026-10-12-13-05-00.gh-issue-158501.n7Qp3k.rst M Lib/test/datetimetester.py M Modules/_datetimemodule.c diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 09a0ef5d223d2b..df7d540cb362f7 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -3770,6 +3770,10 @@ def test_fromisoformat_fails_datetime(self): '2009-04-19T12:30:45.400 +02:30', # Space between ms and timezone (gh-130959) '2009-04-19T12:30:45.400 ', # Trailing space (gh-130959) '2009-04-19T12:30:45. 400', # Space before fraction (gh-130959) + '2009-04-19T12:30x+05:00', # Stray text before offset (gh-158501) + '2009-04-19T12:30:45 +02:00', # Space before offset (gh-158501) + '2009-04-19T12:30:45.123456 junk Z', # Stray text before Z (gh-158501) + '20090419T1230:Z', # Stray separator before Z (gh-158501) '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 '2009-04-19T12:30:45-00:90:00', # Time zone field out from range @@ -5094,6 +5098,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:30x+05:00', # Stray text before offset (gh-158501) + '12:30:45 +02:00', # Space before offset (gh-158501) + '12:30:45.123456 junk Z', # Stray text before Z (gh-158501) + '1230:Z', # Stray separator before Z (gh-158501) '24:00:00.000001', # Has non-zero microseconds on 24:00 '24:00:01.000000', # Has non-zero seconds on 24:00 '24:01:00.000000', # Has non-zero minutes on 24:00 diff --git a/Misc/NEWS.d/next/Library/2026-10-12-13-05-00.gh-issue-158501.n7Qp3k.rst b/Misc/NEWS.d/next/Library/2026-10-12-13-05-00.gh-issue-158501.n7Qp3k.rst new file mode 100644 index 00000000000000..e47c5da38c8e86 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-12-13-05-00.gh-issue-158501.n7Qp3k.rst @@ -0,0 +1,4 @@ +:meth:`datetime.time.fromisoformat` and +:meth:`datetime.datetime.fromisoformat` now reject stray text between the +time and a UTC offset. The C implementation previously accepted strings +that the pure-Python implementation rejected. diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 511b444037ceac..cd2dd94c8164a5 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -1046,8 +1046,11 @@ parse_hh_mm_ss_ff(const char *tstr, const char *tstr_end, int *hour, } break; } - else if (p >= p_end) { - return c != '\0'; + else if (p > p_end) { + return 0; // Stopped at p_end: an offset designator or NUL + } + else if (p == p_end) { + return 1; // Stray character just before p_end } else if (has_separator && (c == ':')) { if (i == 2) { @@ -1087,8 +1090,8 @@ parse_hh_mm_ss_ff(const char *tstr, const char *tstr_end, int *hour, ++p; // skip truncated digits } - // Return 1 if it's not the end of the string - return *p != '\0'; + // Return 1 if there is unparsed text before p_end + return p != p_end; } static int @@ -1122,15 +1125,11 @@ parse_isoformat_time(const char *dtstr, size_t dtlen, int *hour, int *minute, if (rv < 0) { return rv; } + else if (rv == 1) { + return -5; // Unparsed text after the time + } else if (tzinfo_pos == p_end) { - // We know that there's no time zone, so if there's stuff at the - // end of the string it's an error. - if (rv == 1) { - return -5; - } - else { - return 0; - } + return 0; } // Special case UTC / Zulu time. _______________________________________________ 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]
