Skip to content

Commit 66b8a63

Browse files
authored
Merge pull request #250 from carterbox/no-overflow-naturaldelta
2 parents e89c8c8 + eb3e253 commit 66b8a63

File tree

2 files changed

+22
-52
lines changed

2 files changed

+22
-52
lines changed

src/humanize/time.py

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -87,24 +87,26 @@ def naturaldelta(
8787
value,
8888
months=True,
8989
minimum_unit="seconds",
90-
when=None,
9190
) -> str:
9291
"""Return a natural representation of a timedelta or number of seconds.
9392
9493
This is similar to `naturaltime`, but does not add tense to the result.
9594
9695
Args:
97-
value (datetime.timedelta): A timedelta or a number of seconds.
96+
value (datetime.timedelta or int): A timedelta or a number of seconds.
9897
months (bool): If `True`, then a number of months (based on 30.5 days) will be
9998
used for fuzziness between years.
10099
minimum_unit (str): The lowest unit that can be used.
101-
when (datetime.datetime): Point in time relative to which _value_ is
102-
interpreted. Defaults to the current time in the local timezone.
103-
Deprecated in version 3.14; If you need to construct a timedelta,
104-
do it inline as the first argument.
100+
when (datetime.datetime): Removed in version 4.0; If you need to
101+
construct a timedelta, do it inline as the first argument.
105102
106103
Returns:
107-
str: A natural representation of the amount of time elapsed.
104+
str (str or `value`): A natural representation of the amount of time
105+
elapsed unless `value` is not datetime.timedelta or cannot be
106+
converted to int. In that case, a `value` is returned unchanged.
107+
108+
Raises:
109+
OverflowError: If `value` is too large to convert to datetime.timedelta.
108110
109111
Examples
110112
Compare two timestamps in a custom local timezone::
@@ -116,24 +118,21 @@ def naturaldelta(
116118
now = dt.datetime.now(tz=berlin)
117119
later = now + dt.timedelta(minutes=30)
118120
119-
assert naturaldelta(later, when=now) == "30 minutes"
121+
assert naturaldelta(later - now) == "30 minutes"
120122
"""
121-
if when:
122-
warnings.warn(
123-
"The `when` parameter of `naturaldelta()` is deprecated and will be "
124-
"removed in humanize 4.0. If you need to construct a timedelta, "
125-
"do it inline as the first argument.",
126-
DeprecationWarning,
127-
stacklevel=2,
128-
)
129123
tmp = Unit[minimum_unit.upper()]
130124
if tmp not in (Unit.SECONDS, Unit.MILLISECONDS, Unit.MICROSECONDS):
131125
raise ValueError(f"Minimum unit '{minimum_unit}' not supported")
132126
minimum_unit = tmp
133127

134-
date, delta = _date_and_delta(value, now=when)
135-
if date is None:
136-
return value
128+
if isinstance(value, dt.timedelta):
129+
delta = value
130+
else:
131+
try:
132+
value = int(value)
133+
delta = dt.timedelta(seconds=value)
134+
except (ValueError, TypeError):
135+
return value
137136

138137
use_months = months
139138

@@ -238,7 +237,7 @@ def naturaltime(
238237
future = date > now
239238

240239
ago = _("%s from now") if future else _("%s ago")
241-
delta = naturaldelta(delta, months, minimum_unit, when=when)
240+
delta = naturaldelta(delta, months, minimum_unit)
242241

243242
if delta == _("a moment"):
244243
return _("now")

tests/test_time.py

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,9 @@ def test_naturaldelta_nomonths(test_input, expected):
119119
(dt.timedelta(days=9), "9 days"),
120120
(dt.timedelta(days=365), "a year"),
121121
(dt.timedelta(days=365 * 1_141), "1,141 years"),
122-
("NaN", "NaN"),
122+
("NaN", "NaN"), # Returns non-numbers unchanged.
123+
# largest possible timedelta
124+
(dt.timedelta(days=999_999_999), "2,739,726 years"),
123125
],
124126
)
125127
def test_naturaldelta(test_input, expected):
@@ -333,37 +335,6 @@ def test_naturaldelta_minimum_unit_explicit(minimum_unit, seconds, expected):
333335
assert humanize.naturaldelta(delta, minimum_unit=minimum_unit) == expected
334336

335337

336-
@pytest.mark.parametrize(
337-
"test_input, when, expected",
338-
[
339-
(NOW, NOW, "a moment"),
340-
(NOW_UTC, NOW_UTC, "a moment"),
341-
],
342-
)
343-
def test_naturaldelta_when_explicit(test_input, when, expected):
344-
# Act / Assert
345-
assert humanize.naturaldelta(test_input, when=when) == expected
346-
347-
348-
@pytest.mark.parametrize(
349-
"value, when",
350-
[
351-
(NOW_UTC, None),
352-
(NOW_UTC, NOW),
353-
(NOW_UTC_PLUS_01_00, None),
354-
(NOW_UTC_PLUS_01_00, NOW),
355-
],
356-
)
357-
def test_naturaldelta_when_missing_tzinfo(value, when):
358-
"""Subtraction `when - value` is not defined by the `datetime` module when
359-
either operand has not timezone-info (`tz=None`) and raises a TypeError.
360-
"""
361-
362-
# Act / Assert
363-
with pytest.raises(TypeError):
364-
humanize.naturaldelta(value, when=when)
365-
366-
367338
@pytest.mark.parametrize(
368339
"seconds, expected",
369340
[

0 commit comments

Comments
 (0)