Python datetime object show wrong timezone offset
I am try creating a datetime object开发者_开发知识库 in python using datetime and pytz, the offset shown is wrong.
import datetime
from pytz import timezone
start = datetime.datetime(2011, 6, 20, 0, 0, 0, 0, timezone('Asia/Kolkata'))
print start
The output shown is
datetime.datetime(2011, 6, 20, 0, 0, tzinfo=<DstTzInfo 'Asia/Kolkata' HMT+5:53:00 STD>)
Note that 'Asia/Kolkata' is IST which is GMT+5:30 and not HMT+5:53. This is a standard linux timezone, why do I get this wrong, and how do I solve it?
See: http://bytes.com/topic/python/answers/676275-pytz-giving-incorrect-offset-timezone
In the comments, someone proposes to use tzinfo.localize()
instead of the datetime
constructor, which does the trick.
>>> tz = timezone('Asia/Kolkata')
>>> dt = tz.localize(datetime.datetime(2011, 6, 20, 0, 0, 0, 0))
>>> dt
datetime.datetime(2011, 6, 20, 0, 0, tzinfo=<DstTzInfo 'Asia/Kolkata' IST+5:30:00 STD>)
UPDATE: Actually, the official pytz website states that you should always use localize
or astimezone
instead of passing a timezone object to datetime.datetime
.
This has been fixed in python >=3.9 by the zoneinfo module in the standard library. The solution in >= 3.9 is probably to stop using pytz.
In [1]: import datetime
In [2]: from zoneinfo import ZoneInfo
In [3]: start = datetime.datetime(2011, 6, 20, 0, 0, 0, 0, ZoneInfo('Asia/Kolkata'))
In [4]: print(start)
2011-06-20 00:00:00+05:30
The reason for this extremely confusing behavior is that time zones used to not be standardized at :30 or :00 offsets. Around the turn of the 20th century most of them came into a standard offset. In the example in OP, the timezone switched in 1906. For US/Central, this happened in 1901.
from datetime import datetime, timedelta, date
from pytz import timezone
d = datetime.combine(date.today(), time.min)
for tz in ('Asia/Kolkata', "US/Central"):
while d > datetime(1800, 1, 1):
localized = timezone(tz).localize(d)
if localized.isoformat()[-2:] not in ("00", "30"):
print(tz)
print(localized.isoformat())
print(timezone(tz).localize(d + timedelta(days=1)).isoformat())
break
d -= timedelta(days=1)
That outputs:
Asia/Kolkata
1906-01-01T00:00:00+05:21
1906-01-02T00:00:00+05:30
US/Central
1901-12-13T00:00:00-05:51
1901-12-14T00:00:00-06:00
Pytz seems to just use the oldest offset when it doesn't have date information, even if it was a very long time ago. In some very natural constructions like passing tzinfo to the datetime constructor, the timezone object is not given that data.
精彩评论