def e161(number, alphabet=PHONE_E161_ALPHABET): ''' Printable a 26 Latin letters (A to Z) phone number to the 12-key telephone keypad number. :param number: string :param alphabet: dict >>> e161('0800-PIZZA123') u'080074992123' >>> e161('0800^PIZZA123') Traceback (most recent call last): ... ValueError: Character "^" (0x5e) is not in the E.161 alphabet ''' digits = [] for char in strip(number, '+-. ()').lower(): length = len(digits) for group, digit in alphabet.iteritems(): if char in group: digits.append(digit) break if len(digits) == length: raise ValueError( _('Character "%s" (0x%02x) is not in the E.161 alphabet') % (char, ord(char))) return u''.join(digits)
def e161(number, alphabet=PHONE_E161_ALPHABET): ''' Printable a 26 Latin letters (A to Z) phone number to the 12-key telephone keypad number. :param number: string :param alphabet: dict >>> print(e161('0800-PIZZA123')) 080074992123 >>> e161('0800^PIZZA123') Traceback (most recent call last): ... ValueError: Character "^" (0x5e) is not in the E.161 alphabet ''' digits = [] for char in strip(number, '+-. ()').lower(): length = len(digits) for group, digit in alphabet.items(): if char in group: digits.append(digit) break if len(digits) == length: raise ValueError( _('Character "%s" (0x%02x) is not in the E.161 alphabet') % (char, ord(char)) ) return u''.join(digits)
def day(t, now=None, format="%B %d"): """ Date delta compared to ``t``. You can override ``now`` to specify what date to compare to. You can override the date format by supplying a ``format`` parameter. :param t: timestamp, :class:`datetime.date` or :class:`datetime.datetime` object :param now: default ``None``, optionally a :class:`datetime.datetime` object :param format: default ``'%B %d'`` >>> import time >>> day(time.time()) 'today' >>> day(time.time() - 86400) 'yesterday' >>> day(time.time() - 604800) 'last week' >>> day(time.time() + 86400) 'tomorrow' >>> day(time.time() + 604800) 'next week' """ t1 = _to_date(t) t2 = _to_date(now or datetime.datetime.now()) diff = t1 - t2 secs = _total_seconds(diff) days = abs(diff.days) if days == 0: return _("today") elif days == 1: if secs < 0: return _("yesterday") else: return _("tomorrow") elif days == 7: if secs < 0: return _("last week") else: return _("next week") else: return t1.strftime(format)
def day(t, now=None, format='%B %d'): ''' Date delta compared to ``t``. You can override ``now`` to specify what date to compare to. You can override the date format by supplying a ``format`` parameter. :param t: timestamp, :class:`datetime.date` or :class:`datetime.datetime` object :param now: default ``None``, optionally a :class:`datetime.datetime` object :param format: default ``'%B %d'`` >>> import time >>> print(day(time.time())) today >>> print(day(time.time() - 86400)) yesterday >>> print(day(time.time() - 604800)) last week >>> print(day(time.time() + 86400)) tomorrow >>> print(day(time.time() + 604800)) next week ''' t1 = _to_date(t) t2 = _to_date(now or datetime.datetime.now()) diff = t1 - t2 secs = _total_seconds(diff) days = abs(diff.days) if days == 0: return _('today') elif days == 1: if secs < 0: return _('yesterday') else: return _('tomorrow') elif days == 7: if secs < 0: return _('last week') else: return _('next week') else: return t1.strftime(format)
def meid(number, separator=u' '): ''' Printable Mobile Equipment Identifier (MEID) number. >>> meid(123456789012345678) u'1B 69B4BA 630F34 6' >>> meid('1B69B4BA630F34') u'1B 69B4BA 630F34 6' ''' if isinstance(number, six.string_types): number = re.sub(r'[\s-]', '', number) try: number = '%014X' % int(number, 16) except ValueError: if len(number) < 18 and number.isdigit(): return meid('%014X' % int(number), separator) else: raise ValueError(_('Invalid MEID, size mismatch')) else: if len(number) not in (14, 15): raise ValueError(_('Invalid MEID, size mismatch')) elif isinstance(number, six.integer_types): if number > 0xfffffffffffffff: raise ValueError(_('Invalid MEID, size mismatch')) return meid(('%014X' % number)[:14], separator) else: raise TypeError(_('Invalid MEID, input type invalid')) number = number.upper() region = number[:2] manufacturer = number[2:8] serial_number = number[8:14] check_digit = number[14:] if check_digit == '': check_digit = luhn_calc(number, chars='0123456789ABCDEF') groups = (region, manufacturer, serial_number, check_digit) return separator.join(list(filter(None, groups)))
def meid(number, separator=u' '): ''' Printable Mobile Equipment Identifier (MEID) number. >>> print(meid(123456789012345678)) 1B 69B4BA 630F34 6 >>> print(meid('1B69B4BA630F34')) 1B 69B4BA 630F34 6 ''' if isinstance(number, six.string_types): number = re.sub(r'[\s-]', '', number) try: number = '%014X' % int(number, 16) except ValueError: if len(number) < 18 and number.isdigit(): return meid('%014X' % int(number), separator) else: raise ValueError(_('Invalid MEID, size mismatch')) else: if len(number) not in (14, 15): raise ValueError(_('Invalid MEID, size mismatch')) elif isinstance(number, six.integer_types): if number > 0xfffffffffffffff: raise ValueError(_('Invalid MEID, size mismatch')) return meid(('%014X' % number)[:14], separator) else: raise TypeError(_('Invalid MEID, input type invalid')) number = number.upper() region = number[:2] manufacturer = number[2:8] serial_number = number[8:14] check_digit = number[14:] if check_digit == '': check_digit = luhn_calc(number, chars='0123456789ABCDEF') groups = (region, manufacturer, serial_number, check_digit) return separator.join(list(filter(None, groups)))
def e123(number, areasize=3, groupsize=4, national=False): ''' Printable E.123 (Notation for national and international telephone numbers from ITU) numbers. :param number: string :param areasize: int :param groupsize: int :param national: bool >>> print(e123(155542315678)) +1 555 4231 5678 >>> print(e123('+31654231567', areasize=1)) +31 6 5423 1567 >>> print(e123('+3114020', areasize=2)) +31 14 020 >>> print(e123('+312054231567', areasize=2, national=True)) (020) 5423 1567 ''' if isinstance(number, six.integer_types): return e123('+%s' % number, areasize, groupsize) elif isinstance(number, six.string_types): number = strip(number, '-. ()') if number.startswith('+'): number = number[1:] if not number.isdigit(): raise ValueError(_('Invalid telephone number')) groups = [] prefix = '' remain = number if national: for x in six.moves.xrange(3, 0, -1): if number[:x] in PHONE_PREFIX: groups.append('(0%s)' % number[x:x + areasize]) remain = number[x + areasize:] break else: prefix = '+' for x in six.moves.xrange(3, 0, -1): if number[:x] in PHONE_PREFIX: groups.append(number[:x]) groups.append(number[x:x + areasize]) remain = number[x + areasize:] break for x in six.moves.xrange(0, len(remain) + 1, groupsize): groups.append(remain[x:x + groupsize]) return '%s%s' % (prefix, ' '.join(list(filter(None, groups))))
def throughput(sample, window=1, format='decimal'): ''' Return the throughput in (intelli)bytes per second. :param sample: number of samples sent :param window: default 1, sample window in seconds or :class:`datetime.timedelta` object :param format: default 'decimal', see :func:`natural.size.filesize` >>> throughput(123456, 42) u'2.87 kB/s' ''' if isinstance(window, datetime.timedelta): window = float(window.days * 86400 + window.seconds) elif isinstance(window, basestring): window = float(window) per_second = sample / float(window) return _('%s/s') % (filesize(per_second, format=format),)
def throughput(sample, window=1, format='decimal'): ''' Return the throughput in (intelli)bytes per second. :param sample: number of samples sent :param window: default 1, sample window in seconds or :class:`datetime.timedelta` object :param format: default 'decimal', see :func:`natural.size.filesize` >>> throughput(123456, 42) u'2.87 kB/s' ''' if isinstance(window, datetime.timedelta): window = float(window.days * 86400 + window.seconds) elif isinstance(window, basestring): window = float(window) per_second = sample / float(window) return _('%s/s') % (filesize(per_second, format=format), )
def _to_datetime(t): ''' Internal function that tries whatever to convert ``t`` into a :class:`datetime.datetime` object. >>> _to_datetime('2013-12-11') datetime.datetime(2013, 12, 11, 0, 0) >>> _to_datetime('Wed, 11 Dec 2013') datetime.datetime(2013, 12, 11, 0, 0) >>> _to_datetime('Wed, 11 Dec 13') datetime.datetime(2013, 12, 11, 0, 0) >>> _to_datetime('2012-06-13T15:24:17') datetime.datetime(2012, 6, 13, 15, 24, 17) ''' if isinstance(t, six.integer_types + (float, )): return datetime.datetime.fromtimestamp(t).replace(microsecond=0) elif isinstance(t, six.string_types): for date_format in ALL_DATETIME_FORMATS: try: d = datetime.datetime.strptime(t, date_format) return d.replace(microsecond=0) except ValueError: pass raise ValueError(_('Format "%s" not supported') % t) elif isinstance(t, datetime.datetime): return t.replace(microsecond=0) elif isinstance(t, datetime.date): d = datetime.datetime.combine(t, datetime.time(0, 0)) return d.replace(microsecond=0) else: raise TypeError
def _to_datetime(t): """ Internal function that tries whatever to convert ``t`` into a :class:`datetime.datetime` object. >>> _to_datetime('2013-12-11') datetime.datetime(2013, 12, 11, 0, 0) >>> _to_datetime('Wed, 11 Dec 2013') datetime.datetime(2013, 12, 11, 0, 0) >>> _to_datetime('Wed, 11 Dec 13') datetime.datetime(2013, 12, 11, 0, 0) >>> _to_datetime('2012-06-13T15:24:17') datetime.datetime(2012, 6, 13, 15, 24, 17) """ if isinstance(t, six.integer_types + (float,)): return datetime.datetime.fromtimestamp(t).replace(microsecond=0) elif isinstance(t, six.string_types): for date_format in ALL_DATETIME_FORMATS: try: d = datetime.datetime.strptime(t, date_format) return d.replace(microsecond=0) except ValueError: pass raise ValueError(_('Format "%s" not supported') % t) elif isinstance(t, datetime.datetime): return t.replace(microsecond=0) elif isinstance(t, datetime.date): d = datetime.datetime.combine(t, datetime.time(0, 0)) return d.replace(microsecond=0) else: raise TypeError
def imei(number): ''' Printable International Mobile Station Equipment Identity (IMEI) numbers. :param number: string, int or long >>> print imei(12345678901234) 12-345678-901234-7 >>> print imei(1234567890123456) 12-345678-901234-56 ''' number = to_decimal(number) length = len(number) if length not in (14, 15, 16): raise ValueError( _('Invaid International Mobile Station Equipment Identity')) if len(number) == 14: # Add Luhn check digit number = luhn_append(number) groups = (number[:2], number[2:8], number[8:14], number[14:]) return u'-'.join(list(filter(None, groups)))
def imei(number): ''' Printable International Mobile Station Equipment Identity (IMEI) numbers. :param number: string or int >>> print(imei(12345678901234)) 12-345678-901234-7 >>> print(imei(1234567890123456)) 12-345678-901234-56 ''' number = to_decimal(number) length = len(number) if length not in (14, 15, 16): raise ValueError( _('Invaid International Mobile Station Equipment Identity') ) if len(number) == 14: # Add Luhn check digit number = luhn_append(number) groups = (number[:2], number[2:8], number[8:14], number[14:]) return u'-'.join(list(filter(None, groups)))
def duration(t, now=None, precision=1, pad=', ', words=None, justnow=datetime.timedelta(seconds=10)): ''' Time delta compared to ``t``. You can override ``now`` to specify what time to compare to. :param t: timestamp, :class:`datetime.date` or :class:`datetime.datetime` object :param now: default ``None``, optionally a :class:`datetime.datetime` object :param precision: default ``1``, number of fragments to return :param words: default ``None``, allow words like "yesterday", if set to ``None`` this will be enabled if ``precision`` is set to ``1`` :param justnow: default ``datetime.timedelta(seconds=10)``, :class:`datetime.timedelta` object passed to :func:`delta` representing tolerance for considering argument ``t`` as meaning 'just now' >>> import time >>> from datetime import datetime >>> print(duration(time.time() + 1)) just now >>> print(duration(time.time() + 11)) 11 seconds from now >>> print(duration(time.time() - 1)) just now >>> print(duration(time.time() - 11)) 11 seconds ago >>> print(duration(time.time() - 3601)) an hour ago >>> print(duration(time.time() - 7201)) 2 hours ago >>> print(duration(time.time() - 1234567)) 2 weeks ago >>> print(duration(time.time() + 7200, precision=1)) 2 hours from now >>> print(duration(time.time() - 1234567, precision=3)) 2 weeks, 6 hours, 56 minutes ago >>> print(duration(datetime(2014, 9, 8), now=datetime(2014, 9, 9))) yesterday >>> print(duration(datetime(2014, 9, 7, 23), now=datetime(2014, 9, 9))) 1 day ago >>> print(duration(datetime(2014, 9, 10), now=datetime(2014, 9, 9))) tomorrow >>> print(duration(datetime(2014, 9, 11, 1), now=datetime(2014, 9, 9, 23))) 1 day from now ''' if words is None: words = precision == 1 t1 = _to_datetime(t) t2 = _to_datetime(now or datetime.datetime.now()) if t1 < t2: format = _('%s ago') else: format = _('%s from now') result, remains = delta(t1, t2, words=words, justnow=justnow) if result in ( _('just now'), _('yesterday'), _('tomorrow'), _('last week'), _('next week'), ): return result elif precision > 1 and remains: t3 = t2 - datetime.timedelta(seconds=remains) return pad.join([ result, duration(t2, t3, precision - 1, pad, words=False), ]) else: return format % (result,)
Return the localised translation of ``message``, based on the current global domain, language, and locale directory. .. py:function:: _multi(singular, plural, count) Return the localised translation based on ``count``, the ``singular`` version if ``count == 1``, the ``plural`` version otherwise. ''' # natural.bank BBAN_RULES = dict( AD=dict(bban='4!n4!n12!c', name=_('Andorra')), AE=dict(bban='3!n16!n', name=_('United Arab Emirates')), AL=dict(bban='8!n16!c', name=_('Albania')), AT=dict(bban='5!n11!n', name=_('Austria')), AZ=dict(bban='4!a20!c', name=_('Republic of Azerbaijan')), BA=dict(bban='3!n3!n8!n2!n', name=_('Bosnia and Herzegovina')), BE=dict(bban='3!n7!n2!n', name=_('Belgium')), BG=dict(bban='4!a4!n2!n8!c', name=_('Bulgaria')), BH=dict(bban='4!a14!c',
def compress(t, sign=False, pad=""): """ Convert the input to compressed format, works with a :class:`datetime.timedelta` object or a number that represents the number of seconds you want to compress. If you supply a timestamp or a :class:`datetime.datetime` object, it will give the delta relative to the current time. You can enable showing a sign in front of the compressed format with the ``sign`` parameter, the default is not to show signs. Optionally, you can chose to pad the output. If you wish your values to be separated by spaces, set ``pad`` to ``' '``. :param t: seconds or :class:`datetime.timedelta` object :param sign: default ``False`` :param pad: default ``''`` >>> compress(1) '1s' >>> compress(12) '12s' >>> compress(123) '2m3s' >>> compress(1234) '20m34s' >>> compress(12345) '3h25m45s' >>> compress(123456) '1d10h17m36s' """ if isinstance(t, datetime.timedelta): seconds = t.seconds + (t.days * 86400) elif isinstance(t, six.integer_types + (float,)): return compress(datetime.timedelta(seconds=t), sign, pad) else: return compress(datetime.datetime.now() - _to_datetime(t), sign, pad) parts = [] if sign: parts.append("-" if t.days < 0 else "+") weeks, seconds = divmod(seconds, TIME_WEEK) days, seconds = divmod(seconds, TIME_DAY) hours, seconds = divmod(seconds, TIME_HOUR) minutes, seconds = divmod(seconds, TIME_MINUTE) if weeks: parts.append(_("%dw") % (weeks,)) if days: parts.append(_("%dd") % (days,)) if hours: parts.append(_("%dh") % (hours,)) if minutes: parts.append(_("%dm") % (minutes,)) if seconds: parts.append(_("%ds") % (seconds,)) return pad.join(parts)
def duration(t, now=None, precision=1, pad=", ", words=None, justnow=datetime.timedelta(seconds=10)): """ Time delta compared to ``t``. You can override ``now`` to specify what time to compare to. :param t: timestamp, :class:`datetime.date` or :class:`datetime.datetime` object :param now: default ``None``, optionally a :class:`datetime.datetime` object :param precision: default ``1``, number of fragments to return :param words: default ``None``, allow words like "yesterday", if set to ``None`` this will be enabled if ``precision`` is set to ``1`` :param justnow: default ``datetime.timedelta(seconds=10)``, :class:`datetime.timedelta` object passed to :func:`delta` representing tolerance for considering argument ``t`` as meaning 'just now' >>> import time >>> from datetime import datetime >>> duration(time.time() + 1) 'just now' >>> duration(time.time() + 11) '11 seconds from now' >>> duration(time.time() - 1) 'just now' >>> duration(time.time() - 11) '11 seconds ago' >>> duration(time.time() - 3601) 'an hour ago' >>> duration(time.time() - 7201) '2 hours ago' >>> duration(time.time() - 1234567) '2 weeks ago' >>> duration(time.time() + 7200, precision=1) '2 hours from now' >>> duration(time.time() - 1234567, precision=3) '2 weeks, 6 hours, 56 minutes ago' >>> duration(datetime(2014, 9, 8), now=datetime(2014, 9, 9)) 'yesterday' >>> duration(datetime(2014, 9, 7, 23), now=datetime(2014, 9, 9)) '1 day ago' >>> duration(datetime(2014, 9, 10), now=datetime(2014, 9, 9)) 'tomorrow' >>> duration(datetime(2014, 9, 11, 1), now=datetime(2014, 9, 9, 23)) '1 day from now' """ if words is None: words = precision == 1 t1 = _to_datetime(t) t2 = _to_datetime(now or datetime.datetime.now()) if t1 < t2: format = _("%s ago") else: format = _("%s from now") result, remains = delta(t1, t2, words=words, justnow=justnow) if result in (_("just now"), _("yesterday"), _("tomorrow"), _("last week"), _("next week")): return result elif precision > 1 and remains: t3 = t2 - datetime.timedelta(seconds=remains) return pad.join([result, duration(t2, t3, precision - 1, pad, words=False)]) else: return format % (result,)
def delta(t1, t2, words=True, justnow=datetime.timedelta(seconds=10)): """ Calculates the estimated delta between two time objects in human-readable format. Used internally by the :func:`day` and :func:`duration` functions. :param t1: timestamp, :class:`datetime.date` or :class:`datetime.datetime` object :param t2: timestamp, :class:`datetime.date` or :class:`datetime.datetime` object :param words: default ``True``, allow words like "yesterday", "tomorrow" and "just now" :param justnow: default ``datetime.timedelta(seconds=10)``, :class:`datetime.timedelta` object representing tolerance for considering a delta as meaning 'just now' >>> delta(_to_datetime('2012-06-13T15:24:17'), \ _to_datetime('2013-12-11T12:34:56')) ('77 weeks', -594639) """ t1 = _to_datetime(t1) t2 = _to_datetime(t2) diff = t1 - t2 date_diff = t1.date() - t2.date() # The datetime module includes milliseconds with float precision. Floats # will give unexpected results here, so we round the value here total = math.ceil(_total_seconds(diff)) total_abs = abs(total) if total_abs < TIME_DAY: if abs(diff) < justnow and words: return (_("just now"), 0) elif total_abs < TIME_MINUTE: seconds = total_abs return (_multi(_("%d second"), _("%d seconds"), seconds) % (seconds,), 0) elif total_abs < TIME_MINUTE * 2 and words: return (_("a minute"), 0) elif total_abs < TIME_HOUR: minutes, seconds = divmod(total_abs, TIME_MINUTE) if total < 0: seconds *= -1 return (_multi(_("%d minute"), _("%d minutes"), minutes) % (minutes,), seconds) elif total_abs < TIME_HOUR * 2 and words: return (_("an hour"), 0) else: hours, seconds = divmod(total_abs, TIME_HOUR) if total < 0: seconds *= -1 return (_multi(_("%d hour"), _("%d hours"), hours) % (hours,), seconds) elif date_diff.days == 1 and words: return (_("tomorrow"), 0) elif date_diff.days == -1 and words: return (_("yesterday"), 0) elif total_abs < TIME_WEEK: days, seconds = divmod(total_abs, TIME_DAY) if total < 0: seconds *= -1 return (_multi(_("%d day"), _("%d days"), days) % (days,), seconds) elif abs(diff.days) == TIME_WEEK and words: if total > 0: return (_("next week"), diff.seconds) else: return (_("last week"), diff.seconds) # FIXME # # The biggest reliable unit we can supply to the user is a week (for now?), # because we can not safely determine the amount of days in the covered # month/year span. else: weeks, seconds = divmod(total_abs, TIME_WEEK) if total < 0: seconds *= -1 return (_multi(_("%d week"), _("%d weeks"), weeks) % (weeks,), seconds)
def compress(t, sign=False, pad=''): ''' Convert the input to compressed format, works with a :class:`datetime.timedelta` object or a number that represents the number of seconds you want to compress. If you supply a timestamp or a :class:`datetime.datetime` object, it will give the delta relative to the current time. You can enable showing a sign in front of the compressed format with the ``sign`` parameter, the default is not to show signs. Optionally, you can chose to pad the output. If you wish your values to be separated by spaces, set ``pad`` to ``' '``. :param t: seconds or :class:`datetime.timedelta` object :param sign: default ``False`` :param pad: default ``''`` >>> print(compress(1)) 1s >>> print(compress(12)) 12s >>> print(compress(123)) 2m3s >>> print(compress(1234)) 20m34s >>> print(compress(12345)) 3h25m45s >>> print(compress(123456)) 1d10h17m36s ''' if isinstance(t, datetime.timedelta): seconds = t.seconds + (t.days * 86400) elif isinstance(t, six.integer_types + (float, )): return compress(datetime.timedelta(seconds=t), sign, pad) else: return compress(datetime.datetime.now() - _to_datetime(t), sign, pad) parts = [] if sign: parts.append('-' if t.days < 0 else '+') weeks, seconds = divmod(seconds, TIME_WEEK) days, seconds = divmod(seconds, TIME_DAY) hours, seconds = divmod(seconds, TIME_HOUR) minutes, seconds = divmod(seconds, TIME_MINUTE) if weeks: parts.append(_('%dw') % (weeks,)) if days: parts.append(_('%dd') % (days,)) if hours: parts.append(_('%dh') % (hours,)) if minutes: parts.append(_('%dm') % (minutes,)) if seconds: parts.append(_('%ds') % (seconds,)) return pad.join(parts)
def delta(t1, t2, words=True, justnow=datetime.timedelta(seconds=10)): ''' Calculates the estimated delta between two time objects in human-readable format. Used internally by the :func:`day` and :func:`duration` functions. :param t1: timestamp, :class:`datetime.date` or :class:`datetime.datetime` object :param t2: timestamp, :class:`datetime.date` or :class:`datetime.datetime` object :param words: default ``True``, allow words like "yesterday", "tomorrow" and "just now" :param justnow: default ``datetime.timedelta(seconds=10)``, :class:`datetime.timedelta` object representing tolerance for considering a delta as meaning 'just now' >>> (x,y) = delta(_to_datetime('2012-06-13T15:24:17'), \ _to_datetime('2013-12-11T12:34:56')) >>> print(x) 77 weeks >>> int(y) -594639 ''' t1 = _to_datetime(t1) t2 = _to_datetime(t2) diff = t1 - t2 date_diff = t1.date() - t2.date() # The datetime module includes milliseconds with float precision. Floats # will give unexpected results here, so we round the value here total = math.ceil(_total_seconds(diff)) total_abs = abs(total) if total_abs < TIME_DAY: if abs(diff) < justnow and words: return ( _('just now'), 0, ) elif total_abs < TIME_MINUTE: seconds = total_abs return ( _multi( _('%d second'), _('%d seconds'), seconds ) % (seconds,), 0, ) elif total_abs < TIME_MINUTE * 2 and words: return ( _('a minute'), 0, ) elif total_abs < TIME_HOUR: minutes, seconds = divmod(total_abs, TIME_MINUTE) if total < 0: seconds *= -1 return ( _multi( _('%d minute'), _('%d minutes'), minutes ) % (minutes,), seconds, ) elif total_abs < TIME_HOUR * 2 and words: return ( _('an hour'), 0, ) else: hours, seconds = divmod(total_abs, TIME_HOUR) if total < 0: seconds *= -1 return ( _multi( _('%d hour'), _('%d hours'), hours ) % (hours,), seconds, ) elif date_diff.days == 1 and words: return (_('tomorrow'), 0) elif date_diff.days == -1 and words: return (_('yesterday'), 0) elif total_abs < TIME_WEEK: days, seconds = divmod(total_abs, TIME_DAY) if total < 0: seconds *= -1 return ( _multi( _('%d day'), _('%d days'), days ) % (days,), seconds, ) elif abs(diff.days) == TIME_WEEK and words: if total > 0: return (_('next week'), diff.seconds) else: return (_('last week'), diff.seconds) # FIXME # # The biggest reliable unit we can supply to the user is a week (for now?), # because we can not safely determine the amount of days in the covered # month/year span. else: weeks, seconds = divmod(total_abs, TIME_WEEK) if total < 0: seconds *= -1 return ( _multi( _('%d week'), _('%d weeks'), weeks ) % (weeks,), seconds, )