Python构造时区感知日期时间

示例

默认情况下,所有datetime对象都是幼稚的。要使其具有时区意识,您必须附加一个tzinfo对象,该对象提供UTC偏移量和时区缩写作为日期和时间的函数。

固定偏移时区

对于与UTC有固定偏移量的时区,在Python 3.2+中,该datetime模块提供了timezone类的具体实现,该类tzinfo带有timedelta和一个(可选)name参数:

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秒
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() # 当地时间
PT = tz.gettz('US/Pacific') # 太平洋时间

dt_l = datetime(2015, 1, 1, 12, tzinfo=local) # 我在美国东部时间
dt_pst = datetime(2015, 1, 1, 12, tzinfo=PT)
dt_pdt = datetime(2015, 7, 1, 12, tzinfo=PT) # DST是自动处理的
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时区应该不是通过构造函数直接连接到时区。而是pytz应使用时区的localize方法附加时区:

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-aware时区上执行日期时间算术,则必须以UTC执行计算(如果您希望绝对经过的时间),或者必须调用normalize()结果:

dt_new = dt_pdt + timedelta(hours=3) # 这应该是太平洋标准时间上午2:30
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