From 6cc8d1e781235235d66e08b8925c1ef03d037fa5 Mon Sep 17 00:00:00 2001 From: santhreal <64453045+santhreal@users.noreply.github.com> Date: Fri, 17 Jul 2026 22:09:33 -0700 Subject: [PATCH 1/2] fix: avoid OverflowError in naturaltime for far-future dates _abs_timedelta used now-(now+delta), which underflows below year 1 for large negative deltas. Negate the timedelta directly instead. --- src/humanize/time.py | 12 ++++++++---- tests/test_time.py | 4 ++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/humanize/time.py b/src/humanize/time.py index 4a07d528..5b601709 100644 --- a/src/humanize/time.py +++ b/src/humanize/time.py @@ -61,9 +61,9 @@ def _abs_timedelta(delta: dt.timedelta) -> dt.timedelta: Returns: datetime.timedelta: Absolute timedelta. """ + # Avoid datetime arithmetic: now+(now-far_future) underflows below year 1. if delta.days < 0: - now = _now() - return now - (now + delta) + return -delta return delta @@ -82,14 +82,18 @@ def _date_and_delta( date = value delta = now - value elif isinstance(value, dt.timedelta): - date = now - value delta = value + try: + date = now - value + except OverflowError: + # Tense only: negative timedelta means future in naturaltime. + date = now + dt.timedelta(days=1) if value < dt.timedelta(0) else now - dt.timedelta(days=1) else: try: value = value if precise else round(value) delta = dt.timedelta(seconds=value) date = now - delta - except (ValueError, TypeError): + except (ValueError, TypeError, OverflowError): return None, value return date, _abs_timedelta(delta) diff --git a/tests/test_time.py b/tests/test_time.py index 76997704..22a276aa 100644 --- a/tests/test_time.py +++ b/tests/test_time.py @@ -179,6 +179,10 @@ def test_naturaldelta(test_input: float | dt.timedelta, expected: str) -> None: (NOW - dt.timedelta(days=365 * 2 + 65), "2 years ago"), (NOW - dt.timedelta(days=365 + 4), "1 year, 4 days ago"), ("NaN", "NaN"), + # Far-future datetimes used to OverflowError in _abs_timedelta. + (dt.datetime(9999, 1, 1), "7,994 years from now"), + (dt.datetime(5000, 6, 15), "2,992 years from now"), + (dt.timedelta(days=-1_000_000), "2,739 years from now"), ], ) def test_naturaltime( From dc93cf33a3a598c6b2246dad6c67fc8f94342320 Mon Sep 17 00:00:00 2001 From: santhreal <64453045+santhreal@users.noreply.github.com> Date: Fri, 17 Jul 2026 22:14:25 -0700 Subject: [PATCH 2/2] refactor: drop OverflowError sentinel from date_and_delta Ship only the _abs_timedelta negation fix; the timedelta Overflow fallback was out of scope for the far-future naturaltime crash. --- src/humanize/time.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/humanize/time.py b/src/humanize/time.py index 5b601709..a36f3b1e 100644 --- a/src/humanize/time.py +++ b/src/humanize/time.py @@ -82,18 +82,14 @@ def _date_and_delta( date = value delta = now - value elif isinstance(value, dt.timedelta): + date = now - value delta = value - try: - date = now - value - except OverflowError: - # Tense only: negative timedelta means future in naturaltime. - date = now + dt.timedelta(days=1) if value < dt.timedelta(0) else now - dt.timedelta(days=1) else: try: value = value if precise else round(value) delta = dt.timedelta(seconds=value) date = now - delta - except (ValueError, TypeError, OverflowError): + except (ValueError, TypeError): return None, value return date, _abs_timedelta(delta)