You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么pandas的DateOffset.rollback()处理天、小时等频率不符合预期?

你的预期是合理的,问题根源是pandas内部的时间偏移分为两类,行为逻辑不统一,没有提供通用的「回退到对应频率起始偏移点」接口:

  • 第一类是锚定型偏移:包括BusinessMonthEnd、MonthEnd、MonthStart、YearBegin等,逻辑锚定在月/年的固定节点,freq.rollback()可以正确回退到上一个锚定点,但不会处理时分秒的截断。
  • 第二类是固定时长型偏移:包括Day、BusinessDay、Hour、周偏移等,rollback()的判定逻辑是只要时间落在对应周期范围内就认为已在偏移点,不会做起始点截断,而pd.Period.start_time刚好适配这类偏移的截断需求。

兼容所有场景的实现如下:

import pandas as pd
from pandas.tseries.offsets import *
from pandas.tseries.holiday import USFederalHolidayCalendar

def to_start(t: pd.Timestamp, freq: pd.DateOffset) -> pd.Timestamp:
    # 固定时长类偏移、自定义工作日偏移、周偏移用Period取周期起始点
    if isinstance(freq, (Tick, BusinessDay, CustomBusinessDay)) or freq.name.startswith("W-"):
        return pd.Period(t, freq=freq).start_time
    # 锚定型偏移用rollback逻辑,同时截断时分秒
    else:
        return freq.rollback(t).normalize()

# 以下所有断言均可通过
# 第一组锚定偏移测试
assert to_start(pd.to_datetime("2021-09-27"), MonthEnd()) == pd.to_datetime("2021-08-31")
assert to_start(pd.to_datetime("2021-09-27"), MonthBegin()) == pd.to_datetime("2021-08-31")
assert to_start(pd.to_datetime("2021-08-27"), BMonthEnd()) == pd.to_datetime("2021-07-30")
assert to_start(pd.to_datetime("2021-08-27"), YearBegin()) == pd.to_datetime("2021-01-01")
assert to_start(pd.to_datetime("2021-08-27"), BYearBegin()) == pd.to_datetime("2021-01-01")

# 节假日日历测试
us_fed_biz_days = CustomBusinessDay(calendar=USFederalHolidayCalendar())
memorial_day = pd.to_datetime("2021-05-31")
the_friday_before_memorial_day = pd.to_datetime("2021-05-28")
assert to_start(memorial_day, us_fed_biz_days) == the_friday_before_memorial_day

# 第二组固定时长偏移测试
assert to_start(pd.to_datetime("2021-08-27 05:00"), Day()) == pd.to_datetime("2021-08-27")
assert to_start(pd.to_datetime("2021-08-27 05:00"), BDay()) == pd.to_datetime("2021-08-27")
assert to_start(pd.to_datetime("2021-08-27 05:15"), Hour()) == pd.to_datetime("2021-08-27 05:00")
assert to_start(pd.to_datetime("2021-08-26"), pd.tseries.frequencies.to_offset("W-MON")) == pd.to_datetime("2021-08-24")

其中normalize()方法的作用是将时间的时分秒部分截断为0,匹配锚定偏移的常用使用习惯。


内容的提问来源于stack exchange,提问作者ilCatania

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 05:27:03