12944qwerty

human_timedelta

Feb 18th, 2022
1,228
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.48 KB | None | 0 0
  1. # from github/Rapptz
  2.  
  3.  
  4. import datetime
  5. from dateutil.relativedelta import relativedelta
  6.  
  7.  
  8. class Plural:
  9.     def __init__(self, value):
  10.         self.value = value
  11.  
  12.     def __format__(self, format_spec):
  13.         v = self.value
  14.         singular, sep, plural = format_spec.partition('|')
  15.         plural = plural or f'{singular}s'
  16.         if abs(v) != 1:
  17.             return f'{v} {plural}'
  18.         return f'{v} {singular}'
  19.  
  20.  
  21. def human_join(seq, delim=', ', final='or'):
  22.     size = len(seq)
  23.     if size == 0:
  24.         return ''
  25.  
  26.     if size == 1:
  27.         return seq[0]
  28.  
  29.     if size == 2:
  30.         return f'{seq[0]} {final} {seq[1]}'
  31.  
  32.     return delim.join(seq[:-1]) + f' {final} {seq[-1]}'
  33.  
  34.  
  35. def human_timedelta(dt, *, source=None, accuracy=3, brief=False, suffix=True):
  36.     now = source or datetime.datetime.utcnow()
  37.     # Microsecond free zone
  38.     now = now.replace(microsecond=0)
  39.     dt = dt.replace(microsecond=0)
  40.     # This implementation uses relativedelta instead of the much more obvious
  41.     # divmod approach with seconds because the seconds approach is not entirely
  42.     # accurate once you go over 1 week in terms of accuracy since you have to
  43.     # hardcode a month as 30 or 31 days.
  44.     # A query like "11 months" can be interpreted as "!1 months and 6 days"
  45.     if dt > now:
  46.         delta = relativedelta(dt, now)
  47.         suffix = ''
  48.     else:
  49.         delta = relativedelta(now, dt)
  50.         suffix = ' ago' if suffix else ''
  51.  
  52.     attrs = [
  53.         ('year', 'y'),
  54.         ('month', 'mo'),
  55.         ('day', 'd'),
  56.         ('hour', 'h'),
  57.         ('minute', 'm'),
  58.         ('second', 's'),
  59.     ]
  60.  
  61.     output = []
  62.     for attr, brief_attr in attrs:
  63.         elem = getattr(delta, attr + 's')
  64.         if not elem:
  65.             continue
  66.  
  67.         if attr == 'day':
  68.             weeks = delta.weeks
  69.             if weeks:
  70.                 elem -= weeks * 7
  71.                 if not brief:
  72.                     output.append(format(Plural(weeks), 'week'))
  73.                 else:
  74.                     output.append(f'{weeks}w')
  75.  
  76.         if elem <= 0:
  77.             continue
  78.  
  79.         if brief:
  80.             output.append(f'{elem}{brief_attr}')
  81.         else:
  82.             output.append(format(Plural(elem), attr))
  83.  
  84.     if accuracy is not None:
  85.         output = output[:accuracy]
  86.  
  87.     if len(output) == 0:
  88.         return 'now'
  89.     else:
  90.         if not brief:
  91.             return human_join(output, final='and') + suffix
  92.         else:
  93.             return ' '.join(output) + suffix
Advertisement
Add Comment
Please, Sign In to add comment