如何消除pandas.Timedelta本地化datetime时的操作顺序影响?
问题:时区操作顺序导致的偏移差异如何消除?
先对datetime()对象执行pandas.Timedelta()运算再本地化,能得到正确的日期、时间、时区及时区偏移;但先本地化datetime()对象再执行时间差运算,时区偏移会基于未感知时区的datetime()对象。原本以为操作顺序不会影响结果,请问如何消除这种顺序差异?
代码示例
import pandas import pytz import datetime unaware_date = datetime.datetime(2023,3,12,17) unaware_timedelta_date = unaware_date - pandas.Timedelta(weeks=110) aware_and_localized_unaware_timedelta_date = pytz.timezone('EST5EDT').localize(unaware_timedelta_date) print(aware_and_localized_unaware_timedelta_date) aware_and_localized_date = pytz.timezone('EST5EDT').localize(unaware_date) aware_and_localized_timedelta_date = aware_and_localized_date - pandas.Timedelta(weeks=110) print(aware_and_localized_timedelta_date)
输出结果
2021-01-31 17:00:00-05:00 2021-01-31 17:00:00-04:00
解决办法
问题根源在于pandas对pytz本地化的原生datetime对象处理逻辑存在缺陷:当对带pytz时区的datetime执行Timedelta运算时,pandas内部没有正确维护时区的夏令时/冬令时规则,导致运算后的时区偏移错误。
可以通过以下两种方式消除差异:
方式1:全程使用pandas的Timestamp和时区处理方法
用pd.Timestamp替代原生datetime,并用pandas内置的tz_localize方法做本地化,pandas能全程正确维护时区信息,无论操作顺序如何,结果都会一致:
import pandas as pd import datetime unaware_date = datetime.datetime(2023,3,12,17) # 先运算再本地化 unaware_timedelta_ts = pd.Timestamp(unaware_date) - pd.Timedelta(weeks=110) aware_ts1 = unaware_timedelta_ts.tz_localize('EST5EDT') print(aware_ts1) # 先本地化再运算 aware_ts2 = pd.Timestamp(unaware_date).tz_localize('EST5EDT') aware_timedelta_ts2 = aware_ts2 - pd.Timedelta(weeks=110) print(aware_timedelta_ts2)
输出结果(两者一致):
2021-01-31 17:00:00-05:00 2021-01-31 17:00:00-05:00
方式2:将本地化后的datetime转成pandas Timestamp再运算
如果必须保留pytz本地化的步骤,只需把本地化后的原生datetime对象转为pd.Timestamp,再执行时间差运算即可:
import pandas import pytz import datetime unaware_date = datetime.datetime(2023,3,12,17) # 原有正确逻辑 unaware_timedelta_date = unaware_date - pandas.Timedelta(weeks=110) aware_and_localized_unaware_timedelta_date = pytz.timezone('EST5EDT').localize(unaware_timedelta_date) print(aware_and_localized_unaware_timedelta_date) # 修改后的先本地化再运算逻辑 aware_and_localized_date = pytz.timezone('EST5EDT').localize(unaware_date) # 转成pandas Timestamp后再运算 aware_and_localized_timedelta_date = pandas.Timestamp(aware_and_localized_date) - pandas.Timedelta(weeks=110) print(aware_and_localized_timedelta_date)
输出结果同样一致。
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

