Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an "all" granularity to humanize #1018

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
10 changes: 8 additions & 2 deletions arrow/arrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@

_GRANULARITY = Literal[
"auto",
"all",
"second",
"minute",
"hour",
Expand Down Expand Up @@ -1130,7 +1131,8 @@ def humanize(
:param locale: (optional) a ``str`` specifying a locale. Defaults to 'en-us'.
:param only_distance: (optional) returns only time difference eg: "11 seconds" without "in" or "ago" part.
:param granularity: (optional) defines the precision of the output. Set it to strings 'second', 'minute',
'hour', 'day', 'week', 'month' or 'year' or a list of any combination of these strings
'hour', 'day', 'week', 'month' or 'year' or a list of any combination of these strings.
Set it to 'all' to include all possible units in the granularity.

Usage::

Expand Down Expand Up @@ -1228,7 +1230,7 @@ def humanize(
years = sign * max(delta_second // self._SECS_PER_YEAR, 2)
return locale.describe("years", years, only_distance=only_distance)

elif isinstance(granularity, str):
elif isinstance(granularity, str) and granularity != "all":
granularity = cast(TimeFrameLiteral, granularity) # type: ignore[assignment]

if granularity == "second":
Expand Down Expand Up @@ -1282,6 +1284,10 @@ def gather_timeframes(_delta: float, _frame: TimeFrameLiteral) -> float:
"minute",
"second",
)

if granularity == "all":
granularity = cast(List[_GRANULARITY], frames)

for frame in frames:
delta = gather_timeframes(delta, frame)

Expand Down
2 changes: 2 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ Indicate a specific time granularity (or multiple):
'an hour and 6 minutes ago'
>>> future.humanize(present, only_distance=True, granularity=["hour", "minute"])
'an hour and 6 minutes'
>>> future.humanize(present, granularity="all")
'in 0 years 0 months 0 weeks 0 days an hour 6 minutes and 0 seconds'

Support for a growing number of locales (see ``locales.py`` for supported languages):

Expand Down
43 changes: 43 additions & 0 deletions tests/test_arrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2032,6 +2032,49 @@ def test_multiple_granularity(self):
== "a minute and 2 seconds ago"
)

def test_all_granularity(self):
assert (
self.now.humanize(granularity="all")
== "in 0 years 0 months 0 weeks 0 days 0 hours 0 minutes and 0 seconds"
MarkKoz marked this conversation as resolved.
Show resolved Hide resolved
) # TODO: this should be "ago"; change this when #997 is merged

later105 = self.now.shift(seconds=10 ** 5)
assert (
self.now.humanize(later105, granularity="all")
== "0 years 0 months 0 weeks a day 3 hours 46 minutes and 40 seconds ago"
)
assert (
later105.humanize(self.now, granularity="all")
== "in 0 years 0 months 0 weeks a day 3 hours 46 minutes and 40 seconds"
)

later108 = self.now.shift(seconds=10 ** 8)
assert (
self.now.humanize(later108, granularity="all")
== "3 years 2 months 0 weeks a day 9 hours 46 minutes and 40 seconds ago"
)
assert (
later108.humanize(self.now, granularity="all")
== "in 3 years 2 months 0 weeks a day 9 hours 46 minutes and 40 seconds"
)
assert (
self.now.humanize(later108, granularity="all", only_distance=True)
== "3 years 2 months 0 weeks a day 9 hours 46 minutes and 40 seconds"
)

later_two_months = self.now.shift(months=2)
assert (
self.now.humanize(later_two_months, granularity="all")
== "in 0 years 2 months 0 weeks 0 days 0 hours 0 minutes and 0 seconds"
) # TODO: this should be "ago"; change this when #997 is merged
assert (
later_two_months.humanize(self.now, granularity="all")
== "in 0 years 2 months 0 weeks 0 days 0 hours 0 minutes and 0 seconds"
)

with pytest.raises(ValueError):
self.now.humanize(later108, granularity=["all", "year"])

def test_seconds(self):

later = self.now.shift(seconds=10)
Expand Down