Repository: arrow-py/arrow

Issue:
Floats in humanize output for languages overriding _format_timeframe
<!--
Thanks for taking the time to submit this bug report.

Please provide us with a detailed description of the
bug and a bit of information about your system.
-->

## Issue Description

Doing humanize on languages that override _format_timeframe is spitting out floats instead of integers which is not nice on the eye.

```
arrow.utcnow().shift(weeks=5).humanize(locale="en", granularity="day")
'in 35 days'
arrow.utcnow().shift(weeks=5).humanize(locale="bg", granularity="day")
'напред 35.0 дни'
arrow.utcnow().shift(seconds=55000).humanize(locale="bg", granularity="minute")
'напред 916.6666666666666 минути'
```
<!--
Replace with a description of the bug.

Be sure to include details such as the expected
and actual outcomes. Happy bug reporting 🐞!
-->

## System Info

- 🖥 **OS name and version**: Debian Buster(10)
- 🐍 **Python version**: 3.7.3
- 🏹 **Arrow version**: 0.15.6


Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/arrow-py/arrow/pull/986?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=arrow-py) Report
> Merging [#986](https://codecov.io/gh/arrow-py/arrow/pull/986?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=arrow-py) (a5ca425) into [master](https://codecov.io/gh/arrow-py/arrow/commit/3606a80e93ccf13f1d870707960fed066962171f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=arrow-py) (3606a80) will **not change** coverage.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/arrow-py/arrow/pull/986/graphs/tree.svg?width=650&height=150&src=pr&token=4EkGnFsIGn&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=arrow-py)](https://codecov.io/gh/arrow-py/arrow/pull/986?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=arrow-py)

```diff
@@            Coverage Diff            @@
##            master      #986   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           10        10           
  Lines         2056      2056           
  Branches       330       330           
=========================================
  Hits          2056      2056           
```


| [Impacted Files](https://codecov.io/gh/arrow-py/arrow/pull/986?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=arrow-py) | Coverage Δ | |
|---|---|---|
| [arrow/locales.py](https://codecov.io/gh/arrow-py/arrow/pull/986/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=arrow-py#diff-YXJyb3cvbG9jYWxlcy5weQ==) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/arrow-py/arrow/pull/986?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=arrow-py).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=arrow-py)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/arrow-py/arrow/pull/986?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=arrow-py). Last update [3606a80...a5ca425](https://codecov.io/gh/arrow-py/arrow/pull/986?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=arrow-py). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=arrow-py).


Patch:
diff --git a/arrow/locales.py b/arrow/locales.py
index d445f2e..7ad396e 100644
--- a/arrow/locales.py
+++ b/arrow/locales.py
@@ -147,7 +147,7 @@ class Locale:
         :param only_distance: return only distance eg: "11 seconds" without "in" or "ago" keywords
         """
 
-        humanized = self._format_timeframe(timeframe, delta)
+        humanized = self._format_timeframe(timeframe, trunc(delta))
         if not only_distance:
             humanized = self._format_relative(humanized, timeframe, delta)
 
@@ -165,7 +165,8 @@ class Locale:
         """
 
         parts = [
-            self._format_timeframe(timeframe, delta) for timeframe, delta in timeframes
+            self._format_timeframe(timeframe, trunc(delta))
+            for timeframe, delta in timeframes
         ]
         if self.and_word:
             parts.insert(-1, self.and_word)
@@ -3318,7 +3319,7 @@ class HebrewLocale(Locale):
         else:
             key = timeframe
 
-        return self.timeframes[key].format(trunc(abs(delta)))
+        return self.timeframes[key].format(abs(delta))
 
     def describe_multi(
         self,
@@ -3334,7 +3335,7 @@ class HebrewLocale(Locale):
 
         humanized = ""
         for index, (timeframe, delta) in enumerate(timeframes):
-            last_humanized = self._format_timeframe(timeframe, delta)
+            last_humanized = self._format_timeframe(timeframe, trunc(delta))
             if index == 0:
                 humanized = last_humanized
             elif index == len(timeframes) - 1:  # Must have at least 2 items


Test patch:
diff --git a/tests/test_arrow.py b/tests/test_arrow.py
index 2dab6ba..ba25127 100644
--- a/tests/test_arrow.py
+++ b/tests/test_arrow.py
@@ -2266,6 +2266,25 @@ class TestArrowHumanize:
         with pytest.raises(ValueError):
             arw.humanize(later, granularity="week")
 
+    # Bulgarian is an example of a language that overrides _format_timeframe
+    # Applicabale to all locales. Note: Contributors need to make sure
+    # that if they override describe or describe_mutli, that delta
+    # is truncated on call
+
+    def test_no_floats(self):
+        arw = arrow.Arrow(2013, 1, 1, 0, 0, 0)
+        later = arw.shift(seconds=55000)
+        humanize_string = arw.humanize(later, locale="bg", granularity="minute")
+        assert humanize_string == "916 минути назад"
+
+    def test_no_floats_multi_gran(self):
+        arw = arrow.Arrow(2013, 1, 1, 0, 0, 0)
+        later = arw.shift(seconds=55000)
+        humanize_string = arw.humanize(
+            later, locale="bg", granularity=["second", "minute"]
+        )
+        assert humanize_string == "916 минути 40 няколко секунди назад"
+
 
 @pytest.mark.usefixtures("time_2013_01_01")
 class TestArrowHumanizeTestsWithLocale: