4

Here is the code which first parses time from string in IST and then converts that to UTC. So when it 4:00 pm in India the time in GMT / UTC is 10:30 am. While the following code prints it as 9:30 pm. So instead of subtracting the offset it is adding the offset. From the python documentation https://docs.python.org/2/library/datetime.html#datetime.datetime.astimezone the sample implementation of astimezone, it does appear that it would add the offset if it is negative but it seems contrary to what it should do. The documentation says that it adjusts the time such that UTC time remains same but in passed timezone's local time which is contrary to the sample implementation.

from dateutil.parser import parse
from pytz import timezone

d = parse('Tue Sep 01 2015 16:00:00 GMT+0530')

# Prints datetime.datetime(2015, 9, 1, 16, 0, tzinfo=tzoffset(None, -19800))
print d

utc = timezone('UTC')

# Prints datetime.datetime(2015, 9, 1, 21, 30, tzinfo=<UTC>)
print d.astimezone(utc)

I am not sure what is wrong. Is it the implementation of the astimezone or the documentation or the offset itself has its sign reversed?

Divick
  • 1,213
  • 1
  • 20
  • 44

2 Answers2

4

astimezone() is correct. parse() is incorrect or the input is ambiguous. parse() interprets GMT+0530 as being the deprecated POSIX-style GMT+h timezone format where the utc offset sign is reversed. See Timezone offset sign reversed by Python dateutil?

To fix it, use the opposite sign:

>>> from dateutil.parser import parse
>>> d = parse('Tue Sep 01 2015 16:00:00 GMT+0530')
>>> utc = d.replace(tzinfo=None) + d.utcoffset() #NOTE: the opposite sign
>>> utc
datetime.datetime(2015, 9, 1, 10, 30)

If the input may be unambiguous (when parse() returns correct results) then you should not change the utc offset sign by hand. You could strip the timezone and reapply it again instead:

>>> import pytz
>>> tz = pytz.timezone('Asia/Kolkata')
>>> tz.localize(parse('Tue Sep 01 2015 16:00:00 GMT+0530').replace(tzinfo=None), is_dst=None)
datetime.datetime(2015, 9, 1, 16, 0, tzinfo=<DstTzInfo 'Asia/Kolkata' IST+5:30:00 STD>)
>>> _.astimezone(pytz.utc)
datetime.datetime(2015, 9, 1, 10, 30, tzinfo=<UTC>)

It may fail for ambiguous or non-existent times (during DST transitions). If you know the input is in GMT+h format then use the 1st code example and convert to UTC manually instead.

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
0

Following snippet works fine.

>>> d = parse('Tue Sep 01 2014 16:00:00 GMT+0530')
>>> ind = timezone('Asia/Kolkata')
>>> d=d.replace(tzinfo=ind)
>>> d
datetime.datetime(2015, 9, 1, 16, 0, tzinfo=<DstTzInfo 'Asia/Kolkata' LMT+5:53:00 STD>)
>>> utc = timezone('UTC')
>>> d.astimezone(utc)
datetime.datetime(2015, 9, 1, 10, 7, tzinfo=<UTC>)

Here I have changed the tzinfo to be used in pytz format. Ensuring that all timezones are in pytz format.

Though, I am not sure why IST is LMT+5:53:00. Found out that offset changes over the years and +5:53 was used long back but now we use +5:30. But frankly I do not have much idea on this.

Barun Sharma
  • 1,452
  • 2
  • 15
  • 20
  • 1
    Because of politics, timezones will literally change from month to month. I found that there was a 2015.4 release of pytz which hopefully makes IST UTC+5:30. I can't get to the source from this netbook, sorry. – msw Sep 03 '15 at 12:08
  • 1
    @msw That's OK. But in that case India should have changed the the time in its clock. I, in India should have updated my watch, I did not as there was no official announcement from govt. If govt has not announced, why has pytz changed that? – Barun Sharma Sep 03 '15 at 12:15
  • 1
    As far as I can tell, all India went to IST upon Independence. There is a standard http://infostore.saiglobal.com/store/Details.aspx?ProductID=1055575 which allegedly conforms to UTC, but I don't have US$87 to find the answer. I'll look at the pytz source later and send a change request if appropriate. You've piqued my curiosity, thanks. – msw Sep 03 '15 at 12:33
  • 1
    You probably may not be able to send the change request for this. Check for "Issues & Limitations" section at https://pypi.python.org/pypi/pytz/2015.4 – Barun Sharma Sep 03 '15 at 12:38
  • @BarunSharma: I am using parse from python-dateutil package specifically so that it can parse the timezone correctly. Otherwise using a simple regular expression along with strptime would have sufficed. So replacing the timezone along with parse wouldn't work in a generic case where the timezone is supposed to be parsed. – Divick Sep 03 '15 at 15:25
  • @DivKis01 You have a valid point here. But you will have to figure out some way to convert the `tzoffset` to pytz timezone format. Anyway will check on my end and would post if I get something. – Barun Sharma Sep 04 '15 at 11:06
  • 2
    don't use `d.replace(tzinfo=pytz_tz)` Use `pytz_tz.localize()` instead (for naive datetime objects). – jfs Sep 04 '15 at 13:30