Skip to content
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 @@ -1129,7 +1130,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 @@ -1227,7 +1229,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 @@ -1290,6 +1292,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/guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,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 @@ -1919,6 +1919,49 @@ def test_multiple_granularity(self):
== "a minute and 2 seconds ago"
)

def test_all_granularity(self):
assert (
self.now.humanize(self.now, granularity="all")
== "in 0 years 0 quarters 0 months 0 weeks 0 days 0 hours 0 minutes and 0 seconds"
)

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

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

later_two_months = self.arrow.shift(days=61)
assert (
self.arrow.humanize(later_two_months, granularity="all")
== "0 years 0 quarters 2 months 0 weeks 0 days 0 hours 0 minutes and 0 seconds ago"
)
assert (
later_two_months.humanize(self.arrow, granularity="all")
== "in 0 years 0 quarters 2 months 0 weeks 0 days 0 hours 0 minutes and 0 seconds"
)

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

def test_seconds(self):
later = self.now.shift(seconds=10)

Expand Down