Skip to content

Commit b3890f4

Browse files
committed
Add Python implementation
1 parent 00ba564 commit b3890f4

File tree

1 file changed

+30
-5
lines changed

1 file changed

+30
-5
lines changed

Lib/_pydatetime.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,16 @@ def _parse_isoformat_time(tstr):
431431

432432
time_comps = _parse_hh_mm_ss_ff(timestr)
433433

434+
hour, minute, second, microsecond = time_comps
435+
became_next_day = False
436+
if (hour == 24):
437+
if not all(time_comp == 0 for time_comp in time_comps[1:]):
438+
raise ValueError("minute, second, and microsecond must be 0 when hour is 24")
439+
440+
hour = 0
441+
time_comps[0] = hour
442+
became_next_day = True
443+
434444
tzi = None
435445
if tz_pos == len_str and tstr[-1] == 'Z':
436446
tzi = timezone.utc
@@ -456,14 +466,14 @@ def _parse_isoformat_time(tstr):
456466
else:
457467
tzsign = -1 if tstr[tz_pos - 1] == '-' else 1
458468

459-
td = timedelta(hours=tz_comps[0], minutes=tz_comps[1],
460-
seconds=tz_comps[2], microseconds=tz_comps[3])
469+
td = timedelta(hours=hour, minutes=minute,
470+
seconds=second, microseconds=microsecond)
461471

462472
tzi = timezone(tzsign * td)
463473

464474
time_comps.append(tzi)
465475

466-
return time_comps
476+
return time_comps, became_next_day
467477

468478
# tuple[int, int, int] -> tuple[int, int, int] version of date.fromisocalendar
469479
def _isoweek_to_gregorian(year, week, day):
@@ -1559,7 +1569,7 @@ def fromisoformat(cls, time_string):
15591569
time_string = time_string.removeprefix('T')
15601570

15611571
try:
1562-
return cls(*_parse_isoformat_time(time_string))
1572+
return cls(*_parse_isoformat_time(time_string)[0])
15631573
except Exception:
15641574
raise ValueError(f'Invalid isoformat string: {time_string!r}')
15651575

@@ -1871,10 +1881,25 @@ def fromisoformat(cls, date_string):
18711881

18721882
if tstr:
18731883
try:
1874-
time_components = _parse_isoformat_time(tstr)
1884+
time_components, became_next_day = _parse_isoformat_time(tstr)
18751885
except ValueError:
18761886
raise ValueError(
18771887
f'Invalid isoformat string: {date_string!r}') from None
1888+
else:
1889+
if became_next_day:
1890+
year, month, day = date_components
1891+
1892+
# Only wrap day/month when it was previously valid
1893+
if month <= 12 and day <= (days_in_month := _days_in_month(year, month)):
1894+
# Calculate midnight of the next day
1895+
day += 1
1896+
if day > days_in_month:
1897+
day = 1
1898+
month += 1
1899+
if month > 12:
1900+
month = 1
1901+
year += 1
1902+
date_components = [year, month, day]
18781903
else:
18791904
time_components = [0, 0, 0, 0, None]
18801905

0 commit comments

Comments
 (0)