pytz and Python timezones

Carl Meyer carl at oddbird.net
Sun Jun 12 11:13:16 EDT 2016


Hi Johannes,

On 06/11/2016 05:37 AM, Johannes Bauer wrote:
> I try to create a localized timestamp
> in the easiest possible way. So, intuitively, I did this:
> 
> datetime.datetime(2016,1,1,0,0,0,tzinfo=pytz.timezone("Europe/Berlin"))

That is indeed intuitive, but unfortunately (due to a misunderstanding
between the original authors of Python's datetime module and the author
of pytz about how timezone-aware datetimes should work in Python) it is
not correct. The correct way to create a localized datetime using pytz
is this:

    tz = pytz.timezone('Europe/Berlin')
    dt = tz.localize(datetime.datetime(2016, 1, 1, 0, 0, 0)

This is documented prominently in the pytz documentation:
http://pytz.sourceforge.net/

> Which gives me:
> 
> datetime.datetime(2016, 1, 1, 0, 0, tzinfo=<DstTzInfo 'Europe/Berlin'
> LMT+0:53:00 STD>)
> 
> Uuuuuh... what?

When you create a pytz timezone object, it encompasses all historical
UTC offsets that have ever been in effect in that location. When you
pass a datetime to the `localize()` method of that timezone object, it
is able to figure out which actual UTC offset was in effect at that
local time in that location, and apply the correct "version" of itself
to that datetime.

However, no such logic is built into the datetime module itself. So when
you just apply a pytz timezone directly to the tzinfo property of a
datetime, pytz by default falls back to the first entry in its
historical table of UTC offsets for that location. For most locations,
that is something called "LMT" or Local Mean Time, which is the
customary time in use at that location prior to the standardization of
timezones. And in most locations, LMT is offset from UTC by a strange
number of minutes. That's why you see "LMT" and the odd 53-minute offset
above.

> This here:
> 
> pytz.timezone("Europe/Berlin").localize(datetime.datetime(2016,1,1))
> 
> Gives me the expected result of:
> 
> datetime.datetime(2016, 1, 1, 0, 0, tzinfo=<DstTzInfo 'Europe/Berlin'
> CET+1:00:00 STD>)
> 
> Can someone explain what's going on here and why I end up with the weird
> "00:53" timezone? Is this a bug or am I doing things wrong?

It is not a bug in pytz or in datetime, in that it is intended behavior,
although that behavior is unfortunately obscure, bug-prone, and
little-understood.

If you are masochistic enough to want to understand how this bad
situation came to be, and what might be done about it, you can read
through PEPs 431 and 495.

Carl

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
URL: <http://mail.python.org/pipermail/python-list/attachments/20160612/33948325/attachment.sig>


More information about the Python-list mailing list