How to humanize date and time in Python

Often there is a task to bring the date and/or time from the standard absolute view (18:03) to the view which is relative to the current moment (5 minutes ago). This task is called humanization. Indeed, in many cases it is more convenient to understand that the event happened 'a minute ago', '2 days ago', 'a week ago' rather than trying to gure out the difference yourself.

If you like to do everything yourself, then it's easy to write the appropriate function to fit your needs. It might look like this, for example.


from datetime import datetime, timedelta
def my_humanize(dt):
	# get the interval from the < dt > to the current moment in seconds
	interval = int((datetime.now() - dt).total_seconds())
	
	# edge case of < dt> is now
	if interval == 0:
		return "just now"
	elif interval > 0:
		keyword = "ago"
	else:
		keyword = "later"
		interval = -interval

	names = ["second", "minute", "hour", "day", "week", "month", "year"]
	multipliers = [1, 60, 3600, 3600*24, 3600*24*7, 3660*24*30, 3660*24*30*12]
	
	pretty = ""
	
	for i, m in enumerate(multipliers[::-1]):
		value = interval // m
		interval -= value * m
		if value != 0:
			if value == 1: # take the singular into account
				pretty += f"{value} {names[-(i+1)]} "
			else:
				pretty += f"{value} {names[-(i+1)]}s "
	return pretty + keyword


print(my_humanize(datetime.now() - timedelta(hours=3, minutes=2, seconds = 1)))
print(my_humanize(datetime.now() - timedelta(hours = 50000, minutes = 15, seconds = 12)))
print(my_humanize(datetime.now() + timedelta(hours = 15)))
print(my_humanize(datetime.now()))


3 hours 2 minutes 1 second ago
5 years 8 months 1 week 2 days 8 hours 15 minutes 12 seconds ago
14 hours 59 minutes 59 seconds later
just now.

We calculate the interval from the argument < dt > to the current moment in seconds. Then we calculate the result of dividing without remainder by each factor from year to second sequentially. And each time we pass only the remainder to the next iteration.

This approach, when you write everything yourself, may not always be appropriate. A more pythonic way is to nd a suitable published module. One of these modules is humanize. You can install it by the following command.

pip install humanize
Requirement already satisfied: humanize in /usr/local/lib/python3.6/dist-packages (0

Then you can import the module and try it. This module contains several functions for the humanized display of various data. The function for humanizing the date is called naturaltime.

from humanize import naturaltime
from datetime import datetime, timedelta
print(naturaltime(datetime.now() - timedelta(seconds = 1)))
print(naturaltime(datetime.now() - timedelta(hours = 50000, minutes = 15, seconds = 12)))
print(naturaltime(datetime.now() + timedelta(hours = 15)))
print(naturaltime(datetime.now()))
a second ago
5 years ago
14 hours from now
now

One of the key advantages of this module is embedded localization for many languages. In particular for Russian, German, Spanish, French, Chinese. You can find more details in the module documentation. For example, you can enable the French localization like this.

_t = humanize.i18n.activate('fr')
print(naturaltime(datetime.now() + timedelta(hours = 15)))
print(naturaltime(datetime.now()))
dans 14 heures
maintenant

To deactivate localization.

humanize.i18n.deactivate()

There is another interesting module called arrow. Let's install and try it too.

pip install arrow
Collecting arrow
Downloading https://files.pythonhosted.org/packages/ca/bc/ebc1afb3c54377e128a01024c
|████████████████████████████████| 51kB 2.3MB/s
Requirement already satisfied: python-dateutil>=2.7.0 in /usr/local/lib/python3.6/dis
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.6/dist-packages (fr
Installing collected packages: arrow
Successfully installed arrow-0.17.0

A feature of this module is the use of its own time format. This can be both an advantage and a disadvantage. The display of this format is often more convenient than the standard datetime object. But to use a standard datetime object it needs to be converted. To humanize date we use humanize method of arrow datetime object.

import arrow
time1 = arrow.get(datetime.now() - timedelta(seconds = 10))
print(time1.humanize())
time2 = arrow.get(datetime.now() - timedelta(hours = 50000, minutes = 15, seconds = 12))
print(time2.humanize())
time3 = arrow.get(datetime.now() + timedelta(hours = 50, minutes = 15, seconds = 12))
print(time3.humanize())
10 seconds ago
5 years ago
in 2 days

The advantage of this module over the previous one is in exible display settings. For this, a special argument granularity is used. Let's take the time2 variable from the previous example and humanize it with different granularity settings.

print(time2.humanize(granularity=["year", "month", "day", "hour", "minute"]))
print(time2.humanize(granularity=["year", "hour", "minute"]))
print(time2.humanize(granularity=["minute"]))
5 years 8 months 13 days 2 hours and 24 minutes ago
5 years 6170 hours and 24 minutes ago
3000024 minutes ago

Conclusion

We have considered several options for humanizing the date and time objects in Python.

Each of the options has its own pros and cons. The most exible but also most time consuming option is to write the function yourself.

If you need localization, you should use humanize module.If you need exibility in display and are satis ed with the necessity for conversion, then you can use arrow module.