python datetime.astimezone behavior incorrect?
Question: 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?


Answer: `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?](http://stackoverflow.com/q/31078749/4279)

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.

