【问题标题】:How to make pandas' timedeltas timezone aware?如何让熊猫的 timedeltas 时区感知?
【发布时间】:2020-11-07 16:08:09
【问题描述】:

如果我这样做

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 年 3 月 8 日是夏令时时钟向前移动的那一天,而这一天只有 23 小时时,这实际上是有道理的。但是我有一个用例,我想要一个始终为一个“本地时间”一天的时间增量。

那么有没有办法创建一个“本地时间感知”的 timedelta 对象,以便“1D”代表一个日历日,无论这一天是 23、24 还是 25 小时长?

【问题讨论】:

  • 您可以在 添加时间增量后进行本地化:(pd.to_datetime("2020-03-08") + pd.to_timedelta('1D')).tz_localize('America/New_York')
  • 这行得通,但是在我正在处理的代码的更广泛上下文中,当我使用每小时时间序列时会产生不良行为。每当我与时间打交道时,我都觉得我的头要爆炸了。
  • 再想一想,似乎还有一个问题:e.g. EST 的 2020-3-7 将有凌晨 2 点,而 2020-3-8 由于过渡到 EDT 而没有。因此,在 UTC/naive 中添加 1 天将起作用,但本地化将失败。
  • 是的,日期时间足够聪明,可以处理这些问题,我希望有一种方法可以让时间增量同样聪明,这样我就不必考虑这个问题了。

标签: python pandas datetime timezone


【解决方案1】:

您可以做的是比较时间戳的.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') 

【讨论】:

    猜你喜欢
    • 2014-05-19
    • 2012-03-30
    • 1970-01-01
    • 2013-05-13
    • 2018-12-12
    • 2016-11-26
    • 2013-11-15
    • 2016-09-30
    相关资源
    最近更新 更多