【问题标题】:How to transform a list of business dates into a nested list of consecutives business dates?如何将营业日期列表转换为连续营业日期的嵌套列表?
【发布时间】:2022-02-20 08:05:10
【问题描述】:

我有一份工作日期列表,如下所示:

list_of_dates = ["15/02/2021", "16/02/2021", "17/02/2021",
                 "19/02/2021", "22/02/2021"," 23/02/2021"]

我想将其转换为连续期间的列表:

list_of_periods = [[start_date="15/02/2021", end_date="17/02/2021"], 
                   [start_date="19/02/2021", end_date="23/02/2021"]

因此,只要两个日期之间有一个或多个工作日,前一个时期就会结束,新时期就会开始。

我考虑过计算日期之间的差异。最好的方法是什么?

【问题讨论】:

  • 你怎么知道第一个周期的结束是"17/02/2021" 而不是"19/02/2021" 甚至是你列表的最后一个日期?
  • @jusstol,他在帖子中解释说:“因此,只要两个日期之间有一天或更多天,前一个时期就会结束,新时期就会开始。”
  • @jusstol 在"17/02/2021""19/02/2021" 之间有一天,它不在列表中,因此该周期结束"17/02/2021"
  • @LoicRW 糟糕,我看错了。

标签: python pandas


【解决方案1】:

要确定连续工作日的跨度,您需要添加周末(可能还包括带有 holidays= 参数的假期),这样您就可以检查所有日期之间是否有 1 天来组建您的小组。

首先将您的列表转换为一系列datetime64 值,然后连接您数据中的所有周末。排序并删除重复项。然后找到差异在哪里!=1 创建您的组,并且您希望最小值和最大值作为开始和结束。

import pandas as pd
list_of_dates = ["15/02/2021", "16/02/2021", "17/02/2021",
                 "19/02/2021", "22/02/2021", "23/02/2021"]

s = pd.Series(pd.to_datetime(list_of_dates, format='%d/%m/%Y'))
sweekend = pd.Series(pd.bdate_range(s.min(), end=s.max(), freq='C', 
                                    weekmask='Sat Sun', holidays=None))

s = pd.concat([s, sweekend]).drop_duplicates().sort_values()

gps = s.diff().dt.days.ne(1).cumsum()
s.to_frame().groupby(gps).agg(start_date=(0, min), end_date=(0, max))

  start_date   end_date
1 2021-02-15 2021-02-17
2 2021-02-19 2021-02-23

【讨论】:

  • 嗨,ALollz,感谢您的完美回复,也处理了非工作日问题!
  • 嘿,ALollz,由于一个奇怪的原因,我无法弄清楚,您的代码不适用于此列表:list_of_dates = ["20/11/2020","23/11/2020" ,"01/12/2020","02/12/2020","03/12/2020"] 完全一样的列表格式,不明白哪里出了问题。
  • @lostAtom 那是因为它与格式混淆了,因为天/月可能会变得模棱两可。在您的第一个案例中不是问题,因为所有天数都 > 12。您可以将第一行更改为 s = pd.Series(pd.to_datetime(list_of_dates, format='%d/%m/%Y')),它会知道将哪个值推断为日期以及将哪个值用作月份。我更新了解决方案以反映这一点。
【解决方案2】:

这似乎就是你要找的东西:Find group of consecutive dates in Pandas DataFrame

如果单个日期可以是它们自己的时期(例如,在您的示例中为 '19/02/2021'),则使用:

import numpy as np
import pandas as pd

list_of_dates = ["15/02/2021","16/02/2021","17/02/2021","19/02/2021","22/02/2021","23/02/2021"]
df = pd.DataFrame({'dates': list_of_dates})
df.dates = pd.to_datetime(df.dates)
day = pd.Timedelta('1d')

breaks = df.dates.diff() != day
groups = breaks.cumsum()
[{'start_date': df.dates[groups==i].iloc[0], 'end_date': df.dates[groups==i].iloc[-1]} 
for i in groups.unique()]

【讨论】:

  • 感谢洛伊克!但是 2021 年 2 月 19 日不被视为单个日期,因为它后面是 22/02/2021(工作日)。 Allolz 解决方案处理周末
【解决方案3】:

假设您的日期是 datetime.date,您可以减去它们并创建一个 timedelta 对象,它表示 2 个日期之间的天数:

from datetime import date

d0 = date(2008, 8, 18)
d1 = date(2008, 9, 26)
delta = d1 - d0
if delta.days >= 1:
  # make time period

https://docs.python.org/library/datetime.html

这不计入工作日。

【讨论】:

    猜你喜欢
    • 2020-08-11
    • 2021-07-17
    • 2020-11-18
    • 2016-11-23
    • 2019-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多