Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit71c42b7

Browse files
donBarboserlend-aaslandpganssle
authored
gh-126883: Add check that timezone fields are in range fordatetime.fromisoformat (#127242)
It was previously possible to specify things like `+00:90:00` which would be equivalent to `+01:30:00`, but is not a valid ISO8601 string.---------Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>Co-authored-by: Paul Ganssle <1377457+pganssle@users.noreply.github.com>
1 parent8d490b3 commit71c42b7

File tree

5 files changed

+63
-9
lines changed

5 files changed

+63
-9
lines changed

‎Lib/_pydatetime.py

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ def _parse_isoformat_time(tstr):
467467
hour,minute,second,microsecond=time_comps
468468
became_next_day=False
469469
error_from_components=False
470+
error_from_tz=None
470471
if (hour==24):
471472
ifall(time_comp==0fortime_compintime_comps[1:]):
472473
hour=0
@@ -500,14 +501,22 @@ def _parse_isoformat_time(tstr):
500501
else:
501502
tzsign=-1iftstr[tz_pos-1]=='-'else1
502503

503-
td=timedelta(hours=tz_comps[0],minutes=tz_comps[1],
504-
seconds=tz_comps[2],microseconds=tz_comps[3])
505-
506-
tzi=timezone(tzsign*td)
504+
try:
505+
# This function is intended to validate datetimes, but because
506+
# we restrict time zones to ±24h, it serves here as well.
507+
_check_time_fields(hour=tz_comps[0],minute=tz_comps[1],
508+
second=tz_comps[2],microsecond=tz_comps[3],
509+
fold=0)
510+
exceptValueErrorase:
511+
error_from_tz=e
512+
else:
513+
td=timedelta(hours=tz_comps[0],minutes=tz_comps[1],
514+
seconds=tz_comps[2],microseconds=tz_comps[3])
515+
tzi=timezone(tzsign*td)
507516

508517
time_comps.append(tzi)
509518

510-
returntime_comps,became_next_day,error_from_components
519+
returntime_comps,became_next_day,error_from_components,error_from_tz
511520

512521
# tuple[int, int, int] -> tuple[int, int, int] version of date.fromisocalendar
513522
def_isoweek_to_gregorian(year,week,day):
@@ -1633,9 +1642,21 @@ def fromisoformat(cls, time_string):
16331642
time_string=time_string.removeprefix('T')
16341643

16351644
try:
1636-
returncls(*_parse_isoformat_time(time_string)[0])
1637-
exceptException:
1638-
raiseValueError(f'Invalid isoformat string:{time_string!r}')
1645+
time_components,_,error_from_components,error_from_tz= (
1646+
_parse_isoformat_time(time_string)
1647+
)
1648+
exceptValueError:
1649+
raiseValueError(
1650+
f'Invalid isoformat string:{time_string!r}')fromNone
1651+
else:
1652+
iferror_from_tz:
1653+
raiseerror_from_tz
1654+
iferror_from_components:
1655+
raiseValueError(
1656+
"Minute, second, and microsecond must be 0 when hour is 24"
1657+
)
1658+
1659+
returncls(*time_components)
16391660

16401661
defstrftime(self,format):
16411662
"""Format using strftime(). The date part of the timestamp passed
@@ -1947,11 +1968,16 @@ def fromisoformat(cls, date_string):
19471968

19481969
iftstr:
19491970
try:
1950-
time_components,became_next_day,error_from_components=_parse_isoformat_time(tstr)
1971+
(time_components,
1972+
became_next_day,
1973+
error_from_components,
1974+
error_from_tz)=_parse_isoformat_time(tstr)
19511975
exceptValueError:
19521976
raiseValueError(
19531977
f'Invalid isoformat string:{date_string!r}')fromNone
19541978
else:
1979+
iferror_from_tz:
1980+
raiseerror_from_tz
19551981
iferror_from_components:
19561982
raiseValueError("minute, second, and microsecond must be 0 when hour is 24")
19571983

‎Lib/test/datetimetester.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3571,6 +3571,10 @@ def test_fromisoformat_fails_datetime(self):
35713571
'2009-04-19T12:30:45.400 +02:30',# Space between ms and timezone (gh-130959)
35723572
'2009-04-19T12:30:45.400 ',# Trailing space (gh-130959)
35733573
'2009-04-19T12:30:45. 400',# Space before fraction (gh-130959)
3574+
'2009-04-19T12:30:45+00:90:00',# Time zone field out from range
3575+
'2009-04-19T12:30:45+00:00:90',# Time zone field out from range
3576+
'2009-04-19T12:30:45-00:90:00',# Time zone field out from range
3577+
'2009-04-19T12:30:45-00:00:90',# Time zone field out from range
35743578
]
35753579

35763580
forbad_strinbad_strs:
@@ -4795,6 +4799,11 @@ def test_fromisoformat_fails(self):
47954799
'12:30:45.400 +02:30',# Space between ms and timezone (gh-130959)
47964800
'12:30:45.400 ',# Trailing space (gh-130959)
47974801
'12:30:45. 400',# Space before fraction (gh-130959)
4802+
'24:00:00.000001',# Has non-zero microseconds on 24:00
4803+
'24:00:01.000000',# Has non-zero seconds on 24:00
4804+
'24:01:00.000000',# Has non-zero minutes on 24:00
4805+
'12:30:45+00:90:00',# Time zone field out from range
4806+
'12:30:45+00:00:90',# Time zone field out from range
47984807
]
47994808

48004809
forbad_strinbad_strs:

‎Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,6 +1288,7 @@ Paul Moore
12881288
Ross Moore
12891289
Ben Morgan
12901290
Emily Morehouse
1291+
Semyon Moroz
12911292
Derek Morr
12921293
James A Morrison
12931294
Martin Morrison
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Add check that timezone fields are in range for
2+
:meth:`datetime.datetime.fromisoformat` and
3+
:meth:`datetime.time.fromisoformat`. Patch by Semyon Moroz.

‎Modules/_datetimemodule.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,7 @@ parse_isoformat_time(const char *dtstr, size_t dtlen, int *hour, int *minute,
10881088
// -3: Failed to parse time component
10891089
// -4: Failed to parse time separator
10901090
// -5: Malformed timezone string
1091+
// -6: Timezone fields are not in range
10911092

10921093
constchar*p=dtstr;
10931094
constchar*p_end=dtstr+dtlen;
@@ -1134,6 +1135,11 @@ parse_isoformat_time(const char *dtstr, size_t dtlen, int *hour, int *minute,
11341135
rv=parse_hh_mm_ss_ff(tzinfo_pos,p_end,&tzhour,&tzminute,&tzsecond,
11351136
tzmicrosecond);
11361137

1138+
// Check if timezone fields are in range
1139+
if (check_time_args(tzhour,tzminute,tzsecond,*tzmicrosecond,0)<0) {
1140+
return-6;
1141+
}
1142+
11371143
*tzoffset=tzsign* ((tzhour*3600)+ (tzminute*60)+tzsecond);
11381144
*tzmicrosecond *=tzsign;
11391145

@@ -5039,6 +5045,9 @@ time_fromisoformat(PyObject *cls, PyObject *tstr) {
50395045
&tzoffset,&tzimicrosecond);
50405046

50415047
if (rv<0) {
5048+
if (rv==-6) {
5049+
gotoerror;
5050+
}
50425051
gotoinvalid_string_error;
50435052
}
50445053

@@ -5075,6 +5084,9 @@ time_fromisoformat(PyObject *cls, PyObject *tstr) {
50755084
invalid_string_error:
50765085
PyErr_Format(PyExc_ValueError,"Invalid isoformat string: %R",tstr);
50775086
returnNULL;
5087+
5088+
error:
5089+
returnNULL;
50785090
}
50795091

50805092

@@ -5927,6 +5939,9 @@ datetime_fromisoformat(PyObject *cls, PyObject *dtstr)
59275939
len-= (p-dt_ptr);
59285940
rv=parse_isoformat_time(p,len,&hour,&minute,&second,
59295941
&microsecond,&tzoffset,&tzusec);
5942+
if (rv==-6) {
5943+
gotoerror;
5944+
}
59305945
}
59315946
if (rv<0) {
59325947
gotoinvalid_string_error;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp