I've learned something useful about Python timezone handling in datetime objects.
Let's suppose I got a timestamp from an external source. It's in a string variable now.
>>> timestamp_str = "2023-07-19T18:15:10-07:00"
Cool, it's in ISO format, let's parse it!
>>> from datetime import datetime
>>> timestamp = datetime.fromisoformat(timestamp_str)
Is it in the past?
>>> timestamp < datetime.now()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes
What? One of these datetime objects contain timezone information, the other one doesn't. They don't play with each other nicely.
>>> timestamp.isoformat()
'2023-07-19T18:15:10-07:00'
>>> datetime.now().isoformat()
'2023-07-19T18:24:10.978546'
OK, how can I add timezone to now
? I'm in Central European Summer Time (CEST) at the moment. But as I learned, it's a bit complicated. I will get back to this later, let's work with UTC, it's easier. datetime.now
accepts a timezone parameter.
>>> from datetime import timezone
>>> datetime.now(timezone.utc).isoformat()
'2023-07-19T18:25:38.4567+00:00'
>>> timestamp < datetime.now(timezone.utc)
False
That's better. But can I use my own timezone here? I can, if I know what my timezone is. CEST is UTC +2. The timezone class is here to help.
>>> from datetime import timedelta
>>> timezone(timedelta(hours=2))
datetime.timezone(datetime.timedelta(seconds=7200))
>>> datetime.now(timezone(timedelta(hours=2))).isoformat()
'2023-07-19T18:31:355.529775+02:00'
>>> timestamp < datetime.now(timezone(timedelta(hours=2)))
False
But what if I don't know my timezone? How can I get the local timezone? If it's a remote host, it can be anywhere. What I found is that the datetime.astimezone()
method can help here. If it gets a target timezone parameter, it converts the datetime to that timezone. If it gets nothing (or None) it uses the system local timezone.
>>> datetime.now().isoformat()
'2023-07-19T18:37:47.447466'
>>> datetime.now(timezone.utc).isoformat()
'2023-07-19T16:37:55.417677+00:00'
>>> datetime.now(timezone.utc).astimezone(timezone(timedelta(hours=2))).isoformat()
'2023-07-19T18:38:32.881836+02:00'
>>> datetime.now(timezone.utc).astimezone().isoformat()
'2023-07-19T18:39:25.116842+02:00'
Yep, I'm really in CEST. I can get that info in the tzinfo
attribute.
>>> datetime.now(timezone.utc).astimezone().tzinfo
datetime.timezone(datetime.timedelta(seconds=7200), 'CEST')
>>> local_timezone = datetime.now(timezone.utc).astimezone().tzinfo
>>> datetime.now().isoformat()
'2023-07-19T18:40:56.4701'
>>> datetime.now(local_timezone).isoformat()
'2023-07-19T18:41:02.30460+02:00'
So astimezone
works fine with no parameters, but I find it hard to read. I'm still looking for the really readable solution.
But here comes the next challenge, if you are still not dizzy. You read the following timestamp from a textfile.
>>> timestamp_str = "2023-07-19T18:39:25"
It doesn't contain timezone information, but you know that it's in Pacific Daylight Time. How can you add that timezone information to the datetime object?
Can datetime.astimezone
help here? It not just simply adds the timezone information to the datetime, it adjusts date and time accordingly.
>>> datetime.fromisoformat(timestamp_str)
datetime.datetime(2023, 7, 19, 18, 39, 25)
>>> pdt_timezone = timezone(timedelta(hours=-7))
>>> datetime.fromisoformat(timestamp_str).astimezone(pdt_timezone)
datetime.datetime(2023, 7, 19, 9, 39, 25, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=61200)))
This is not exactly what I wanted. It turned out that the solution is simply replacing tzinfo
in the datetime object.
>>> datetime.fromisoformat(timestamp_str).replace(tzinfo=pdt_timezone)
datetime.datetime(2023, 7, 19, 18, 39, 25, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=61200)))
Much better. Happy? Kind of. Can we just store every timestamp with timezone info added? Or everything it UTC? Thanks.
Top comments (1)
Hi rkucsora!
Thanks for sharing your knowledge on how to deal with timezones in Python with us here on Dev!
However, you should consider grouping the paragraphs of your article into sections so readers can easily read and assimilate what you’re trying to teach.
Thanks again and Happy coding!