如何给带时区的时间戳加时间增量并适配夏令时(DST)
问题:带时区日期添加相对增量后无法自动适配夏令时?
我有一个datetime.datetime对象:
my_timestamp = datetime.datetime(2022, 2, 1, 0, 0)
通过以下代码将其转换为Europe/Amsterdam时区的时间对象:
import pytz my_datetime = pytz.timezone('Europe/Amsterdam').localize(my_timestamp)
得到的结果是对应CET时区的正确时间:
datetime.datetime(2022, 2, 1, 0, 0, tzinfo=<DstTzInfo 'Europe/Amsterdam' CET+1:00:00 STD>)
接下来需要给这个时间添加3个月的相对增量,使用了dateutil.relativedelta:
from dateutil.relativedelta import relativedelta my_datetime_with_offset = my_datetime + relativedelta(months = 3)
返回结果为:
datetime.datetime(2022, 5, 1, 0, 0, tzinfo=<DstTzInfo 'Europe/Amsterdam' CET+1:00:00 STD>)
但我期望它能自动适配夏令时(DST),返回CEST时区的对象:
datetime.datetime(2022, 5, 1, 0, 0, tzinfo=<DstTzInfo 'Europe/Amsterdam' CEST+2:00:00 DST>)
我找到了一种临时解决方法:
# 1. 创建带时区的时间戳 my_datetime = pytz.timezone('Europe/Amsterdam').localize(datetime(2022, 2, 1, 0, 0)) # 2. 保存时区信息 my_tz = my_datetime.tzinfo # 3. 转换为无时区对象并添加增量 my_datetime_with_offset = my_datetime.replace(tzinfo=None) + relativedelta(months = 3) # 4. 重新转换为带时区的时间戳 my_datetime_with_offset = my_tz.localize(my_datetime_with_offset) # 该方法有效
但这更像是临时的变通方案,我想知道基于datetime.datetime、pytz和dateutil的组合,有没有更规范的实现方式?
解决方案
方案1:使用标准库zoneinfo(推荐)
使用Python 3.9+自带的zoneinfo替代pytz,无需额外安装依赖,添加增量后会自动适配夏令时:
from zoneinfo import ZoneInfo # 标准库 from datetime import datetime from dateutil.relativedelta import relativedelta my_datetime = datetime(2022, 2, 1, 0, 0, tzinfo=ZoneInfo("Europe/Amsterdam")) my_datetime = my_datetime + relativedelta(months=3)
注意:此方案与pandas 1.4.4不兼容,若需配合旧版pandas使用,建议选择方案2。
方案2:沿用pytz规范,使用normalize方法
利用pytz的normalize方法修正时区信息,确保夏令时自动适配:
import pytz from datetime import datetime from dateutil.relativedelta import relativedelta my_datetime = pytz.timezone('Europe/Amsterdam').localize(datetime(2022, 2, 1, 0, 0)) my_tz = my_datetime.tzinfo my_datetime_with_offset = my_tz.normalize(my_datetime + relativedelta(months=3))
内容的提问来源于stack exchange,提问作者Silverwilly
相关产品推荐
相关产品推荐

