|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | + |
| 3 | +from ..translator import Translator |
| 4 | + |
| 5 | + |
| 6 | +class DifferenceFormatter(object): |
| 7 | + """ |
| 8 | + Handles formatting differences in text. |
| 9 | + """ |
| 10 | + |
| 11 | + THRESHOLDS = ( |
| 12 | + ('remaining_seconds', 'second', 59), |
| 13 | + ('minutes', 'minute', 59), |
| 14 | + ('hours', 'hour', 23), |
| 15 | + ('remaining_days', 'day', 6), |
| 16 | + ('weeks', 'week', 3), |
| 17 | + ('months', 'month', 11), |
| 18 | + ('years', 'year', None), |
| 19 | + ) |
| 20 | + |
| 21 | + def __init__(self, translator=Translator()): |
| 22 | + self._translator = translator |
| 23 | + |
| 24 | + def diff_for_humans(self, date, other=None, absolute=False, locale=None): |
| 25 | + """ |
| 26 | + Get the difference in a human readable format. |
| 27 | +
|
| 28 | + :param date: The datetime to start with. |
| 29 | + :type date: pendulum.Date or pendulum.Pendulum |
| 30 | +
|
| 31 | + :param other: The datetime to compare against (defaults to now). |
| 32 | + :type other: pendulum.Date or pendulum.Pendulum or None |
| 33 | +
|
| 34 | + :param absolute: Removes time difference modifiers ago, after, etc |
| 35 | + :type absolute: bool |
| 36 | +
|
| 37 | + :param locale: The locale to use |
| 38 | + :type locale: str or None |
| 39 | +
|
| 40 | + :rtype: str |
| 41 | + """ |
| 42 | + is_now = other is None |
| 43 | + |
| 44 | + if is_now: |
| 45 | + if hasattr(date, 'now'): |
| 46 | + other = date.now(date.timezone) |
| 47 | + else: |
| 48 | + other = date.today() |
| 49 | + |
| 50 | + diff = date.diff(other) |
| 51 | + |
| 52 | + count = diff.remaining_seconds |
| 53 | + unit = 'second' |
| 54 | + |
| 55 | + if diff.years > 0: |
| 56 | + unit = 'year' |
| 57 | + count = diff.years |
| 58 | + |
| 59 | + if diff.months > 6: |
| 60 | + count += 1 |
| 61 | + elif diff.months == 11 and (diff.weeks * 7 + diff.remaining_days) > 15: |
| 62 | + unit = 'year' |
| 63 | + count = 1 |
| 64 | + elif diff.months > 0: |
| 65 | + unit = 'month' |
| 66 | + count = diff.months |
| 67 | + |
| 68 | + if (diff.weeks * 7 + diff.remaining_days) > 28: |
| 69 | + count += 1 |
| 70 | + elif diff.weeks > 0: |
| 71 | + unit = 'week' |
| 72 | + count = diff.weeks |
| 73 | + |
| 74 | + if diff.remaining_days > 3: |
| 75 | + count += 1 |
| 76 | + elif diff.days > 0: |
| 77 | + unit = 'day' |
| 78 | + count = diff.days |
| 79 | + elif diff.hours > 0: |
| 80 | + unit = 'hour' |
| 81 | + count = diff.hours |
| 82 | + elif diff.minutes > 0: |
| 83 | + unit = 'minute' |
| 84 | + count = diff.minutes |
| 85 | + |
| 86 | + if count == 0: |
| 87 | + count = 1 |
| 88 | + |
| 89 | + time = self._translator.transchoice(unit, count, {'count': count}, locale=locale) |
| 90 | + |
| 91 | + if absolute: |
| 92 | + return time |
| 93 | + |
| 94 | + is_future = diff.invert |
| 95 | + |
| 96 | + if is_now: |
| 97 | + trans_id = 'from_now' if is_future else 'ago' |
| 98 | + else: |
| 99 | + trans_id = 'after' if is_future else 'before' |
| 100 | + |
| 101 | + # Some langs have special pluralization for past and future tense |
| 102 | + try_key_exists = '%s_%s' % (unit, trans_id) |
| 103 | + if try_key_exists != self._translator.transchoice(try_key_exists, count, locale=locale): |
| 104 | + time = self._translator.transchoice(try_key_exists, count, {'count': count}, locale=locale) |
| 105 | + |
| 106 | + return self._translator.trans(trans_id, {'time': time}, locale=locale) |
0 commit comments