Created
January 9, 2013 01:59
-
-
Save davidjb/4489920 to your computer and use it in GitHub Desktop.
Improved humanisation for Ago
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from datetime import datetime, timedelta | |
import ago | |
def human(date, | |
precision=2, | |
past_fmt="{} ago", | |
present_fmt="right now", | |
future_fmt="in {}", | |
present_tolerance=timedelta(0)): | |
"""Humanise a datetime object's difference between it and the time now. | |
Pass this method a datetime object, it will compute the difference between | |
it and ``datetime.now()`` and return this difference as a "human-readable" | |
string. Use the ``precision`` keyword argument to control the granularity | |
of the resulting string. | |
>>> from datetime import datetime, timedelta | |
>>> one_min_from_now = datetime.now() + timedelta(minutes=1.5) | |
>>> human(one_min_from_now, precision=1) | |
'in 1 minute' | |
>>> one_min_ago = datetime.now() - timedelta(minutes=1.5) | |
>>> human(one_min_ago, precision=1) | |
'1 minute ago' | |
This function will format the humanised difference according to the | |
string formats provided as keyword arguments for past, present, and | |
future dates. | |
>>> human(datetime.now() - timedelta(days=5, hours=2, minutes=30), precision=3, past_fmt="{} in the past") | |
'5 days, 2 hours, 30 minutes in the past' | |
>>> human(datetime.now() + timedelta(days=5, hours=2, minutes=30, seconds=30), precision=3, future_fmt="Coming up in {} time") | |
'Coming up in 5 days, 2 hours, 30 minutes time' | |
>>> human(one_min_ago, precision=1, present_tolerance=timedelta(minutes=2)) | |
'right now' | |
>>> human(one_min_from_now, precision=1, present_tolerance=timedelta(minutes=2), present_fmt="very recently") | |
'very recently' | |
*Arguments/keywords* | |
date | |
The ``datetime`` object to compare to the current ``datetime`` (``datetime.now()``). | |
The timedelta between these is what is humanised. Required. | |
precision | |
The precision to use when humanising the resulting timedelta. This is | |
passed to ``delta2human``. Default: 2. | |
past_fmt | |
String to be formatted if the date is earlier than the current | |
time, outside of the given ``present_tolerance``. This string is | |
formatted using ``format()`` method and passed the result of | |
``delta2human``. Default: "{} ago". | |
present_fmt | |
String to be used if the date is considered the present. See | |
``present_tolerance`` for what is considered the 'present' time. | |
Default: "right now". | |
future_fmt | |
String to be formatted if the date is later than the current | |
time, outside of the given ``present_tolerance``. This string is | |
formatted using ``format()`` method and passed the result of | |
``delta2human``. Default: "{} ago". | |
present_tolerance | |
The ``datetime.timedelta`` margin to consider the difference | |
between ``date`` and the current ``datetime`` as being | |
'right now'. For example, this if set as | |
``datetime.timedelta(minutes=5)``, then dates between 5 | |
minutes before and 5 minutes after now will be treated as the present. | |
Increasing the tolerance can useful for reducing precision to make | |
the result seem more 'human'. | |
This argument may be passed as ``dict`` or two-tuple of options used | |
for constructing a ``timedelta`` object. | |
Default: ``datetime.timedelta(0)`` (exact datetime match required). | |
""" | |
if not isinstance(present_tolerance, timedelta): | |
present_tolerance = timedelta(**dict(present_tolerance)) | |
result = present_fmt | |
delta = date - datetime.now() | |
delta2human = lambda: ago.delta2human(abs(delta), precision=precision) | |
if delta > present_tolerance: | |
result = future_fmt.format(delta2human()) | |
elif delta < -present_tolerance: | |
result = past_fmt.format(delta2human()) | |
return result | |
if __name__ == "__main__": | |
import doctest | |
doctest.testmod() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment