Python/Pandas:查找将假期考虑在内的日期时间的自定义业务季度结束

Posted

技术标签:

【中文标题】Python/Pandas:查找将假期考虑在内的日期时间的自定义业务季度结束【英文标题】:Python/Pandas: Find the Custom Business Quarter End of a datetime which takes holidays into account 【发布时间】:2021-10-21 11:40:11 【问题描述】:

我想在 python 中找到一个日期时间的商业季度结束,这也将照顾假期。为简单起见,这些假期可以作为列表传递。我从pandas.tseries.offsets 知道BQuarterEnd()。据我所知,它没有考虑假期。

示例:如果 2020-11-20 已通过,而 2020-12-31 是工作日但也是假期;它应该返回2020-12-30

谢谢。

【问题讨论】:

【参考方案1】:

在 Pandas 中,有一组 Custom business days 函数,您可以在其中定义自己的假期列表,然后这些函数会根据自定义假期列表为您计算正确的日期偏移量。

例如,我们有CustomBusinessMonthEnd(更好的文档here)。很遗憾,季度末没有对应的CustomBusinessQuarterEnd (Custom Business QuarterEnd)函数。

但是,我们仍然可以获得一些变通解决方案,如下所示:

    定义您的自定义假期列表,例如:
holiday_list = ['2020-12-31']
    使用QuarterEnd + CustomBusinessMonthEnd 的组合来获取Custom Business QuarterEnd 跳过假期所需的日期:
import pandas as pd

base_date = pd.to_datetime('2020-11-20')   # Base date

custom_business_quarter_end = (base_date 
                                   + pd.offsets.QuarterEnd(n=0) 
                                   - pd.offsets.MonthBegin() 
                                   + pd.offsets.CustomBusinessMonthEnd(holidays=holiday_list))

首先,我们将您的基准日期添加到QuarterEnd 以获得季度结束日期(不考虑节假日)。然后,为了让 Custom Business QuarterEnd 跳过节假日,我们使用 CustomBusinessMonthEnd 传递节假日列表作为参数来调整节假日。

对于QuarterEnd,我们传递参数n=0 来处理基准日期已经在季度结束日期的极端情况。我们避免QuarterEnd 将本季度结束日期滚动到下一个季度结束日期。您可以参考官方文档here 了解更多关于 Pandas 如何处理落在锚定日期上的日期(参见以“对于 n=0 时的情况,...”开头的小节)

我们也先使用MonthBegin,然后再调用CustomBusinessMonthEnd。这是为了避免将月末锚点的一天滚动到下个月。我们需要这个,因为n=0 参数对CustomBusinessMonthEnd 的工作方式与QuarterEnd 的工作方式不同,以避免翻转。因此,这个额外的减号MonthBegin 是必需的。使用MonthBegin,我们先得到季度末的月份开始日期,即2020-12-01,然后得到自定义的业务月末日期。这样我们就可以避免QuarterEnd的结果,例如2020-12-31 被滚动到下个月底,例如直接调用CustomBusinessMonthEnd2021-01-31

结果:

print(custom_business_quarter_end)

2020-12-30 00:00:00

【讨论】:

这很棒。谢谢。一些边缘情况对我来说失败了。一,当基准日期不是业务日期时,例如2022-12-31,它给出2023-03-31,但预期是2022-12-30。在这种情况下,为简单起见,假期列表为空。也许 QuarterEnd() 而不是 BQuarterEnd 可以完成这项工作。另一种没有给出所需输出的情况:假设给定日期是 BQuarterEnd 并且也是假期。例如2020-12-31 是基准日期和假期。它给了2021-03-31 @ParasGupta 感谢您进行彻底的测试并建议边缘情况。对于边缘情况,我们可以在调用BQuarterEnd 之前进一步获取以MonthBegin 开头的月份。这将与我们在调用 CustomBusinessMonthEnd 之前最初使用 MonthBegin 的方式相同,以避免在月末锚定日期出现不必要的滚动。您可以查看并重试。让我知道结果。谢谢! @ParasGupta 我已经用新添加的MonthBegin 进一步微调了代码以传递参数n=0 以确保基准日期是一个月的第一天,它不会回滚到上个月。请尝试使用最新的代码。 @ParasGupta 使用QuarterEnd 而不是BQuarterEnd 并将参数n=0 传递给QuarterEnd,从而稍微简化了代码。希望这应该是最终版本。 谢谢。我还用你的线索搞乱了QuarterEnd。这个完美无缺。太好了!!【参考方案2】:

您可能需要一个自定义函数。可能是这样的:

def custom_quarter_end(date, holidays=[]):
    holidays = [pd.Timestamp(h) for h in holidays]
    end = pd.Timestamp(date)+pd.tseries.offsets.BQuarterEnd()
    while end in holidays:
        end = end - pd.tseries.offsets.BDay()
    return end

>>> custom_quarter_end("2020-11-20", ["2020-12-30", "2020-12-31"])
Timestamp('2020-12-29 00:00:00')

【讨论】:

以上是关于Python/Pandas:查找将假期考虑在内的日期时间的自定义业务季度结束的主要内容,如果未能解决你的问题,请参考以下文章

计算包括节假日在内的工作日

Python pandas:连接列查找

pandas / python中的最佳数据库查找和更新

Python Pandas - 查找具有最大聚合值的连续组

Python pandas:查找两列的余弦相似度

我可以将 SQL Server (=MS SQL) 中的表导入 Python / Pandas 数据框吗?