ago/ago.py
Chad Birch 217a7fbe61 Refactor get_delta_from_subject() method
Refactors the get_delta_from_subject() method for a few benefits:

* Checks type more idiomatically (using isinstance instead of type)
* Raise a TypeError if passed a type that isn't able to be handled
* Return immediately if passed a timedelta, so the rest of the method
  doesn't need to be inside an else block
2018-10-05 21:32:42 -06:00

85 lines
2.6 KiB
Python

from datetime import datetime, timedelta
units = ("year", "day", "hour", "minute", "second", "millisecond", "microsecond")
def get_delta_from_subject(subject):
"""Convert the subject to a timedelta and return it."""
if isinstance(subject, timedelta):
return subject
if isinstance(subject, datetime):
dt = subject
else:
# if it's not a datetime, assume it's a unix timestamp
try:
subject = float(subject)
except ValueError:
# some unknown type that couldn't be converted to a float
raise TypeError("Unsupported subject type")
dt = datetime.fromtimestamp(subject)
# strip timezone data
dt = dt.replace(tzinfo=None)
# finally, return a timedelta from the datetime
return datetime.now() - dt
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))