Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions Lib/_pydatetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,14 +360,20 @@ def _parse_isoformat_date(dtstr):
# see the comment on Modules/_datetimemodule.c:_find_isoformat_datetime_separator
if len(dtstr) not in (7, 8, 10):
raise ValueError("Invalid isoformat string")
year = int(dtstr[0:4])
def _read(s, n):
# Require exactly n ASCII digits, as the C parse_digits() does.
if len(s) != n or not all(map(_is_ascii_digit, s)):
raise ValueError(f"Invalid isoformat string: {dtstr!r}")
return int(s)

year = _read(dtstr[0:4], 4)
has_sep = dtstr[4] == '-'

pos = 4 + has_sep
if dtstr[pos:pos + 1] == "W":
# YYYY-?Www-?D?
pos += 1
weekno = int(dtstr[pos:pos + 2])
weekno = _read(dtstr[pos:pos + 2], 2)
pos += 2

dayno = 1
Expand All @@ -377,17 +383,17 @@ def _parse_isoformat_date(dtstr):

pos += has_sep

dayno = int(dtstr[pos:pos + 1])
dayno = _read(dtstr[pos:pos + 1], 1)

return list(_isoweek_to_gregorian(year, weekno, dayno))
else:
month = int(dtstr[pos:pos + 2])
month = _read(dtstr[pos:pos + 2], 2)
pos += 2
if (dtstr[pos:pos + 1] == "-") != has_sep:
raise ValueError("Inconsistent use of dash separator")

pos += has_sep
day = int(dtstr[pos:pos + 2])
day = _read(dtstr[pos:pos + 2], 2)

return [year, month, day]

Expand Down
10 changes: 10 additions & 0 deletions Lib/test/datetimetester.py
Original file line number Diff line number Diff line change
Expand Up @@ -2106,6 +2106,16 @@ def test_fromisoformat_fails(self):
'10000-W25-1', # Invalid year
'2020-W25-0', # Invalid day-of-week
'2020-W25-8', # Invalid day-of-week
# gh-152204: each fixed-width field must be exactly N ASCII digits
'2020+12', # '+' accepted in a basic-format field
'2020 12', # space accepted in a basic-format field
'+020-06-15', # leading sign in the year
'202012+9', # '+' in the day field
'2020-W 5', # space in the week day-of-week field
'2020061', # 7 chars: day slice reads a 1-character tail
'2020123', # 7 chars: day slice reads a 1-character tail
'9999121', # 7 chars: day slice reads a 1-character tail
'2020-W2', # 1-digit week number
'٢025-03-09' # Unicode characters
'2009\ud80002\ud80028', # Separators are surrogate codepoints
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Fix the pure-Python implementation of :meth:`datetime.date.fromisoformat`
silently mis-parsing some malformed ISO 8601 basic-format dates (for example
``'2020+12'`` or ``'2020061'``). Each fixed-width field is now required to be
exactly *N* ASCII digits before conversion, matching the C implementation,
which already rejected these inputs.
Loading