diff options
Diffstat (limited to 'pendulum/formatting/difference_formatter.py')
-rw-r--r-- | pendulum/formatting/difference_formatter.py | 299 |
1 files changed, 146 insertions, 153 deletions
diff --git a/pendulum/formatting/difference_formatter.py b/pendulum/formatting/difference_formatter.py index 3243089..dad219d 100644 --- a/pendulum/formatting/difference_formatter.py +++ b/pendulum/formatting/difference_formatter.py @@ -1,153 +1,146 @@ -import typing
-
-import pendulum
-
-from pendulum.utils._compat import decode
-
-from ..locales.locale import Locale
-
-
-class DifferenceFormatter(object):
- """
- Handles formatting differences in text.
- """
-
- def __init__(self, locale="en"):
- self._locale = Locale.load(locale)
-
- def format(
- self, diff, is_now=True, absolute=False, locale=None
- ): # type: (pendulum.Period, bool, bool, typing.Optional[str]) -> str
- """
- Formats a difference.
-
- :param diff: The difference to format
- :type diff: pendulum.period.Period
-
- :param is_now: Whether the difference includes now
- :type is_now: bool
-
- :param absolute: Whether it's an absolute difference or not
- :type absolute: bool
-
- :param locale: The locale to use
- :type locale: str or None
-
- :rtype: str
- """
- if locale is None:
- locale = self._locale
- else:
- locale = Locale.load(locale)
-
- count = diff.remaining_seconds
-
- if diff.years > 0:
- unit = "year"
- count = diff.years
-
- if diff.months > 6:
- count += 1
- elif diff.months == 11 and (diff.weeks * 7 + diff.remaining_days) > 15:
- unit = "year"
- count = 1
- elif diff.months > 0:
- unit = "month"
- count = diff.months
-
- if (diff.weeks * 7 + diff.remaining_days) >= 27:
- count += 1
- elif diff.weeks > 0:
- unit = "week"
- count = diff.weeks
-
- if diff.remaining_days > 3:
- count += 1
- elif diff.remaining_days > 0:
- unit = "day"
- count = diff.remaining_days
-
- if diff.hours >= 22:
- count += 1
- elif diff.hours > 0:
- unit = "hour"
- count = diff.hours
- elif diff.minutes > 0:
- unit = "minute"
- count = diff.minutes
- elif 10 < diff.remaining_seconds <= 59:
- unit = "second"
- count = diff.remaining_seconds
- else:
- # We check if the "a few seconds" unit exists
- time = locale.get("custom.units.few_second")
- if time is not None:
- if absolute:
- return time
-
- key = "custom"
- is_future = diff.invert
- if is_now:
- if is_future:
- key += ".from_now"
- else:
- key += ".ago"
- else:
- if is_future:
- key += ".after"
- else:
- key += ".before"
-
- return locale.get(key).format(time)
- else:
- unit = "second"
- count = diff.remaining_seconds
-
- if count == 0:
- count = 1
-
- if absolute:
- key = "translations.units.{}".format(unit)
- else:
- is_future = diff.invert
-
- if is_now:
- # Relative to now, so we can use
- # the CLDR data
- key = "translations.relative.{}".format(unit)
-
- if is_future:
- key += ".future"
- else:
- key += ".past"
- else:
- # Absolute comparison
- # So we have to use the custom locale data
-
- # Checking for special pluralization rules
- key = "custom.units_relative"
- if is_future:
- key += ".{}.future".format(unit)
- else:
- key += ".{}.past".format(unit)
-
- trans = locale.get(key)
- if not trans:
- # No special rule
- time = locale.get(
- "translations.units.{}.{}".format(unit, locale.plural(count))
- ).format(count)
- else:
- time = trans[locale.plural(count)].format(count)
-
- key = "custom"
- if is_future:
- key += ".after"
- else:
- key += ".before"
-
- return locale.get(key).format(decode(time))
-
- key += ".{}".format(locale.plural(count))
-
- return decode(locale.get(key).format(count))
+from __future__ import annotations + +import typing as t + +from pendulum.locales.locale import Locale + +if t.TYPE_CHECKING: + from pendulum import Duration + + +class DifferenceFormatter: + """ + Handles formatting differences in text. + """ + + def __init__(self, locale: str = "en") -> None: + self._locale = Locale.load(locale) + + def format( + self, + diff: Duration, + is_now: bool = True, + absolute: bool = False, + locale: str | Locale | None = None, + ) -> str: + """ + Formats a difference. + + :param diff: The difference to format + :param is_now: Whether the difference includes now + :param absolute: Whether it's an absolute difference or not + :param locale: The locale to use + """ + if locale is None: + locale = self._locale + else: + locale = Locale.load(locale) + + if diff.years > 0: + unit = "year" + count = diff.years + + if diff.months > 6: + count += 1 + elif diff.months == 11 and (diff.weeks * 7 + diff.remaining_days) > 15: + unit = "year" + count = 1 + elif diff.months > 0: + unit = "month" + count = diff.months + + if (diff.weeks * 7 + diff.remaining_days) >= 27: + count += 1 + elif diff.weeks > 0: + unit = "week" + count = diff.weeks + + if diff.remaining_days > 3: + count += 1 + elif diff.remaining_days > 0: + unit = "day" + count = diff.remaining_days + + if diff.hours >= 22: + count += 1 + elif diff.hours > 0: + unit = "hour" + count = diff.hours + elif diff.minutes > 0: + unit = "minute" + count = diff.minutes + elif 10 < diff.remaining_seconds <= 59: + unit = "second" + count = diff.remaining_seconds + else: + # We check if the "a few seconds" unit exists + time = locale.get("custom.units.few_second") + if time is not None: + if absolute: + return t.cast(str, time) + + key = "custom" + is_future = diff.invert + if is_now: + if is_future: + key += ".from_now" + else: + key += ".ago" + else: + if is_future: + key += ".after" + else: + key += ".before" + + return t.cast(str, locale.get(key).format(time)) + else: + unit = "second" + count = diff.remaining_seconds + + if count == 0: + count = 1 + + if absolute: + key = f"translations.units.{unit}" + else: + is_future = diff.invert + + if is_now: + # Relative to now, so we can use + # the CLDR data + key = f"translations.relative.{unit}" + + if is_future: + key += ".future" + else: + key += ".past" + else: + # Absolute comparison + # So we have to use the custom locale data + + # Checking for special pluralization rules + key = "custom.units_relative" + if is_future: + key += f".{unit}.future" + else: + key += f".{unit}.past" + + trans = locale.get(key) + if not trans: + # No special rule + key = f"translations.units.{unit}.{locale.plural(count)}" + time = locale.get(key).format(count) + else: + time = trans[locale.plural(count)].format(count) + + key = "custom" + if is_future: + key += ".after" + else: + key += ".before" + + return t.cast(str, locale.get(key).format(time)) + + key += f".{locale.plural(count)}" + + return t.cast(str, locale.get(key).format(count)) |