Reputation: 1171
I'm trying to apply a tzinfo to a datetime object.
In [1]: from datetime import datetime
In [2]: import pytz
In [3]: london = pytz.timezone("Europe/London")
In [4]: london
Out[5]: <DstTzInfo 'Europe/London' LMT-1 day, 23:59:00 STD>
In [6]: localized_date_object = datetime(2016, 1, 1, 11, 30, 0, 5000, london)
In [7]: localized_date_object
Out[8]: datetime.datetime(2016, 1, 1, 11, 30, 0, 5000, tzinfo=<DstTzInfo 'Europe/London' LMT-1 day, 23:59:00 STD>)
In [9]: utc_date_object = localized_date_object.astimezone(pytz.utc)
In [10]: utc_date_object
Out[11]: datetime.datetime(2016, 1, 1, 11, 31, 0, 5000, tzinfo=<UTC>)
In [16]: paris = pytz.timezone("Europe/Paris")
In [17]: localized_date_object = datetime(2016, 1, 1, 11, 30, 0, 5000, paris)
In [18]: utc_date_object = localized_date_object.astimezone(pytz.utc)
In [19]: utc_date_object
Out[19]: datetime.datetime(2016, 1, 1, 11, 21, 0, 5000, tzinfo=<UTC>)
As you can see, it's applying delta to minutes instead of hours.
Can someone explain me what I'm doing wrong here.
Upvotes: 8
Views: 7418
Reputation: 2024
There is often more than one definition of the offset from UTC depending on the agreed standardisation at that time.
When using datatime function with timezone to construct a datetime, it is not very clever about which conversion to use and will tend to default to an old historic offset, in your example one which as a one minute offset. It is doing this because it chooses the timezone delta before considering the date being converted.
This alternative method resolves that gives more reliable (modern standards) results:
dt = mytz.localize(datetime(2020, 4, 7, 16, 30))
Upvotes: 0
Reputation: 111
The pytz docs say:
This library only supports two ways of building a localized time. The first is to use the localize() method provided by the pytz library. This is used to localize a naive datetime (datetime with no timezone information):
The second way of building a localized time is by converting an existing localized time using the standard astimezone() method:
Unfortunately using the tzinfo argument of the standard datetime constructors ‘’does not work’’ with pytz for many timezones.
In the code sample provided you are trying to use the tzinfo
argument rather than localize()
>>> london = pytz.timezone("Europe/London")
>>> datetime.datetime(2016, 1, 1, 11, 30, 0, 5000, london) # This is incorrect
datetime.datetime(2016, 1, 1, 11, 30, 0, 5000, tzinfo=<DstTzInfo 'Europe/London' LMT-1 day, 23:59:00 STD>)
>>> london.localize(datetime.datetime(2016, 1, 1, 11, 30, 0, 5000)) # This is correct
datetime.datetime(2016, 1, 1, 11, 30, 0, 5000, tzinfo=<DstTzInfo 'Europe/London' GMT0:00:00 STD>)
Upvotes: 11
Reputation: 16625
I think that you should use CET for Paris time and UTC for London time. I am using a bit different approach but it works for me:
from datetime import datetime
from pytz import timezone
ldo = datetime(2016, 1, 1, 11, 30, 0, 5000)
ldo = ldo.replace(tzinfo=timezone('Europe/London'))
udo = ldo.astimezone(timezone('UTC'))
print ldo
print udo
ldo = datetime(2016, 1, 1, 11, 30, 0, 5000)
ldo = ldo.replace(tzinfo=timezone('CET'))
udo = ldo.astimezone(timezone('UTC'))
print ldo
print udo
UPDATE:
When you store time values there should be also stored related timezone information. IMO best practice is to store everything in UTC and convert for viewing to "user" timezone. BTW converting from UTC to Europe/Paris works flawlessly, try this:
winter = datetime(2016, 1, 1, 11, 30, 0, 5000, tzinfo=timezone("UTC"))
paris = winter.astimezone(timezone("Europe/Paris"))
print paris
# 2016-01-01 12:30:00.005000+01:00
summer = datetime(2016, 6, 1, 11, 30, 0, 5000, tzinfo=timezone("UTC"))
paris = summer.astimezone(timezone("Europe/Paris"))
print paris
# 2016-06-01 13:30:00.005000+02:00
Upvotes: 2
Reputation: 8599
The timezone Europe/London is after UTC 1 minute. The timezone Europe/Paris is before UTC by 9 minutes. London and Paris is close to Greenwich geographically, so timezone offset is small.
If you try
pytz.timezone("Asia/Shanghai")
, you will see hours change.
Upvotes: 0
Reputation: 1215
In line #5, it shows a strange output - <DstTzInfo 'Europe/London' LMT-1 day, 23:59:00 STD>
which seems to be one-minute shift (Minus 1 day + 23:59:00 hours).
I would suggest that you try a few other time zone definitions in pytz to see their declarations.
Upvotes: 0