Skip to content
11 changes: 8 additions & 3 deletions src/humanize/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

__lazy_modules__ = {"humanize.i18n", "humanize.number"}

import math
from enum import Enum
from functools import total_ordering

Expand Down Expand Up @@ -117,9 +118,6 @@ def naturaldelta(
converted to int (cannot be float due to 'inf' or 'nan').
In that case, a `value` is returned unchanged.

Raises:
OverflowError: If `value` is too large to convert to datetime.timedelta.

Examples:
Compare two timestamps in a custom local timezone::

Expand Down Expand Up @@ -151,6 +149,13 @@ def naturaldelta(
int(value) # Explicitly don't support string such as "NaN" or "inf"
value = float(value)
delta = dt.timedelta(seconds=value)
except OverflowError:
# int(value) raises OverflowError for non-finite floats (inf/-inf).
# Like NaN they are returned unchanged. A truly too-large *finite*
# float still raises, preserving the documented OverflowError contract.
if not math.isfinite(value):
return str(value)
raise
except (ValueError, TypeError):
return str(value)

Expand Down
19 changes: 19 additions & 0 deletions tests/test_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,25 @@ def test_naturaldelta(test_input: float | dt.timedelta, expected: str) -> None:
assert humanize.naturaldelta(-test_input) == expected


def test_naturaldelta_non_finite_floats() -> None:
"""Regression for #333: non-finite floats must not raise OverflowError.

float("inf") and float("-inf") trigger int(value) -> OverflowError inside
timedelta(seconds=value). They should be returned as strings, like float("nan").
A legitimately too-large *finite* float must still raise OverflowError.
"""
# Non-finite values return the string repr
assert humanize.naturaldelta(float("inf")) == "inf"
assert humanize.naturaldelta(float("-inf")) == "-inf"
# NaN already worked before; confirm it still does
assert humanize.naturaldelta(float("nan")) == "nan"
# A truly too-large finite float must still raise (documented behaviour)
import pytest

with pytest.raises(OverflowError):
humanize.naturaldelta(1e308 * 10)


@freeze_time(FROZEN_DATE)
@pytest.mark.parametrize(
"test_input, expected",
Expand Down
Loading