Skip to content

Commit

Permalink
Merge pull request #250 from carterbox/no-overflow-naturaldelta
Browse files Browse the repository at this point in the history
  • Loading branch information
hugovk authored Feb 12, 2022
2 parents e89c8c8 + eb3e253 commit 66b8a63
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 52 deletions.
39 changes: 19 additions & 20 deletions src/humanize/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,24 +87,26 @@ def naturaldelta(
value,
months=True,
minimum_unit="seconds",
when=None,
) -> str:
"""Return a natural representation of a timedelta or number of seconds.
This is similar to `naturaltime`, but does not add tense to the result.
Args:
value (datetime.timedelta): A timedelta or a number of seconds.
value (datetime.timedelta or int): A timedelta or a number of seconds.
months (bool): If `True`, then a number of months (based on 30.5 days) will be
used for fuzziness between years.
minimum_unit (str): The lowest unit that can be used.
when (datetime.datetime): Point in time relative to which _value_ is
interpreted. Defaults to the current time in the local timezone.
Deprecated in version 3.14; If you need to construct a timedelta,
do it inline as the first argument.
when (datetime.datetime): Removed in version 4.0; If you need to
construct a timedelta, do it inline as the first argument.
Returns:
str: A natural representation of the amount of time elapsed.
str (str or `value`): A natural representation of the amount of time
elapsed unless `value` is not datetime.timedelta or cannot be
converted to int. 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 All @@ -116,24 +118,21 @@ def naturaldelta(
now = dt.datetime.now(tz=berlin)
later = now + dt.timedelta(minutes=30)
assert naturaldelta(later, when=now) == "30 minutes"
assert naturaldelta(later - now) == "30 minutes"
"""
if when:
warnings.warn(
"The `when` parameter of `naturaldelta()` is deprecated and will be "
"removed in humanize 4.0. If you need to construct a timedelta, "
"do it inline as the first argument.",
DeprecationWarning,
stacklevel=2,
)
tmp = Unit[minimum_unit.upper()]
if tmp not in (Unit.SECONDS, Unit.MILLISECONDS, Unit.MICROSECONDS):
raise ValueError(f"Minimum unit '{minimum_unit}' not supported")
minimum_unit = tmp

date, delta = _date_and_delta(value, now=when)
if date is None:
return value
if isinstance(value, dt.timedelta):
delta = value
else:
try:
value = int(value)
delta = dt.timedelta(seconds=value)
except (ValueError, TypeError):
return value

use_months = months

Expand Down Expand Up @@ -238,7 +237,7 @@ def naturaltime(
future = date > now

ago = _("%s from now") if future else _("%s ago")
delta = naturaldelta(delta, months, minimum_unit, when=when)
delta = naturaldelta(delta, months, minimum_unit)

if delta == _("a moment"):
return _("now")
Expand Down
35 changes: 3 additions & 32 deletions tests/test_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ def test_naturaldelta_nomonths(test_input, expected):
(dt.timedelta(days=9), "9 days"),
(dt.timedelta(days=365), "a year"),
(dt.timedelta(days=365 * 1_141), "1,141 years"),
("NaN", "NaN"),
("NaN", "NaN"), # Returns non-numbers unchanged.
# largest possible timedelta
(dt.timedelta(days=999_999_999), "2,739,726 years"),
],
)
def test_naturaldelta(test_input, expected):
Expand Down Expand Up @@ -333,37 +335,6 @@ def test_naturaldelta_minimum_unit_explicit(minimum_unit, seconds, expected):
assert humanize.naturaldelta(delta, minimum_unit=minimum_unit) == expected


@pytest.mark.parametrize(
"test_input, when, expected",
[
(NOW, NOW, "a moment"),
(NOW_UTC, NOW_UTC, "a moment"),
],
)
def test_naturaldelta_when_explicit(test_input, when, expected):
# Act / Assert
assert humanize.naturaldelta(test_input, when=when) == expected


@pytest.mark.parametrize(
"value, when",
[
(NOW_UTC, None),
(NOW_UTC, NOW),
(NOW_UTC_PLUS_01_00, None),
(NOW_UTC_PLUS_01_00, NOW),
],
)
def test_naturaldelta_when_missing_tzinfo(value, when):
"""Subtraction `when - value` is not defined by the `datetime` module when
either operand has not timezone-info (`tz=None`) and raises a TypeError.
"""

# Act / Assert
with pytest.raises(TypeError):
humanize.naturaldelta(value, when=when)


@pytest.mark.parametrize(
"seconds, expected",
[
Expand Down

0 comments on commit 66b8a63

Please sign in to comment.