85 lines
2.5 KiB
Python
85 lines
2.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
import re
|
|
|
|
from datetime import datetime, timedelta
|
|
|
|
|
|
def date_from_iso(date: str) -> datetime:
|
|
return datetime.strptime(date, '%Y-%m-%dT%H:%M:%S.%fZ')
|
|
|
|
|
|
def time_delta(text: str) -> timedelta:
|
|
match = re.match(r'(\d+)(s|m|h|mon|w|y)', text)
|
|
if match:
|
|
num, unit = match.groups()
|
|
num = int(num)
|
|
if unit == 's':
|
|
unit = 'seconds'
|
|
elif unit == 'm':
|
|
unit = 'minutes'
|
|
elif unit == 'h':
|
|
unit = 'hours'
|
|
elif unit == 'd':
|
|
unit = 'days'
|
|
elif unit == 'w':
|
|
unit = 'weeks'
|
|
elif unit == 'mon':
|
|
unit = 'weeks'
|
|
num *= 4
|
|
elif unit == 'y':
|
|
unit = 'weeks'
|
|
num *= 52
|
|
return timedelta(**{unit: num})
|
|
|
|
|
|
def time_since(date: datetime, now: datetime = None):
|
|
"""
|
|
Takes two datetime objects and returns the time between d and now
|
|
as a nicely formatted string, e.g. "10 minutes". If d occurs after now,
|
|
then "0 minutes" is returned.
|
|
|
|
Units used are years, months, weeks, days, hours, and minutes.
|
|
Seconds and microseconds are ignored. Up to two adjacent units will be
|
|
displayed. For example, "2 weeks, 3 days" and "1 year, 3 months" are
|
|
possible outputs, but "2 weeks, 3 hours" and "1 year, 5 days" are not.
|
|
|
|
Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
|
|
"""
|
|
chunks = (
|
|
(60 * 60 * 24 * 365, ('year', 'years')),
|
|
(60 * 60 * 24 * 30, ('month', 'months')),
|
|
(60 * 60 * 24 * 7, ('week', 'weeks')),
|
|
(60 * 60 * 24, ('day', 'days')),
|
|
(60 * 60, ('hour', 'hours')),
|
|
(60, ('minute', 'minutes'))
|
|
)
|
|
|
|
if not now:
|
|
now = datetime.now()
|
|
|
|
# ignore microsecond part of 'd' since we removed it from 'now'
|
|
delta = now - (date - timedelta(0, 0, date.microsecond))
|
|
since = delta.days * 24 * 60 * 60 + delta.seconds
|
|
if since <= 0:
|
|
# d is in the future compared to now, stop processing.
|
|
return u'0 ' + 'minutes'
|
|
|
|
name = None
|
|
count = None
|
|
seconds = None
|
|
|
|
for i, (seconds, name) in enumerate(chunks):
|
|
count = since // seconds
|
|
if count != 0:
|
|
break
|
|
|
|
s = '%(number)d %(type)s' % {'number': count, 'type': name[count != 1]}
|
|
|
|
if i + 1 < len(chunks):
|
|
# Now get the second item
|
|
seconds2, name2 = chunks[i + 1]
|
|
count2 = (since - (seconds * count)) // seconds2
|
|
if count2 != 0:
|
|
s += ', %d %s' % (count2, name2[count2 != 1])
|
|
return s
|