Proper Time Zone Support
Previously, I gave you a quick overview of the course. In this lesson, I’ll be talking about the new
zoneinfo library. By default, timestamps created with the
datetime module have no time zone information.
You can add a time zone to a date using the
tz attribute in the date/time creation methods. Timestamps without time zone information are called naive.
datetime.now() without any parameters returns a naive datetime. By passing in a
tz parameter, you can set a time zone to be associated with the timestamp.
In this case here, I’ve passed in
utc. Previous to Python 3.9, the only time zone that came out of the box was UTC. You had to subclass it or use a third-party library in order to use time zones besides UTC.
Python 3.9 introduces the
zoneinfo module. The
ZoneInfo class inside of it accesses your computer’s time zone database and makes that information available to you in your code.
01:06 You can specify times zones by name, and there are hundreds of them—including historic values—available. The library also handles the name changes that happen if your time zone switches into Daylight Savings Time.
01:22 Let me start by demonstrating time zones before Python 3.9. These are the modules you’ll need.
now() returns the current datetime. This is a naive datetime; it does not include time zone information. I can use the
timezone module and specify a time zone of
utc, and now I have a datetime including time zone information.
The new feature from Python 3.9 is the
ZoneInfo class. I can specify a
ZoneInfo using a time zone string. This is the time zone for the west coast of Canada.
You can use a
ZoneInfo object in conjunction with the
Here’s the current time in Oslo. The
.astimezone() function allows you to convert a
datetime between time zones.
Let me just construct a new
This one’s in Vancouver. Then I can call
.astimezone(), passing in Oslo,
and I get the same datetime stamp, but in the Oslo time zone. It’s converted it for me.
zoneinfo has an
available_timezones() function to list everything that’s in the database. There’s a lot there, so I’m not going to show it all to you.
The number of entries varies from operating system to operating system. What is happening here is
zoneinfo is loading a file that comes with your computer.
I’m running this on a Mac, and at the moment there’s
595 items in the database. My colleague who wrote the article that goes with this course—I believe he was using Linux and he got
609, so you’re going to get variation from place to place.
03:16 There aren’t 595 times zones on the planet, so why is there so much information in the database? This is because it includes historical information. As countries change, as borders change, and as countries change their mind about what time zone they’re in—the data shifts.
03:32 Let me show you an extreme example of this.
03:41 This is the time zone for Christmas Island. You might be wondering why I said Christmas. Well, the name of the zone there is actually the Kiribati spelling of the word Christmas. Kiribati pronounces it closer to “kirismash”, but I’m not going to embarrass myself by attempting that. Christmas Island is near the International Date Line. At the end of 1994, the residents of Christmas Island decided they wanted to shift what time zone they were in.
04:10 They changed which side of the date line they were on in order to minimize the time difference with their primary trading partners. Here’s New Year’s Eve 1994 in UTC.
Now I’m going to use
.astimezone() to convert that to Christmas Island’s time zone, and you’ll notice that that’s showing as December 30th. To make the next bit clearer, I’m going to use the
timedelta library to create a variable containing the amount of time in an hour.
04:43 It’ll make some of the math in the next chunk simpler.
There’s the library. And I’m going to store the amount of a single hour in a variable called
And this is where the weirdness happens. The original
.astimezone() was 1994, December 30th. One hour later, it’s 1995, January 1st. Because Christmas Island decided to switch from one side of the date line to the other at the end of 1994, they lost December 31st. It just disappeared. One hour, it was 1994, December 30th. An hour later, it was 1995.
You can see the same thing happening by calling
.utcoffset() (UTC offset).
This function returns the
timedelta between your current time zone and UTC. The delta on December 30th, 1994 was 50,400 seconds.
06:00 Dividing that by an hour, gives something that’s a little easier to keep in your head. It was -10 hours. The UTC offset the next day…
06:14 was 14 hours. They swapped which side of the International Date Line they were on, and everything moved forward by 24 hours. In addition to historical corner cases, you can also see more typical changes like those caused by Daylight Savings Time. Once again, here’s Vancouver.
.tzname() function gives you the short name that is commonly used for a time zone. On October 5th, this time zone is referred to as
'PDT', short for Pacific Daylight Time.
Later on in the same year, and the short name for this time zone changes to
'PST', for Pacific Standard Time. The
zoneinfo database allows you to see all of this.
As I mentioned before, the
ZoneInfo class is getting its time zone information from a database on your computer. Depending on your operating system, the values in that database may be different or could be missing altogether.
Some computers don’t have this database installed, particularly certain versions of Windows. If you go to use the
ZoneInfo class in this case, you’ll get an exception. To make sure all Python programmers are on an equal footing, the folks at Python have also created a
tzdata database, so if your operating system doesn’t ship with the database, you can use
pip install to get a copy of the database maintained by the Python folks.
ZoneInfo has also been backported to earlier versions of Python. You can get this code using
pip install backports.zoneinfo. If you’re trying to write code that uses this module in Python 3.9 or earlier, you can do a
except block importing
zoneinfo or the
backports version of
zoneinfo to make sure that you always get the library.
08:09 Here are a few things to keep in mind when using time zones. If you’re trying to record a timestamp that is a civil time, it should include a time zone. Civil times are things like meetings, train times, concerts—the kinds of thing you would put inside of your calendar.
08:26 These kinds of events tend to be related to a location. Keeping the appropriate time zone allows you to store that information with the timestamp. This is particularly useful if your user is traveling.
08:38 If they happen to be in another time zone, they need to know what the appointment was in the time zone they were in. If you aren’t storing the time zone information, things get muddy quickly. Timestamps, on the other hand, should be naive and based on UTC.
08:54 The typical use of timestamps is inside of server logs. You don’t want to be dealing with the changes in Daylight Savings Time, or time zone changes of a server, or where the server is located when you’re trying to timestamp an event.
09:07 UTC is always monotonically increasing. That means the numeric value is always going up. Because of things like Daylight Savings Time, that’s not true of civil times.
09:18 It is possible for an event at 1:30 in the morning to be after an event at 2:00 in the morning in a time zone that uses Daylight Savings Time on the day that it shifts. Because you don’t want to be dealing with this inside of your server logs, stick with a UTC-based timestamp.
09:37 Next up, I’ll introduce you to the new operators for dictionaries.
Dang, sorry. I made my comment before I saw you addressed the missing IANA database in your video. Sorry.
I tried to see what’s in zoneinfo.available_timezones() and I get an error telling ‘zoneinfo’ is not defined. However, I’ve imported it. Could someone point me what’s the issue? Thank you.
@raulfz Are you sure you’re running Python 3.9? It sounds like you might be running an earlier version or have a typo in your code. Would you mind sharing it?
Hi, thank so much for your response. I didn’t realize that I’ve just imported the function TimeZone and not the whole timezone module, that was the problem.
I was following the video code exactly as it is shown:
from zoneinfo import TimeZone
Instead of writing:
What I could have realized when I called
zoneinfo.avaliable_timezones() Thank you for taking the time to answer my question.
You’re right. Looks like I missed a line when I copied it into the presentation. I’ll get it patched to avoid future confusion. Sorry about that.
No problem at all, actually I should kind of infer it by noting that you were calling the method on zoneinfo object and not on ZoneInfo. Anyway, thank you for your time.
Become a Member to join the conversation.
jamesbrown68 on Nov. 18, 2020
For Windows users like me, the ZoneInfo class might not work. Entering something like
ZoneInfo("America/Vancouver")will return “ZoneInfoNotFoundError”.
Per the Python docs,
The solution was to use pip to install ‘tzdata’ first before working with the ZoneInfo class.