A little example:
$ python
Python 3.13.2 (main, Feb 5 2025, 08:05:21) [GCC 14.2.1 20250128] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime
>>> datetime.datetime.strptime("2025-UTC", "%Y-%Z")
datetime.datetime(2025, 1, 1, 0, 0)
>>> datetime.datetime.strptime("2025-+0000", "%Y-%z")
datetime.datetime(2025, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)
However reading the documentation, I would expect %Z
passed to strptime
to return an aware object for the values it supports:
%Z
...
strptime() only accepts certain values for %Z:
- any value in time.tzname for your machine’s locale
- the hard-coded values UTC and GMT
Even stranger, the internal function called by datetime.datetime.strptime
: _strptime parses the UTC
as expected:
>>> from _strptime import _strptime
>>> _strptime("2025-UTC", "%Y-%Z")
((2025, 1, 1, 0, 0, 0, 2, 1, 0, 'UTC', None), 0, 0)
So why doesn’t the high-level function return an aware object if the low-level function parsed the data?
I witnessed this behavior with python 3.5, 3.7, 3.10, 3.12 and 3.13 so I assume it isn’t a bug, but a feature? And so, what is the expected use/behavior of %Z in datetime.datetime.strptime? Did I miss something in the documentation or is it a bit unclear as to strptime is returning a naive or an aware object?
originally posted on Python Discuss Forum (with images there), sadly without success
I understand your question this way:
When using %Z
(timezone name like "UTC"), strptime()
parses the timezone but returns a naive datetime (no tzinfo).
When using %z
(UTC offset like "+0000"), strptime()
returns an aware datetime with tzinfo set
This is actually intentional behavior, And not a bug.
The reason behind this behavior is: strptime()
function was originally designed to match C-language strptime behavior, which doesn't handle timezone conversion. _strptime
function is shared with the time module, which doesn't have timezone awareness. Though %Z
can recognize timezone names, it doesn't have enough information to find the actual offset (especially for non-UTC/GMT zones)
_strptime
shows different output because: The low-level _strptime
function returns parsed components (including the timezone string). but doesn't do the final datetime construction. Higher-level datetime.strptime()
ignores the timezone name when creating the datetime object.
They should have clearly mentioned this behavior in the official document. They've mentioned what values %Z
accepts. but it is not said that these won't make the datetime timezone-aware.
So, youy can either Use %z with explicit offsets when possible. Or manually add the timezone after parsing:
dt = datetime.strptime("2025-UTC", "%Y-%Z").replace(tzinfo=timezone.utc)