构建时区感知日期时间

默认情况下,所有 datetime 对象都是天真的。要使它们能够识别时区,必须附加 tzinfo 对象,该对象提供 UTC 偏移和时区缩写作为日期和时间的函数。

固定偏移时区

对于与 UTC 固定偏移的时区,在 Python 3.2+中,datetime 模块提供 timezone 类,tzinfo 的具体实现,它采用 timedelta 和(可选)名称参数:

Python 3.x >= 3.2

from datetime import datetime, timedelta, timezone
JST = timezone(timedelta(hours=+9))

dt = datetime(2015, 1, 1, 12, 0, 0, tzinfo=JST)
print(dt)
# 2015-01-01 12:00:00+09:00

print(dt.tzname())
# UTC+09:00

dt = datetime(2015, 1, 1, 12, 0, 0, tzinfo=timezone(timedelta(hours=9), 'JST'))
print(dt.tzname)
# 'JST'

对于 3.2 之前的 Python 版本,必须使用第三方库,例如 dateutildateutil 提供了一个等价的类 tzoffset,它(从版本 2.5.3 开始)接受 dateutil.tz.tzoffset(tzname, offset) 形式的参数,其中 offset 以秒为单位指定:

Python 3.x < 3.2

Python 2.x < 2.7

from datetime import datetime, timedelta
from dateutil import tz

JST = tz.tzoffset('JST', 9 * 3600) # 3600 seconds per hour
dt = datetime(2015, 1, 1, 12, 0, tzinfo=JST)
print(dt)
# 2015-01-01 12:00:00+09:00
print(dt.tzname)
# 'JST'

夏令时的区域

对于具有夏令时的区域,python 标准库不提供标准类,因此必须使用第三方库。 pytzdateutil 是提供时区类的热门库。

除静态时区外,dateutil 还提供使用夏令时的时区类(请参阅 tz 模块的文档 )。你可以使用 tz.gettz() 方法获取时区对象,然后可以将其直接传递给 datetime 构造函数:

from datetime import datetime
from dateutil import tz
local = tz.gettz() # Local time
PT = tz.gettz('US/Pacific') # Pacific time

dt_l = datetime(2015, 1, 1, 12, tzinfo=local) # I am in EST
dt_pst = datetime(2015, 1, 1, 12, tzinfo=PT)
dt_pdt = datetime(2015, 7, 1, 12, tzinfo=PT) # DST is handled automatically
print(dt_l)
# 2015-01-01 12:00:00-05:00
print(dt_pst)
# 2015-01-01 12:00:00-08:00
print(dt_pdt)
# 2015-07-01 12:00:00-07:00

注意 :从版本 2.5.3 开始,dateutil 无法正确处理模糊日期时间,并且始终默认为较晚的日期。没有办法构造一个具有 dateutil 时区的对象,例如 2015-11-01 1:30 EDT-4,因为这是夏令时转换期间。

使用 pytz 时,所有的边缘案件得到妥善处理,但 pytz 时区应该不是通过构造函数直接连接到时区。相反,应使用时区的 localize 方法附加 pytz 时区:

from datetime import datetime, timedelta
import pytz

PT = pytz.timezone('US/Pacific')
dt_pst = PT.localize(datetime(2015, 1, 1, 12))
dt_pdt = PT.localize(datetime(2015, 11, 1, 0, 30))
print(dt_pst)
# 2015-01-01 12:00:00-08:00
print(dt_pdt)
# 2015-11-01 00:30:00-07:00

请注意,如果在支持 pytz 的时区上执行日期时算术,则必须以 UTC 格式执行计算(如果需要绝对经过时间),或者必须在结果上调用 normalize()

dt_new = dt_pdt + timedelta(hours=3) # This should be 2:30 AM PST
print(dt_new)
# 2015-11-01 03:30:00-07:00
dt_corrected = PT.normalize(dt_new)
print(dt_corrected)
# 2015-11-01 02:30:00-08:00