Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 两个日期之间的天数,不包括周末_Python_Datetime - Fatal编程技术网

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)

这是我实现的一个函数,用于测量跨分支集成代码需要多少工作日。它不需要像其他解决方案那样迭代整个中间天,只需要在第一周迭代

此问题可分为两个不同的问题:

  • 计算间隔中的整周数:对于整周,周末天数始终为2。这是一个简单的整数除法:
    (todate-fromdate)/7

  • 计算剩余时间间隔内的周末天数:这可以通过计数方法(map reduce)轻松解决:
    求和(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&region=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