Skip to content

Commit

Permalink
Add an "all" granularity to humanize
Browse files Browse the repository at this point in the history
It's more convenient to pass a simple short string than to pass a list
of 7 strings.

Resolve arrow-py#997
  • Loading branch information
MarkKoz committed Aug 8, 2021
1 parent 2ade710 commit 2506875
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 2 deletions.
10 changes: 8 additions & 2 deletions arrow/arrow.py
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
43 changes: 43 additions & 0 deletions tests/test_arrow.py
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"
) # 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

0 comments on commit 2506875

Please sign in to comment.