如何让 pandas' timedeltas 时区感知?
How to make pandas' timedeltas timezone aware?
如果我这样做
import pandas as pd
pd.to_datetime("2020-03-08") + pd.to_timedelta('1D')
我得到了预期的 Timestamp('2020-03-09 00:00:00')
。
但是当我尝试使用时区感知数据类型时..
pd.to_datetime("2020-03-08").tz_localize('America/New_York') + pd.to_timedelta('1D')
我得到 Timestamp('2020-03-09 01:00:00-0400', tz='America/New_York')
午夜后一小时。
当您意识到 2020-03-08 是夏令时时钟向前移动的那一天,而这一天只有 23 小时时,这实际上是有道理的。但是我有一个用例,我想要一个始终是“本地时间”一天的时间增量。
那么有没有一种方法可以创建“本地时间感知”timedelta 对象,以便“1D”代表一个日历日,无论这一天是 23、24 还是 25 小时?
您可以做的是比较时间戳的 .dst()
属性,如果 DST 转换介于两者之间,则调整 1 小时。您还必须注意添加 timedelta 会导致生成的时间戳恰好落在时区中不存在的小时的情况。
import pandas as pd
import pytz
def account_for_dst(t0, t1):
"""
adjust the timedelta between two timezone-aware timestamps t0 and t1
for DST transitions.
"""
# check if time delta would fall exactly on a DST transition:
dt = t1-t0
try:
_ = (t0.tz_localize(None)+dt).tz_localize(t0.tz)
except pytz.NonExistentTimeError:
return t0, t1 # t0 and t1 not modified...
# otherwise, adjust the time delta...
else:
if t0.dst() > t1.dst():
t1 += pd.to_timedelta('1H')
elif t0.dst() < t1.dst():
t1 -= pd.to_timedelta('1H')
return t0, t1
这会产生像
这样的模范结果
times = ("2020-3-7 02:00", "2020-3-8 00:00", "2020-11-1 00:00")
for t in times:
t0 = pd.to_datetime(t).tz_localize('America/New_York')
t1 = t0 + pd.to_timedelta('1D')
print(f"before: {str(t0), str(t1)}")
t0, t1 = account_for_dst(t0, t1)
print(f"after: {str(t0), str(t1)}\n")
# before: ('2020-03-07 02:00:00-05:00', '2020-03-08 03:00:00-04:00')
# after: ('2020-03-07 02:00:00-05:00', '2020-03-08 03:00:00-04:00')
# before: ('2020-03-08 00:00:00-05:00', '2020-03-09 01:00:00-04:00')
# after: ('2020-03-08 00:00:00-05:00', '2020-03-09 00:00:00-04:00')
# before: ('2020-11-01 00:00:00-04:00', '2020-11-01 23:00:00-05:00')
# after: ('2020-11-01 00:00:00-04:00', '2020-11-02 00:00:00-05:00')
如果我这样做
import pandas as pd
pd.to_datetime("2020-03-08") + pd.to_timedelta('1D')
我得到了预期的 Timestamp('2020-03-09 00:00:00')
。
但是当我尝试使用时区感知数据类型时..
pd.to_datetime("2020-03-08").tz_localize('America/New_York') + pd.to_timedelta('1D')
我得到 Timestamp('2020-03-09 01:00:00-0400', tz='America/New_York')
午夜后一小时。
当您意识到 2020-03-08 是夏令时时钟向前移动的那一天,而这一天只有 23 小时时,这实际上是有道理的。但是我有一个用例,我想要一个始终是“本地时间”一天的时间增量。
那么有没有一种方法可以创建“本地时间感知”timedelta 对象,以便“1D”代表一个日历日,无论这一天是 23、24 还是 25 小时?
您可以做的是比较时间戳的 .dst()
属性,如果 DST 转换介于两者之间,则调整 1 小时。您还必须注意添加 timedelta 会导致生成的时间戳恰好落在时区中不存在的小时的情况。
import pandas as pd
import pytz
def account_for_dst(t0, t1):
"""
adjust the timedelta between two timezone-aware timestamps t0 and t1
for DST transitions.
"""
# check if time delta would fall exactly on a DST transition:
dt = t1-t0
try:
_ = (t0.tz_localize(None)+dt).tz_localize(t0.tz)
except pytz.NonExistentTimeError:
return t0, t1 # t0 and t1 not modified...
# otherwise, adjust the time delta...
else:
if t0.dst() > t1.dst():
t1 += pd.to_timedelta('1H')
elif t0.dst() < t1.dst():
t1 -= pd.to_timedelta('1H')
return t0, t1
这会产生像
这样的模范结果times = ("2020-3-7 02:00", "2020-3-8 00:00", "2020-11-1 00:00")
for t in times:
t0 = pd.to_datetime(t).tz_localize('America/New_York')
t1 = t0 + pd.to_timedelta('1D')
print(f"before: {str(t0), str(t1)}")
t0, t1 = account_for_dst(t0, t1)
print(f"after: {str(t0), str(t1)}\n")
# before: ('2020-03-07 02:00:00-05:00', '2020-03-08 03:00:00-04:00')
# after: ('2020-03-07 02:00:00-05:00', '2020-03-08 03:00:00-04:00')
# before: ('2020-03-08 00:00:00-05:00', '2020-03-09 01:00:00-04:00')
# after: ('2020-03-08 00:00:00-05:00', '2020-03-09 00:00:00-04:00')
# before: ('2020-11-01 00:00:00-04:00', '2020-11-01 23:00:00-05:00')
# after: ('2020-11-01 00:00:00-04:00', '2020-11-02 00:00:00-05:00')