12

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

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

我正在努力寻找一种干净、高效和 Pythonic 的方式来让生成器跳过周末和节假日。提前致谢!

4

5 回答 5

27

我强烈建议将dateutil库用于此类任务。工作日的基本(忽略假期)迭代器就是:

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))
于 2012-07-18T21:11:58.220 回答
11

假设startDateandendDate是 datetime 或 date 对象,您可以使用weekday方法获取星期几,如果是星期六或星期日则跳过它。做就是了:

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)

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

于 2012-07-18T21:09:39.543 回答
9

Python pandas 有一个内置方法 bdate_range() ,默认频率为工作日。 https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.bdate_range.html

import pandas as pd
pd.bdate_range(start='1/25/2020', end='2/24/2020')
于 2020-03-06T22:28:43.187 回答
7

有一个有用的库叫做dateutil可以为你做这种事情。它可以生成日期范围(或基于自定义规则的日期),不包括某些日子,考虑从某一天开始的一周等......还具有比内置日期时间库更灵活的时间增量。

http://labix.org/python-dateutil/上的文档- 在 PyPi 上可用

于 2012-07-18T21:09:56.483 回答
1
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
于 2015-10-18T21:05:00.093 回答