Python日期范围生成器(超过工作日)

Python日期范围生成器(超过工作日),python,Python,我正在尝试创建一个生成器函数来迭代工作日(工作日),跳过周末(假期也不错!)。到目前为止,我只有一个函数可以简单地迭代几天: def daterange(startDate, endDate): for i in xrange(int((endDate - startDate).days)): yield startDate + timedelta(i) 我正在努力寻找一种干净、高效、符合Python风格的方法,让发电机在周末和节假日都能正常工作。提前谢谢 假设star

我正在尝试创建一个生成器函数来迭代工作日(工作日),跳过周末(假期也不错!)。到目前为止,我只有一个函数可以简单地迭代几天:

def daterange(startDate, endDate):
    for i in xrange(int((endDate - startDate).days)):
        yield startDate + timedelta(i)

我正在努力寻找一种干净、高效、符合Python风格的方法,让发电机在周末和节假日都能正常工作。提前谢谢

假设
startDate
endDate
是日期时间或日期对象,您可以使用来获取一周中的某一天,如果是星期六或星期日,则跳过它。只要做:

def daterange(startDate, endDate):
    for i in xrange(int((endDate - startDate).days)):
        nextDate = startDate + timedelta(i)
        if nextDate.weekday() not in (5, 6):
            yield startDate + timedelta(i)

对于假期,您必须手动检查您想要的每个假期。有些假期是以复杂的方式定义的,所以这可能有点棘手。

有一个名为
dateutil
的有用库,可以为您做这类事情。它可以生成日期范围(或基于自定义规则的日期),不包括某些天,考虑从一天开始的一周等等。还有一个比内置datetime库更灵活的timedelta


PyPi上提供的文档,我强烈建议您使用该库执行此类任务。工作日内的基本(不忽略节假日)迭代器就是:

from dateutil.rrule import DAILY, rrule, MO, TU, WE, TH, FR

def daterange(start_date, end_date):
  return rrule(DAILY, dtstart=start_date, until=end_date, byweekday=(MO,TU,WE,TH,FR))
def get_date_range(开始、结束、工作日=None、假日=None、跳过非工作日=True):
"""
此函数计算跳过非工作日和指定假日的两个日期之间的持续时间
:rtype:tuple
:参数开始:日期
:参数结束:日期
:param workdays:string[逗号分隔的值,0-周一到6-周日,例如“0,1,2,3,4”]
:参数假日:列表
:参数跳过非工作日:布尔值
:返回:
"""
从日期时间导入时间增量
持续时间=0
#定义工作日
如果无工作日:
工作日=[0,1,2,3,4]
其他:
工作日=工作日。拆分(“,”)
#检查我们是否需要跳过非工作日
如果跳过非工作日为假:
工作日=[0,1,2,3,4,5,6]
#验证日期
如果结束<开始:
返回False,“结束日期早于开始日期”
#现在是我们迭代的时候了
i=开始

而Python有一个内置方法bdate_range(),默认频率为工作日。


在假期里看这个问题:这真的符合你说的吗?我在Linux和Mac OS上的Python2.7和3.3上尝试过它,在所有情况下,它都会返回所有天,包括周末。如果您查看
dateutil.rrule.WDAYMASK
,您可能会看到它是一个0-6的列表,即所有天,而不仅仅是星期一到星期五。@JohnZwinck对,WDAYMASK确实不正确(至少在当前版本的dateutil中是这样)。我更新了答案以反映这一点。请使用dateutil.rrule import*
中的
,否则您将得到错误,因为MO未标识dateutil不支持向后迭代,以防您有此用例。显然,作者认为这并不重要。
def get_date_range(start, end, workdays=None, holidays=None, skip_non_workdays=True):
"""
This function calculates the durations between 2 dates skipping non workdays and holidays as specified
:rtype : tuple
:param start: date
:param end: date
:param workdays: string [Comma Separated Values, 0 - Monday through to 6 - Sunday e.g "0,1,2,3,4"]
:param holidays: list
:param skip_non_workdays: boolean
:return:
"""
from datetime import timedelta

duration = 0

# define workdays
if workdays is None:
    workdays = [0, 1, 2, 3, 4]
else:
    workdays = workdays.split(",")

# check if we need to skip non workdays
if skip_non_workdays is False:
    workdays = [0, 1, 2, 3, 4, 5, 6]

# validate dates
if end < start:
    return False, "End date is before start date"

# now its time for us to iterate
i = start
while i <= end:

    # first let's give benefit of the doubt
    incr = True

    # lets see if day is in the workday array if not then fault it's existence here
    try:
        workdays.index(i.weekday())
    except ValueError:
        incr = False

    # lets check if day is an holiday, charge guilty if so.
    # We are checking the index in holiday array
    try:
        holidays.index(i)
        incr = False
    except (ValueError, AttributeError):
        pass

    if incr:
        duration += 1
        print "This day passed the criterion %s" % i

    i += timedelta(1)

return True, duration
import pandas as pd
pd.bdate_range(start='1/25/2020', end='2/24/2020')