Nick Jensen
Nick Jensen

Reputation: 441

Python datetime + pytz issue

I'm creating a datetime object via strptime, set to "2016-01-02 03:04:05" in the "Europe/Madrid" timezone via pytz. Then I'm converting it to UTC.

Why does it add 15 minutes instead of subtract 1 hour?

>>> import datetime
>>> import pytz
>>> d = datetime.datetime.strptime('2016-01-02 03:04:05', '%Y-%m-%d %H:%M:%S')
>>> d
datetime.datetime(2016, 1, 2, 3, 4, 5)
>>> d = d.replace(tzinfo=pytz.timezone('Europe/Madrid'))
>>> d
datetime.datetime(2016, 1, 2, 3, 4, 5, tzinfo=<DstTzInfo 'Europe/Madrid' LMT-1 day, 23:45:00 STD>)
>>> d.astimezone(pytz.utc)
datetime.datetime(2016, 1, 2, 3, 19, 5, tzinfo=<UTC>)

It works correctly if instead of using "Europe/Madrid" I use "CET":

>>> d = d.replace(tzinfo=pytz.timezone('CET'))
>>> d
datetime.datetime(2016, 1, 2, 3, 4, 5, tzinfo=<DstTzInfo 'CET' CET+1:00:00 STD>)
>>> d.astimezone(pytz.utc)
datetime.datetime(2016, 1, 2, 2, 4, 5, tzinfo=<UTC>)

Edit 1: Python version is 2.7.11. pytz version is 2015.7.

Edit 2: Possible solution is to use d = pytz.timezone('Europe/Madrid').localize(d) instead of d = d.replace(tzinfo=pytz.timezone('Europe/Madrid')):

>>> d = datetime.datetime.strptime('2016-01-02 03:04:05', '%Y-%m-%d %H:%M:%S')
>>> d
datetime.datetime(2016, 1, 2, 3, 4, 5)
>>> d = pytz.timezone('Europe/Madrid').localize(d)
>>> d
datetime.datetime(2016, 1, 2, 3, 4, 5, tzinfo=<DstTzInfo 'Europe/Madrid' CET+1:00:00 STD>)
>>> d.astimezone(pytz.utc)
datetime.datetime(2016, 1, 2, 2, 4, 5, tzinfo=<UTC>)

Edit 3: Perhaps this is an instance of "using the tzinfo argument of the standard datetime constructors 'does not work' with pytz for many timezones"? Source

Upvotes: 6

Views: 957

Answers (1)

eumiro
eumiro

Reputation: 212845

Yes, the problem is in

d.replace(tzinfo=pytz.timezone('Europe/Madrid'))

where it applies the first known UTC offset in Madrid (called LMT = Local Mean Time), which was 15 minutes behind UTC (valid until 1900), or in this case expressed as -1 day +23:45:

datetime.datetime(2016, 1, 2, 3, 4, 5, tzinfo=<DstTzInfo 'Europe/Madrid' LMT-1 day, 23:45:00 STD>)

Use

pytz.timezone('Europe/Madrid').localize(d)

instead:

datetime.datetime(2016, 1, 2, 3, 4, 5, tzinfo=<DstTzInfo 'Europe/Madrid' CET+1:00:00 STD>)

which will apply the UTC offset valid in 2016, i.e. CE(S)T.

Upvotes: 8

Related Questions