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?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
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.
Method 2
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.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0