python/cpython · error · ValueError
second must be in 0..59, not {second}
Error message
second must be in 0..59, not {second} What it means
Raised by _check_time_fields() when the second argument to time()/datetime() is not in 0..59. Notably, second=60 (a leap second) is invalid: CPython's datetime does not represent leap seconds, so UTC times like 23:59:60 must be handled before construction.
Source
Thrown at Lib/_pydatetime.py:591
raise ValueError(f"year must be in {MINYEAR}..{MAXYEAR}, not {year}")
if not 1 <= month <= 12:
raise ValueError(f"month must be in 1..12, not {month}")
dim = _days_in_month(year, month)
if not 1 <= day <= dim:
raise ValueError(f"day {day} must be in range 1..{dim} for month {month} in year {year}")
return year, month, day
def _check_time_fields(hour, minute, second, microsecond, fold):
hour = _index(hour)
minute = _index(minute)
second = _index(second)
microsecond = _index(microsecond)
if not 0 <= hour <= 23:
raise ValueError(f"hour must be in 0..23, not {hour}")
if not 0 <= minute <= 59:
raise ValueError(f"minute must be in 0..59, not {minute}")
if not 0 <= second <= 59:
raise ValueError(f"second must be in 0..59, not {second}")
if not 0 <= microsecond <= 999999:
raise ValueError(f"microsecond must be in 0..999999, not {microsecond}")
if fold not in (0, 1):
raise ValueError(f"fold must be either 0 or 1, not {fold}")
return hour, minute, second, microsecond, fold
def _check_tzinfo_arg(tz):
if tz is not None and not isinstance(tz, tzinfo):
raise TypeError(
"tzinfo argument must be None or of a tzinfo subclass, "
f"not {type(tz).__name__!r}"
)
def _divide_and_round(a, b):
"""divide a by b and round result to the nearest integer
When the ratio is exactly half-way between two integers,
the even integer is returned.View on GitHub (pinned to bc6749cc3b)
Solutions
- Convert leap seconds to second=59 with an extra-second flag, or smear, before constructing datetime
- Use divmod carry: sec, rem = divmod(sec, 60) and add rem to minutes
- Validate 0 <= second <= 59 in ingestion parsers
Example fix
// before
dt = datetime(2016, 12, 31, 23, 59, 60) # leap second -> ValueError
// after
if sec == 60:
dt = datetime(2016, 12, 31, 23, 59, 59) # flag leap second separately
else:
dt = datetime(2016, 12, 31, 23, 59, sec) Defensive patterns
Strategy: validation
Validate before calling
if not 0 <= second <= 59:
raise ValueError('second must be 0..59 (leap seconds unsupported)') Type guard
def valid_second(s) -> bool:
return 0 <= s <= 59 Prevention
- Sanitize :60 leap seconds from GPS/NTP/UTC feeds before constructing datetimes
- Round sub-second carries into minutes with divmod(sec, 60)
When it happens
Trigger: time(23, 59, 60); parsing GPS/NTP or UTC timestamps during an inserted leap second; carrying 60 from sub-second rounding logic.
Common situations: Ingesting UTC time series or satellite/GPS data that contains :60 seconds; smearing or rounding bugs that produce second=60; test fixtures copied from leap-second tables.
Related errors
- hour must be in 0..23, not {hour}
- minute must be in 0..59, not {minute}
- microsecond must be in 0..999999, not {microsecond}
- month must be in 1..12, not {month}
- day {day} must be in range 1..{dim} for month {month} in yea
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/b3b25da094af5419.
Report an issue: GitHub.