The main problem here is that you are using a pytz
time zone. pytz
zones do not follow the tzinfo
interface and cannot be simply attached to datetime
objects (either through the constructor or through replace
). If you would like to use pytz
time zones, you should use pytz.timezone.localize
with a naive datetime
. If the datetime
is already timezone-aware, you can use datetime.astimezone
to convert it between zones.
from dateutil import parser
import pytz
LON = pytz.timezone('Europe/London')
dt = parser.parse('2017-05-31T15:00:00')
dt = LON.localize(dt)
print(dt) # 2017-05-31 15:00:00+01:00
This is because pytz
's interface uses localize
to attach a static time zone to a datetime
. For the same reason, if you do arithmetic on the now-localized datetime
object, it may give similar improper results and you'll have to use pytz.timezone.normalize
to fix it. The reason this is done this way is that, historically, it has not been possible to handle ambiguous datetimes using a Pythonic tzinfo
interface, which changed with PEP 495 in Python 3.6, making pytz
's workaround less necessary.
If you would like to pass a tzinfo
to a datetime
using replace
or the constructor, or you would prefer to use the pythonic interface, dateutil
's time zone suite implements a PEP 495-compliant tzinfo
interface. The equivalent using a dateutil
zone is:
from dateutil import parser
from dateutil import tz
LON = tz.gettz('Europe/London')
dt = parser.parse('2017-05-31T15:00:00').replace(tzinfo=LON)
print(dt) # 2017-05-31 15:00:00+01:00