Python Datetime Object Show Wrong Timezone Offset

Python datetime object show wrong timezone offset

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.

Python timezone offset wrong?

Instead of assigning the tzinfo parameter, use the localize method from pytz.

tz = get_localzone()
date = tz.localize(datetime(2015, 6, 17, 14, 58, 45))

This is discussed prominently in the pytz documentation, starting with the the first "Note" box, and in the very first code sample.

It's also shown in the tzlocal documentation, which is where (I assume) your get_localzone() method is coming from.

FYI, the -05:51 offset comes from the original LMT value of the America/Chicago time zone, which is -05:50:36 and is assumed to have been in use way back in 1883 as shown here. It's rounded to the nearest minute, giving the -05:51 LMT value in Python. You are seeing that offset because the localize method wasn't called, so pytz is just using the first offset known to that time zone's entry.

creating a timezone aware datetime object returns a wrong timezone

It is mentioned in the docs that constructing datetime objects doesn't work this way.

You are supposed to do this:

from datetime import datetime

from pytz import timezone

eastern = timezone('US/Eastern')
obj = eastern.localize(datetime(2020, 7, 1, 9, 30))
>>> obj
datetime.datetime(2020, 7, 1, 9, 30, tzinfo=<DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST>)
>>> print(obj)
2020-07-01 09:30:00-04:00

isoformat function of datetime module in python returns incorrect offset

It's almost always wrong to just tack on a pytz instance for the tzinfo when creating a datetime. The correct way to convert a naive datetime into a timezone aware instance using pytz is with the zone's localize method:

zone.localize(dt)

Output for your case:

>>> print(timezone.localize(zoned_time_stamp))
2017-06-01 05:30:00+05:30

It's quite clearly documented that passing a pytz instance in tzinfo is not a supported way of creating a localized datetime. However, that's also such a commonly seen mistake in Python code - guess many users don't read the docs!

To understand why the incorrect approach showed what it did (weird +05:53 offset), refer to pytz: The Fastest Footgun in the West by Paul Ganssle.

datetuil results in wrong utc offset when using lower case

The dateutil library, by default, diverges from POSIX-style time zones, which "use an inverted offset format, so normally GMT+3 would be parsed as an offset 3 hours behind GMT. The tzstr time zone object will parse this as an offset 3 hours ahead of GMT" (dateutil documentation on dateutil.tz.tzstr()).

The library determines when to invert the offset by checking if your timezone abbreviation is either "UTC" or "GMT" (case sensitive), then multiplies the offset by -1. Because the check is case sensitive, the offset for "UTC-6" does properly get offset to -0600 but "utc-6" does not (tzstr source code).

# Here we break the compatibility with the TZ variable handling.
# GMT-3 actually *means* the timezone -3.
if res.stdabbr in ("GMT", "UTC") and not posix_offset:
res.stdoffset *= -1

Regardless of if this was an intentional decision, with the current tzstr implementation, you should uppercase your timezone strings before passing them in to gettz().

pytz giving wrong timezone offset for 'Africa/Khartoum'

I cannot reproduce the example for datetime.datetime.now. pytz also shows the correct UTC offset change in 2017 for the timezone 'Africa/Khartoum'. However, you need to use the localize method (see e.g. here).

import datetime
import pytz

tz = pytz.timezone('Africa/Khartoum')

# correct UTC offset for "now":
tz_offset = tz.localize(datetime.datetime.now()).strftime('%z')
print(tz_offset)
# +0200

# also correct UTC offset around 1st Nov 2017:
tz_offset = tz.localize(datetime.datetime(2017,10,31)).strftime('%z')
print(tz_offset)
# +0300
tz_offset = tz.localize(datetime.datetime(2017,11,1)).strftime('%z')
print(tz_offset)
# +0200

If you don't localize, you only get the local mean time. With dateutil, you would not have to localize and could implement the timezone directly:

import dateutil
tz = dateutil.tz.gettz('Africa/Khartoum')
tz_offset = datetime.datetime(2017,10,31, tzinfo=tz).strftime('%z')
print(tz_offset)
# +0300
tz_offset = datetime.datetime(2017,11,1, tzinfo=tz).strftime('%z')
print(tz_offset)
# +0200


Related Topics



Leave a reply



Submit