Making sense of timezones in Python

Avoiding common pitfalls when dealing with timezones

Daniel van Flymen
2 min readAug 20, 2019
Photo by Sonja Langford

Running into timezone trouble in your Python project? Here’s a quick primer on how timezones work and how to convert between them (mostly because I usually forget how to do this myself).

We’ll be using the popular pytz package, so make sure it’s installed.

🙃 Naive and aware datetimes

A naive datetime doesn’t have a timezone associated with it. An aware one does.

from datetime import datetime
from pytz import timezone
# Set the time to noon on 2019-08-19
naive = datetime(2019, 08, 19, 12, 00)
# Let's treat this time as being in the UTC timezone
aware = timezone('UTC').localize(naive)

pytz.localize() is useful for making a naive timezone aware. I find that it’s useful when a front-end client sends a datetime to the backend to be treated as a particular timezone (usually UTC).

🎛 Converting between timezones

💡 It’s best practice to store all datetimes in your project as UTC. Most ORMs, including SQLAlchemy and Django will store aware datetimes in UTC. This ensures you almost never have to do conversions between timezones. It’s best to leave the rendering of timezones to the front-end…

To render an aware datetime (perhaps from a record in a database) in another timezone we can use the pytz.astimezone() method:

from datetime import datetime
from pytz import timezone
# Set the time to noon on 2019-08-19
naive = datetime(2019, 08, 19, 12, 00)
UTC = timezone('UTC')
NYC = timezone('America/New_York')
aware = UTC.localize(naive)# UTC is 5 hours ahead of New York, let's verify
time_in_new_york = aware.astimezone(NYC)
print(time_in_new_york)
>>> 2019-08-19 08:00:00-04:00

🐍 Common Pitfalls

Avoid using datetime.replace(tzinfo=…) to make timezones aware

It will only work with UTC and the behavior is inconsistent with other timezones. Rather use localize() as above.

Getting the correct UTC time

from datetime import datetime
from pytz import UTC
# Naive UTC
naive = datetime.utcnow()
# Aware UTC (if you're about to render it in another timezone)
aware = UTC.localize(datetime.utcnow())

Using datetime.now() just returns your system’s current wall-clock time.

--

--