64
>>> import pytz
>>> pytz.timezone('Asia/Hong_Kong')
<DstTzInfo 'Asia/Hong_Kong' LMT+7:37:00 STD>

A seven hour and 37 minute offset? This is a little strange, does anyone experience the same issue?

In fact I'm getting different behavior between

import pytz
from datetime import datetime
hk = pytz.timezone('Asia/Hong_Kong')

dt1 = datetime(2012,1,1,tzinfo=hk)
dt2 = hk.localize(datetime(2012,1,1))
if dt1 > dt2:
   print "Why?"
3

3 Answers 3

82
+50

Time zones and offsets change over the years. The default zone name and offset delivered when pytz creates a timezone object are the earliest ones available for that zone, and sometimes they can seem kind of strange. When you use localize to attach the zone to a date, the proper zone name and offset are substituted. Simply using the datetime constructor to attach the zone to the date doesn't allow it to adjust properly.

Sign up to request clarification or add additional context in comments.

Comments

27

Coming here nearly 10 years later, I think it's worth a note that we can now exclusively utilize the Python 3.9+ standard library to handle time zones, without a "localize trap".

Use the zoneinfo module to set and replace the tzinfo however you like, ex:

from datetime import datetime
from zoneinfo import ZoneInfo

hk = ZoneInfo('Asia/Hong_Kong')
print(repr(hk))
# zoneinfo.ZoneInfo(key='Asia/Hong_Kong')

dt1 = datetime(2012,1,1,tzinfo=hk)
print(dt1)
# 2012-01-01 00:00:00+08:00

# set tz to a naive datetime object (pytz localize):
dt2 = datetime(2012,1,1).replace(tzinfo=hk)
print(dt2)
# 2012-01-01 00:00:00+08:00

Notes

  • on Windows, make sure to have tzdata installed since Windows on its own does not provide the IANA database
  • there is a deprecation shim for pytz

Alternatives, if you're not able to use zoneinfo:

2 Comments

I think the interface between datetime and tzinfo was extended to allow this to work. When pytz was created it was stuck working the way it did.
@MarkRansom right, I think I remember having looked into this in the context of another question. So it's not just an additional library and done, it's a bit of an evolution.
20

While I'm sure historic changes in timezones are a factor, passing pytz timezone object to the DateTime constructor results in odd behavior even for timezones that have experienced no changes since their inception.

import datetime
import pytz 

dt = datetime.datetime(2020, 7, 15, 0, 0, tzinfo= pytz.timezone('US/Eastern'))

produces

2020-07-15 00:00:00-04:56

Creating the datetime object then localizing it produced expected results

import datetime
import pytz 

dt = datetime.datetime(2020, 7, 15, 0, 0)
dt_local = timezone('US/Eastern').localize(dt)

produces

2020-07-15 00:00:00-04:00

9 Comments

Prior to November 1883, there weren't any standard time zones in the US; time was local: en.wikipedia.org/wiki/Time_in_the_United_States#History. I expect that the timezone database is returning New York time.
If you look at example data from the Olson Database you can see that New York had an offset of 4:56:02 prior to 1883 November 18, 12:03:58. So it's incorrect that the New York time zone never changed.
I stand corrected. That would explain this behavior for datetimes in 1883, but not 2020
See my answer. The tzinfo object doesn't know what date you're going to use with it unless you use localize. For some reason pytz assumes 1883 is just as likely as 2020.
True but it is still reasonable to expect datetime to use the passed timezone object appropriately with the data parameters passed to its constructor.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.