What Are Python Timezones? A Complete Introduction

Navigate to:

Datetime Python objects are split into two groups: naïve and aware. Naïve datetime objects are ones that don’t carry any information about timezones whatsoever, and aware objects do carry such information. Considering that, if you want to be able to work with Python datetime objects effectively, you must understand Python timezones, and that’s what this post is all about.

I’ll open the post by answering the title question: what are Python timezones? You’ll understand what timezones are in Python programming and what role they play, and see some examples of timezones.

With the what and why of Python timezones out of the way, the next logical step is to cover the how: you’ll see how you can get started using Python timezones in practice, with and without using the famous pytz library. Before wrapping up, you’ll see a brief Q&A section with some common questions people ask about Python timezones.

Let’s begin!

Prerequisites

There aren’t a lot of prerequisites for following along with this post. You’ll just need to have Python installed—version 3.9 or newer—and basic familiarity with the language. Do you have that? Then we’re good to go.

What Are Python Timezones?

What’s a time zone in the first place? Here’s the start of the Wikipedia definition:

A time zone is an area which observes a uniform standard time for legal, commercial and social purposes.

Thus, Python timezones are simply Python’s implementation of the concept of time zones.

The role of timezones in Python programming

The usage of timezones in Python programming is essential when you need to work with aware datetime objects. As you’ve read in the introduction, Python datetime objects by default are naïve—that is, they don’t know anything about timezones. Consider the following excerpt of code:


from datetime import datetime

today = datetime.now()

print(today)

print(today.tzinfo)

The code above uses the datetime.now() function to retrieve the current date and time and display it. Additionally, it displays the value of the tzinfo attribute on the datetime object.

However, the datetime object you get from datetime.now() is a naïve object: it doesn’t know anything about its timezone of origin. Take a look at the result I got after printing it:


2023-09-30 18:46:45.951525

None

The code displays the current—regarding the local machine—date and time, but the object doesn’t know anything about the timezone to which it belongs: that’s why None is displayed.

Now, let’s try something different: retrieve a datetime from a specific timezone. First, let’s install a required package:


pip install tzdata

The tzdata package contains timezone data we will need for the next code examples to work. Okay, the next step is actually changing the previous code to the following:


from zoneinfo import ZoneInfo

from datetime import datetime

today = datetime.now(ZoneInfo("America/Los_Angeles"))

print(today)

print(today.tzinfo)

Things are starting to get interesting, right? As you can see, the code now provides an instance of the ZoneInfo class for the datetime.now() function, specifying “America/Los_Angeles” as the timezone.

By running the code, this is the result I get now:


2023-09-30 14:59:34.788621-07:00

America/Los_Angeles

Things now look different. The string displaying the date and time in the ISO-8601 format now contains the offset from UTC appended to it (the “-07:00”). Also, the tzinfo attribute on the object now correctly returns the name of the timezone.

Python timezone examples

When working with timezones in Python—and programming in general—you’ll often see timezones represented by strings such as the following ones:

  • America/Sao_Paulo
  • Europe/Lisbon
  • Asia/Tokyo

What exactly are those and how do they work?

The above are examples of unique timezone names from the tz database, also called the IANA timezone database, or the Olson database.

How to Use Python Timezones

You’ve already seen a glimpse of how to use timezones in Python programming. Let’s delve deeper into it now. As you’ve seen in this post—and were possibly aware of even before—Python offers the datetime module which stores many of the types and functions you’ll need to work with dates.

You’ll now see two approaches you can use to retrieve objects that are aware of their timezones:

  • using the popular pytz library
  • employing only native functionality

The pytz library

The pytz library is a library that enables Python programmers to handle timezones from the Olson database. Let’s see a usage example. First, you’ll need to install the dependency:


pip install pytz

Then, write some code:


from datetime import datetime

import pytz

# getting the timezone for Santiago, Chile

chile_timezone = pytz.timezone("America/Santiago")

# retrieving the current time according to the timezone

current_time = datetime.now(chile_timezone)

print(current_time)

The native way

Since the version 3.9, Pythons counts with the zoneinfo module, which you’re already acquainted with from earlier examples. Let’s convert the previous example from pytz to zoneinfo:


from datetime import datetime

from zoneinfo import ZoneInfo

# Getting the timezone for Santiago, Chile

chile_timezone = ZoneInfo("America/Santiago")

# Retrieving the current time according to the timezone

current_time = datetime.now(chile_timezone)

print(current_time)

In the grand scheme of things, the code doesn’t change all that much, so which one should you choose? You’ll learn more about this in a minute.

Python Timezones Q&A

Let’s do a quick recap. Up until now, you’ve learned:

  • what timezones in Python are, and why they matter
  • a list of some important timezones, along with the strings that identify them on the tz (aka Olson) database
  • how to use Python timezones, in two different approaches

Now, let’s cover more ground by answering common Python timezone questions.

How do I get timezones in Python?

As you could see from our examples, you get timezones by either using the pytz library or the newer zoneinfo module:


# Getting the timezone for Santiago, Chile using 'ZoneInfo'

chile_timezone = ZoneInfo("America/Santiago")

# Getting the timezone for Santiago, Chile using 'pytz'

chile_timezone = pytz.timezone("America/Santiago")

Which one should you choose? The next question will answer that.

Is pytz deprecated?

At the time of this writing (late 2023): yes, pytz is deprecated. You shouldn’t use it for new projects written with Python 3.9 or newer versions, according to the project’s homepage:

Projects using Python 3.9 or later should be using the support now included as part of the standard library, and third-party packages work with it such as tzdata. pytz offers no advantages beyond backwards compatibility with code written for earlier versions of Python.

What library does Python use for timezones?

Historically, the main package Python used for timezone handling was, as you’ve seen, pytz. And, as you’ve also seen, this package is currently deprecated, meaning Python developers writing programs in recent versions of the languages should prefer the new, native solution of using the zoneinfo module.

Back at the start of this post, we used yet another library: tzdata. This package contains the actual data for the timezone database. Interestingly, you shouldn’t always need that package: its purpose is to function as a fallback for systems that don’t have this data—cough, Windows, cough—or maybe don’t have it in the standard locations.

Wrapping Up & Best Practices

Time handling is a fascinating and complex topic. In this post, you learned about timezones in Python, their importance and how to use them. Before parting ways, I’ll share a few tips. First, use UTC whenever you’ll need to record that something happened at a given time (for instance, for logging or auditing purposes). Here’s an example:


utc_timezone = zoneinfo.ZoneInfo("UTC")

utc_time = datetime.now(utc_timezone)

Local/naïve datetimes are great when the dates don’t need to leave the context of a single machine—e.g., they’ll be used only for being displayed on the screen. The instant they are “transmitted”—for instance, sent over the network or persisted to a database—all context is lost.

Of course, avoid mixing naïve and aware objects when performing comparisons and calculations. Additionally, use caution when performing time arithmetic. If you’re not mindful of, let’s say, daylight savings time, you could obtain incorrect results.

Finally, always strive to educate your team on date and time fundamentals. This topic is tricky—developers aren’t always educated about it, and many programming languages’ date and time APIs are written in an error-prone way.

Additional resources

This post was written by Carlos Schults. Carlos is a consultant and software engineer with experience in desktop, web, and mobile development. Though his primary language is C#, he has experience with a number of languages and platforms. His main interests include automated testing, version control, and code quality.