76 lines
2.5 KiB
Python
76 lines
2.5 KiB
Python
from datetime import datetime, timedelta
|
|
|
|
units = ("year", "day", "hour", "minute", "second", "millisecond", "microsecond")
|
|
|
|
|
|
def get_delta_from_subject(subject):
|
|
subject_type = type(subject)
|
|
if subject_type is timedelta:
|
|
delta = subject
|
|
else:
|
|
if subject_type is int or subject_type is float:
|
|
dt = datetime.fromtimestamp(float(subject))
|
|
else:
|
|
# assume subject is a datetime object and strip timezone data.
|
|
dt = subject.replace(tzinfo=None)
|
|
# finally, create a timedelta from datetime.
|
|
delta = datetime.now() - dt
|
|
return delta
|
|
|
|
|
|
def delta2dict(delta):
|
|
"""Accepts a delta, returns a dictionary of units"""
|
|
delta = abs(delta)
|
|
return {
|
|
"year": int(delta.days / 365),
|
|
"day": int(delta.days % 365),
|
|
"hour": int(delta.seconds / 3600),
|
|
"minute": int(delta.seconds / 60) % 60,
|
|
"second": delta.seconds % 60,
|
|
"millisecond": delta.microseconds / 1000,
|
|
"microsecond": delta.microseconds % 1000,
|
|
}
|
|
|
|
|
|
def human(
|
|
subject, precision=2, past_tense="{} ago", future_tense="in {}", abbreviate=False
|
|
):
|
|
"""
|
|
Accept a subject, return a human readable timedelta string.
|
|
|
|
:param subject: a datetime, timedelta, or timestamp (integer / float) object
|
|
:param precision: the desired amount of unit precision (default: 2)
|
|
:param past_tense: the format string used for a past timedelta (default: '{} ago')
|
|
:param future_tense: the format string used for a future timedelta (default: 'in {}')
|
|
:param abbreviate: boolean to abbreviate units (default: False)
|
|
|
|
:returns: Human readable timedelta string (Str)
|
|
"""
|
|
delta = get_delta_from_subject(subject)
|
|
the_tense = future_tense if delta < timedelta(0) else past_tense
|
|
|
|
d = delta2dict(delta)
|
|
|
|
hlist = []
|
|
count = 0
|
|
|
|
# start building up the output in the hlist.
|
|
for unit in units:
|
|
if count >= precision:
|
|
break # met precision
|
|
if d[unit] == 0:
|
|
continue # skip 0's
|
|
if abbreviate:
|
|
if unit == "millisecond":
|
|
abr = "ms"
|
|
elif unit == "microsecond":
|
|
abr = "um"
|
|
else:
|
|
abr = unit[0]
|
|
hlist.append("{}{}".format(d[unit], abr))
|
|
else:
|
|
s = "" if d[unit] == 1 else "s" # handle plurals
|
|
hlist.append("{} {}{}".format(d[unit], unit, s))
|
|
count += 1
|
|
|
|
return the_tense.format(", ".join(hlist))
|