Python 两个日期之间的天数,不包括周末
如何计算两个日期之间的天数(周末除外)Python 两个日期之间的天数,不包括周末,python,datetime,Python,Datetime,如何计算两个日期之间的天数(周末除外) import datetime # some givens dateB = datetime.date(2010, 8, 31) dateA = datetime.date(2010, 7, 8) delta = datetime.timedelta(1) # number of days days = 0 while dateB != dateA: #subtract a day dateB -= delta # if n
import datetime
# some givens
dateB = datetime.date(2010, 8, 31)
dateA = datetime.date(2010, 7, 8)
delta = datetime.timedelta(1)
# number of days
days = 0
while dateB != dateA:
#subtract a day
dateB -= delta
# if not saturday or sunday, add to count
if dateB.isoweekday() not in (6, 7):
days += 1
我想这样的办法应该行得通。我现在没有工具来测试它。>>从datetime导入日期,timedelta
>>> from datetime import date,timedelta
>>> fromdate = date(2010,1,1)
>>> todate = date(2010,3,31)
>>> daygenerator = (fromdate + timedelta(x + 1) for x in xrange((todate - fromdate).days))
>>> sum(1 for day in daygenerator if day.weekday() < 5)
63
>>>fromdate=日期(2010,1,1)
>>>todate=日期(2010年3月31日)
>>>daygenerator=(xrange((todate-fromdate).days)中x的fromdate+timedelta(x+1))
>>>总和(如果day.weekday()小于5,则daygenerator中的天为1)
63
这是从fromdate
到todate
获取的
然后我们可以从生成器中创建一个列表,使用筛选出周末,列表的大小给出了我们想要的天数。然而,为了避免在内存中保存整个列表,如果日期相隔很长时间,这可能会成为一个问题,我们使用另一个生成器表达式过滤掉周末,但返回1而不是每个日期。而不必存储整个列表
注意,如果
fromdate==todate
这将计算0而不是1。到目前为止给出的答案是有效的,但是如果日期相距太远(由于循环),则效率非常低
这应该起作用:
import datetime
start = datetime.date(2010,1,1)
end = datetime.date(2010,3,31)
daydiff = end.weekday() - start.weekday()
days = ((end-start).days - daydiff) / 7 * 5 + min(daydiff,5) - (max(end.weekday() - 4, 0) % 5)
这将把它转换为整周(有5个工作日),然后处理剩余的几天。固定周六到周日同一个周末运行
from __future__ import print_function
from datetime import date, timedelta
def workdaycount(startdate,enddate):
if startdate.year != enddate.year:
raise ValueError("Dates to workdaycount must be during same year")
if startdate == enddate:
return int(startdate.weekday() < 5)
elif (enddate - startdate).days == 1 and enddate.weekday() == 6: # Saturday and Sunday same weekend
return 0
first_week_workdays = min(startdate.weekday(), 4) + 1
last_week_workdays = min(enddate.weekday(), 4) + 1
workweeks = int(enddate.strftime('%W')) - int(startdate.strftime('%W'))
return (5 * workweeks) + last_week_workdays - first_week_workdays + 1
for comment, start,end in (
("Two dates same weekend:", date(2010,9,18), date(2010,9,19)),
("Same dates during weekend:", date(2010,9,19), date(2010,9,19)),
("Same dates during week", date(2010,9,16), date(2010,9,16)),
("Dates during same week", date(2010,9,13), date(2010,9,16)),
("Dates during following weeks", date(2010,9,7), date(2010,9,16)),
("Dates after two weeks", date(2010,9,7), date(2010,9,24)),
("Dates from other solution", date(2010,1, 1), date(2010, 3,31))):
daydiff = end.weekday() - start.weekday()
days = ((end-start).days - daydiff) / 7 * 5 + min(daydiff,5)
daygenerator = (start + timedelta(x + 1) for x in xrange((end - start).days))
gendays = sum(day.weekday() < 5 for day in daygenerator)
print(comment,start,end,workdaycount(start,end))
print('Other formula:', days, '. Generator formula: ', gendays)
from\uuuuu future\uuuuu导入打印功能
从日期时间导入日期,时间增量
def workdaycount(开始日期、结束日期):
如果开始日期。年份!=enddate.year:
raise VALUE ERROR(“工作日计数的日期必须在同一年内”)
如果startdate==enddate:
返回int(startdate.weekday()<5)
elif(enddate-startdate).days==1和enddate.weekday()==6:#周六和周日同一周末
返回0
第一周工作日=min(startdate.weekday(),4)+1
上周工作日=min(enddate.weekday(),4)+1
工作周=int(enddate.strftime('%W'))-int(startdate.strftime('%W'))
返回(5*工作周)+上周工作日-第一周工作日+1
如需评论,请以开头和结尾(
(“同一周末的两个日期:”,日期(2010,9,18),日期(2010,9,19)),
(“周末期间的相同日期:”,日期(2010,9,19),日期(2010,9,19)),
(“一周内的相同日期”、日期(2010,9,16)、日期(2010,9,16)),
(“同一周内的日期”、日期(2010,9,13)、日期(2010,9,16)),
(“随后几周内的日期”、日期(2010,9,7)、日期(2010,9,16)),
(“两周后的日期”、日期(2010,9,7)、日期(2010,9,24)),
(“其他解决方案的日期”,日期(2010年1月1日),日期(2010年3月31日)):
daydiff=end.weekday()-start.weekday()
天数=((结束-开始).days-daydiff)/7*5+分钟(daydiff,5)
daygenerator=(开始+时间增量(x+1)表示x范围内的x((结束-开始).days))
gendays=总和(day.weekday()<5表示day中的day生成器)
打印(注释、开始、结束、工作日计数(开始、结束))
打印('其他公式:',天'。生成器公式:',天)
懒惰的方法是pip安装workdays
以获得能够实现这一点的python包
我尝试了前两个答案(戴夫·韦伯和尼尔的),但由于某种原因,这两个答案都不正确。这可能是我的一个错误,但我选择了现有的库,因为它可能有更多的功能,并且在边缘情况下测试得更好:
我将Dave Webb的答案改编成一个函数,并添加了一些测试用例:
import datetime
def weekdays_between(start, end):
return sum([1 for daydelta in xrange(1, (end - start).days + 1)
if (start + datetime.timedelta(daydelta)).weekday() < 5])
assert 7 == weekdays_between(
datetime.date(2014,2,19),
datetime.date(2014,3,1))
assert 1 == weekdays_between(
datetime.date(2014,2,19),
datetime.date(2014,2,20))
assert 2 == weekdays_between(
datetime.date(2014,2,19),
datetime.date(2014,2,22))
assert 2 == weekdays_between(
datetime.date(2014,2,19),
datetime.date(2014,2,23))
assert 3 == weekdays_between(
datetime.date(2014,2,19),
datetime.date(2014,2,24))
assert 1 == weekdays_between(
datetime.date(2014,2,21),
datetime.date(2014,2,24))
assert 1 == weekdays_between(
datetime.date(2014,2,22),
datetime.date(2014,2,24))
assert 2 == weekdays_between(
datetime.date(2014,2,23),
datetime.date(2014,2,25))
导入日期时间
def工作日之间(开始、结束):
返回和([1表示xrange中的daydelta(1,(结束-开始)。天数+1)
if(start+datetime.timedelta(dayddelta)).weekday()<5])
断言7==工作日与(
日期时间。日期(2014年2月19日),
日期时间。日期(2014年3月1日)
断言1==工作日与(
日期时间。日期(2014年2月19日),
日期时间。日期(2014年2月20日)
断言2==工作日与(
日期时间。日期(2014年2月19日),
日期时间。日期(2014年2月22日)
断言2==工作日与(
日期时间。日期(2014年2月19日),
日期时间。日期(2014年2月23日)
断言3==工作日与(
日期时间。日期(2014年2月19日),
日期时间。日期(2014年2月24日)
断言1==工作日与(
日期时间。日期(2014年2月21日),
日期时间。日期(2014年2月24日)
断言1==工作日与(
日期时间。日期(2014年2月22日),
日期时间。日期(2014年2月24日)
断言2==工作日与(
日期时间。日期(2014年2月23日),
日期时间。日期(2014年2月25日)
我认为最干净的解决方案是使用numpy函数busday\u count
import numpy as np
import datetime as dt
start = dt.date( 2014, 1, 1 )
end = dt.date( 2014, 1, 16 )
days = np.busday_count( start, end )
请注意,@neil的(否则很棒的)代码将在周日到周四的时间间隔内失败。这里有一个修正:
def working_days_in_range(from_date, to_date):
from_weekday = from_date.weekday()
to_weekday = to_date.weekday()
# If start date is after Friday, modify it to Monday
if from_weekday > 4:
from_weekday = 0
day_diff = to_weekday - from_weekday
whole_weeks = ((to_date - from_date).days - day_diff) / 7
workdays_in_whole_weeks = whole_weeks * 5
beginning_end_correction = min(day_diff, 5) - (max(to_weekday - 4, 0) % 5)
working_days = workdays_in_whole_weeks + beginning_end_correction
# Final sanity check (i.e. if the entire range is weekends)
return max(0, working_days)
这是我实现的一个函数,用于测量跨分支集成代码需要多少工作日。它不需要像其他解决方案那样迭代整个中间天,只需要在第一周迭代 此问题可分为两个不同的问题:
(todate-fromdate)/7
求和(map(is_weekend,rem_days))
>>> for i in range(10): latency(datetime.now(), datetime.now() + timedelta(days=i))
...
0 1 1 1 2 3 4 5 6 6
在PyPi中使用名为businessduration的包 示例代码: Out[6]:62.99927083333
第一次导入
numpy
为np
。函数np.busday\u count
统计两个日期之间的有效天数,不包括结束日期的日期
如果结束日期早于开始日期,则计数将为负数。有关np.busday\u计数的更多信息,请阅读文档
请注意,函数接受字符串,在调用函数之前不必实例化datetime
对象
from __future__ import print_function
from datetime import date, timedelta
def workdaycount(startdate,enddate):
if startdate.year != enddate.year:
raise ValueError("Dates to workdaycount must be during same year")
if startdate == enddate:
return int(startdate.weekday() < 5)
elif (enddate - startdate).days == 1 and enddate.weekday() == 6: # Saturday and Sunday same weekend
return 0
first_week_workdays = min(startdate.weekday(), 4) + 1
last_week_workdays = min(enddate.weekday(), 4) + 1
workweeks = int(enddate.strftime('%W')) - int(startdate.strftime('%W'))
return (5 * workweeks) + last_week_workdays - first_week_workdays + 1
for comment, start,end in (
("Two dates same weekend:", date(2010,9,18), date(2010,9,19)),
("Same dates during weekend:", date(2010,9,19), date(2010,9,19)),
("Same dates during week", date(2010,9,16), date(2010,9,16)),
("Dates during same week", date(2010,9,13), date(2010,9,16)),
("Dates during following weeks", date(2010,9,7), date(2010,9,16)),
("Dates after two weeks", date(2010,9,7), date(2010,9,24)),
("Dates from other solution", date(2010,1, 1), date(2010, 3,31))):
daydiff = end.weekday() - start.weekday()
days = ((end-start).days - daydiff) / 7 * 5 + min(daydiff,5)
daygenerator = (start + timedelta(x + 1) for x in xrange((end - start).days))
gendays = sum(day.weekday() < 5 for day in daygenerator)
print(comment,start,end,workdaycount(start,end))
print('Other formula:', days, '. Generator formula: ', gendays)
还支持特定的有效天数和添加假期的选项
import numpy as np
np.busyday_count('2019-01-21','2020-03-28',weekmask=[1,1,1,1,1,0,0],holidays=['2020-01-01'])
import numpy as np
np.busday_count('2018-04-10', '2018-04-11')
import numpy as np
np.busyday_count('2019-01-21','2020-03-28',weekmask=[1,1,1,1,1,0,0],holidays=['2020-01-01'])
import datetime
def getWeekdaysNumber(start,end):
numberOfDays = (end-start).days+1
numberOfWeeks = numberOfDays // 7
reminderDays = numberOfDays % 7
numberOfDays -= numberOfWeeks *2
if reminderDays:
#this line is creating a set of weekdays for remainder days where 7 and 0 will be Saturday, 6 and -1 will be Sunday
weekdays = set(range(end.isoweekday(), end.isoweekday() - reminderDays, -1))
numberOfDays -= len(weekdays.intersection([7,6,0,-1])
return numberOfDays
start = date(2018,10,10)
end = date (2018,10,17)
result = getWeekdaysNumber(start,end)`
In [3]: import datetime
In [4]: from networkdays import networkdays
In [5]: HOLIDAYS = { datetime.date(2020, 12, 25),}
In [6]: days = networkdays.Networkdays(datetime.date(2020, 12, 1),datetime.date(2020, 12, 31), holidays=HOLIDAYS, weekdaysoff={6,7})
In [7]: days.networkdays()
Out[7]:
[datetime.date(2020, 12, 1),
datetime.date(2020, 12, 2),
datetime.date(2020, 12, 3),
datetime.date(2020, 12, 4),
datetime.date(2020, 12, 7),
datetime.date(2020, 12, 8),
datetime.date(2020, 12, 9),
datetime.date(2020, 12, 10),
datetime.date(2020, 12, 11),
datetime.date(2020, 12, 14),
datetime.date(2020, 12, 15),
datetime.date(2020, 12, 16),
datetime.date(2020, 12, 17),
datetime.date(2020, 12, 18),
datetime.date(2020, 12, 21),
datetime.date(2020, 12, 22),
datetime.date(2020, 12, 23),
datetime.date(2020, 12, 24),
datetime.date(2020, 12, 28),
datetime.date(2020, 12, 29),
datetime.date(2020, 12, 30),
datetime.date(2020, 12, 31)]
def get_workdays(from_date: datetime, to_date: datetime):
# if the start date is on a weekend, forward the date to next Monday
if from_date.weekday() > 4:
from_date = from_date + timedelta(days=7 - from_date.weekday())
# if the end date is on a weekend, rewind the date to the previous Friday
if to_date.weekday() > 4:
to_date = to_date - timedelta(days=to_date.weekday() - 4)
if from_date > to_date:
return 0
# that makes the difference easy, no remainders etc
diff_days = (to_date - from_date).days + 1
weeks = int(diff_days / 7)
return weeks * 5 + (to_date.weekday() - from_date.weekday()) + 1
from dateutil import rrule
from datetime import datetime
import pytz
timezone_manila = pytz.timezone('Asia/Manila')
class Holidays(object):
def __init__(self, holidaydata):
self.holidaydata = holidaydata
def isHoliday(self,dateobj):
for holiday in self.holidaydata:
d = datetime(holiday['date']['year'], holiday['date']['month'], holiday['date']['day'], tzinfo=timezone_manila)
if d == dateobj:
return True
return False
def pullHolidays(start, end):
import urllib.request, json
urlstring = "https://kayaposoft.com/enrico/json/v2.0/?action=getHolidaysForDateRange&fromDate=%s&toDate=%s&country=phl®ion=dc&holidayType=public_holiday" % (start.strftime("%d-%m-%Y"),end.strftime("%d-%m-%Y"))
with urllib.request.urlopen(urlstring) as url:
holidaydata = json.loads(url.read().decode())
return Holidays(holidaydata)
def countWorkDays(start, end):
workdays=0
holidayData=pullHolidays(start,end)
for dt in rrule.rrule(rrule.DAILY, dtstart=start, until=end):
if dt.weekday() < 5:
if holidayData.isHoliday(dt) == False:
workdays+=1
return workdays