diff --git a/src/humanize/time.py b/src/humanize/time.py index 7c4a28eb..a14f5250 100644 --- a/src/humanize/time.py +++ b/src/humanize/time.py @@ -61,10 +61,10 @@ def _abs_timedelta(delta: dt.timedelta) -> dt.timedelta: Returns: datetime.timedelta: Absolute timedelta. """ - if delta.days < 0: - now = _now() - return now - (now + delta) - return delta + # Use abs() rather than round-tripping through the current datetime: + # `now + delta` overflows (OverflowError) when a negative delta reaches back + # past year 1, e.g. for naturaltime(dt.datetime(9999, 12, 31)). + return abs(delta) def _date_and_delta( diff --git a/tests/test_time.py b/tests/test_time.py index 887a3fc5..c483e669 100644 --- a/tests/test_time.py +++ b/tests/test_time.py @@ -196,6 +196,9 @@ def test_naturaldelta_too_large_value_raises() -> None: (NOW - dt.timedelta(days=365 + 35), "1 year, 1 month ago"), (dt.timedelta(days=-10000), "27 years from now"), (dt.timedelta(days=365 + 35), "1 year, 1 month ago"), + # far-future values used to raise OverflowError in _abs_timedelta + (dt.datetime(9999, 12, 31), "7,995 years from now"), + (dt.timedelta(days=-800_000), "2,192 years from now"), (22.5, "22 seconds ago"), (23.5, "24 seconds ago"), (23.9, "24 seconds ago"), @@ -645,6 +648,12 @@ def test_precisedelta_one_unit_enough( (dt.timedelta(days=32), "seconds", "1 month and 1 day"), (dt.timedelta(days=62), "seconds", "2 months and 1 day"), (dt.timedelta(days=92), "seconds", "3 months"), + # a negative delta reaching back past year 1 used to raise OverflowError + ( + dt.timedelta(days=-800_000), + "seconds", + "2,191 years, 9 months and 10 days", + ), (dt.timedelta(days=31), "days", "1 month"), (dt.timedelta(days=32), "days", "1 month and 1 day"), (dt.timedelta(days=62), "days", "2 months and 1 day"),