Skip to content

Commit 54ecfa5

Browse files
committed
gh-152157: Reject empty fraction before timezone in C fromisoformat
The C accelerator for datetime.fromisoformat() and time.fromisoformat() accepted a decimal separator (. or ,) with no following digit when a timezone designator came next, e.g. '12:34:56.+05:00', while the pure-Python implementation correctly raised ValueError. Handle the decimal-separator case before the generic end-of-substring check so an empty fraction is rejected.
1 parent a6c2d4a commit 54ecfa5

3 files changed

Lines changed: 23 additions & 7 deletions

File tree

Lib/test/datetimetester.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3758,6 +3758,10 @@ def test_fromisoformat_fails_datetime(self):
37583758
'2009-04-19T12:30:45-00:90:00', # Time zone field out from range
37593759
'2009-04-19T12:30:45-00:00:90', # Time zone field out from range
37603760
'2020-2020', # Ambiguous 9-char date portion
3761+
'2009-04-19T12:30:45.+05:00', # Empty fraction before offset
3762+
'2009-04-19T12:30:45.-05:00', # Empty fraction before offset
3763+
'2009-04-19T12:30:45.Z', # Empty fraction before Z
3764+
'2009-04-19T12:30:45,+05:00', # Empty fraction (comma) before offset
37613765
]
37623766

37633767
for bad_str in bad_strs:
@@ -5003,6 +5007,10 @@ def test_fromisoformat_fails(self):
50035007
'24:01:00.000000', # Has non-zero minutes on 24:00
50045008
'12:30:45+00:90:00', # Time zone field out from range
50055009
'12:30:45+00:00:90', # Time zone field out from range
5010+
'12:30:45.+05:00', # Empty fraction before offset
5011+
'12:30:45.-05:00', # Empty fraction before offset
5012+
'12:30:45.Z', # Empty fraction before Z
5013+
'12:30:45,+05:00', # Empty fraction (comma) before offset
50065014
]
50075015

50085016
for bad_str in bad_strs:
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
:meth:`~datetime.datetime.fromisoformat` and :meth:`~datetime.time.fromisoformat`
2+
now reject a decimal separator (``.`` or ``,``) that is not followed by any
3+
fractional digit before a timezone designator, such as ``'12:34:56.+05:00'``.
4+
The C implementation previously accepted such strings while the pure-Python
5+
implementation correctly raised :exc:`ValueError`.

Modules/_datetimemodule.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,20 +1034,23 @@ parse_hh_mm_ss_ff(const char *tstr, const char *tstr_end, int *hour,
10341034
has_separator = (c == ':');
10351035
}
10361036

1037-
if (p >= p_end) {
1037+
if (c == '.' || c == ',') {
1038+
if (i < 2) {
1039+
return -3; // Decimal mark on hour or minute
1040+
}
1041+
if (p >= p_end) {
1042+
return -3; // Decimal mark not followed by any digit
1043+
}
1044+
break;
1045+
}
1046+
else if (p >= p_end) {
10381047
return c != '\0';
10391048
}
10401049
else if (has_separator && (c == ':')) {
10411050
if (i == 2) {
10421051
return -4; // Malformed microsecond separator
10431052
}
10441053
continue;
1045-
}
1046-
else if (c == '.' || c == ',') {
1047-
if (i < 2) {
1048-
return -3; // Decimal mark on hour or minute
1049-
}
1050-
break;
10511054
} else if (!has_separator) {
10521055
--p;
10531056
} else {

0 commit comments

Comments
 (0)