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')