User-friendly time format in Python?

36,490

Solution 1

The code was originally published on a blog post "Python Pretty Date function" (http://evaisse.com/post/93417709/python-pretty-date-function)

It is reproduced here as the blog account has been suspended and the page is no longer available.

def pretty_date(time=False):
    """
    Get a datetime object or a int() Epoch timestamp and return a
    pretty string like 'an hour ago', 'Yesterday', '3 months ago',
    'just now', etc
    """
    from datetime import datetime
    now = datetime.now()
    if type(time) is int:
        diff = now - datetime.fromtimestamp(time)
    elif isinstance(time, datetime):
        diff = now - time
    elif not time:
        diff = 0
    second_diff = diff.seconds
    day_diff = diff.days

    if day_diff < 0:
        return ''

    if day_diff == 0:
        if second_diff < 10:
            return "just now"
        if second_diff < 60:
            return str(second_diff) + " seconds ago"
        if second_diff < 120:
            return "a minute ago"
        if second_diff < 3600:
            return str(second_diff // 60) + " minutes ago"
        if second_diff < 7200:
            return "an hour ago"
        if second_diff < 86400:
            return str(second_diff // 3600) + " hours ago"
    if day_diff == 1:
        return "Yesterday"
    if day_diff < 7:
        return str(day_diff) + " days ago"
    if day_diff < 31:
        return str(day_diff // 7) + " weeks ago"
    if day_diff < 365:
        return str(day_diff // 30) + " months ago"
    return str(day_diff // 365) + " years ago"

Solution 2

If you happen to be using Django, then new in version 1.4 is the naturaltime template filter.

To use it, first add 'django.contrib.humanize' to your INSTALLED_APPS setting in settings.py, and {% load humanize %} into the template you're using the filter in.

Then, in your template, if you have a datetime variable my_date, you can print its distance from the present by using {{ my_date|naturaltime }}, which will be rendered as something like 4 minutes ago.

Other new things in Django 1.4.

Documentation for naturaltime and other filters in the django.contrib.humanize set.

Solution 3

In looking for the same thing with the additional requirement that it handle future dates, I found this: http://pypi.python.org/pypi/py-pretty/1

Example code (from site):

from datetime import datetime, timedelta
now = datetime.now()
hrago = now - timedelta(hours=1)
yesterday = now - timedelta(days=1)
tomorrow = now + timedelta(days=1)
dayafter = now + timedelta(days=2)

import pretty
print pretty.date(now)                      # 'now'
print pretty.date(hrago)                    # 'an hour ago'
print pretty.date(hrago, short=True)        # '1h ago'
print pretty.date(hrago, asdays=True)       # 'today'
print pretty.date(yesterday, short=True)    # 'yest'
print pretty.date(tomorrow)                 # 'tomorrow'

Solution 4

You can also do that with arrow package

From github page:

>>> import arrow
>>> utc = arrow.utcnow()
>>> utc = utc.shift(hours=-1)
>>> utc.humanize()
'an hour ago'

Solution 5

There is humanize package:

>>> from datetime import datetime, timedelta
>>> import humanize # $ pip install humanize
>>> humanize.naturaltime(datetime.now() - timedelta(days=1))
'a day ago'
>>> humanize.naturaltime(datetime.now() - timedelta(hours=2))
'2 hours ago'

It supports localization , internationalization :

>>> _ = humanize.i18n.activate('ru_RU')
>>> print humanize.naturaltime(datetime.now() - timedelta(days=1))
день назад
>>> print humanize.naturaltime(datetime.now() - timedelta(hours=2))
2 часа назад
Share:
36,490
flybywire
Author by

flybywire

Updated on July 05, 2022

Comments

  • flybywire
    flybywire almost 2 years

    Python: I need to show file modification times in the "1 day ago", "two hours ago", format.

    Is there something ready to do that? It should be in English.

  • flybywire
    flybywire over 14 years
    that is tailored to my exact needs. Thanks!
  • Chris Dail
    Chris Dail over 14 years
    The link no longer exists and is giving a Forbidden. Need a permlink here or the content to be moved into this post.
  • Jed Smith
    Jed Smith over 14 years
    @Chris: Thanks for the heads up, and it was still in Google Cache so I snagged it.
  • wenbert
    wenbert over 13 years
    This does not work for me. I get this error: local variable 'diff' referenced before assignment why?
  • Karl Bartel
    Karl Bartel over 12 years
    Unfortunately py-pretty does not seem to allow i18n.
  • Jonathan
    Jonathan almost 11 years
  • Jon z
    Jon z over 10 years
    It would be nice if the time units were not pluralized for single counts, for example '1 week ago' rather than '1 weeks ago'
  • aqs
    aqs over 9 years
    Is adding it to INSTALLED_APPS really necessary? It worked without that for me, although I used the filter inside python, not the template
  • Zeeshan Anjum
    Zeeshan Anjum over 8 years
    UnboundLocalError: local variable 'diff' referenced before assignment
  • Olivier Pons
    Olivier Pons about 8 years
    What is the point of the code diff = now - now. Cant we do instead diff = 0
  • TaiwanGrapefruitTea
    TaiwanGrapefruitTea over 7 years
    @Jonathan I tried human_dates 0.2.0 and got: 2.76986301369863 years ago . I found a version in django at github.com/django/django/blob/master/django/utils/timesince.‌​py which gives me: 2 years, 9 months
  • swdev
    swdev about 7 years
    Nice solution. Keeping it simple allows more reuse. E.g can use suffix for relative time value + " ago" or duration value + " left"
  • Ayrat
    Ayrat about 6 years
    @wenbert because in python 3 mtime is of type float, not of type int. In the first if, change int to float.
  • Lucas Werkmeister
    Lucas Werkmeister about 5 years
    Note that humanize does not support timezone-aware datetimes; you’ll have to convert those via into naive ones (in the local timezone) with dt.astimezone().replace(tzinfo=None).
  • Trect
    Trect about 4 years
    Can I use this inside view
  • WinEunuuchs2Unix
    WinEunuuchs2Unix almost 4 years
    The link appears broken again, not 404 but rather a sales page in foreign language.