构建时区感知日期时间
默认情况下,所有 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 版本,必须使用第三方库,例如 dateutil
。dateutil
提供了一个等价的类 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 标准库不提供标准类,因此必须使用第三方库。 pytz
和 dateutil
是提供时区类的热门库。
除静态时区外,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