Python 计算日期之间的天数,忽略周末

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3615375/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 11:57:33  来源:igfitidea点击:

Count number of days between dates, ignoring weekends

python

提问by Mohammad Nadeem

How can I calculate number of days between two dates ignoring weekends?

如何计算两个日期之间的天数而忽略周末?

回答by Coding District

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

I think something like that should work. I don't have the tools to test it right now.

我认为这样的事情应该有效。我现在没有工具来测试它。

回答by Dave Webb

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

This creates a generator using a generator expressionwhich will yield the list of daysto get from the fromdateto todate.

将创建使用生成器表达式生成器,其将产生的天列表从获取fromdatetodate

We could then create a list from the generator, filtering out weekends using the weekday()function, and the size of the list gives the number of days we want. However, to save having the whole list in memory which could be a problem if the dates are a long time apart we use another generator expression which filters out weekends but returns 1 instead of each date. We can then just add all these 1s together to get the lengthwithout having to store the whole list.

然后,我们可以从发电机创建列表,使用过滤掉周末weekday()功能,而列表的大小给予我们想要的天数。然而,为了将整个列表保存在内存中,如果日期相隔很长时间,这可能会成为一个问题,我们使用另一个生成器表达式,它过滤掉周末但返回 1 而不是每个日期。 然后我们可以将所有这些 1 加在一起得到长度,而不必存储整个列表。

Note, if fromdate == todatethis calculate 0 not 1.

请注意,如果fromdate == todate这计算 0 而不是 1。

回答by neil

The answers given so far will work, but are highly inefficient if the dates are a large distance apart (due to the loop).

到目前为止给出的答案是有效的,但如果日期相距很远(由于循环),则效率非常低。

This should work:

这应该有效:

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)

This turns it into whole weeks (which have 5 working days) and then deals with the remaining days.

这将它变成整周(有 5 个工作日),然后处理剩余的天数。

回答by Tony Veijalainen

Fixed Saturday to Sunday same weekend to function.

修复了周六至周日同一周末的功能。

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)

回答by Matthew Scouten

The lazy way is to pip install workdaysto get the python package that does exactly this.

懒惰的方法是pip install workdays获取执行此操作的 python 包。

https://pypi.python.org/pypi/workdays/

https://pypi.python.org/pypi/workdays/

回答by Andy Baker

I tried the top two answers (Dave Webb's and neil's) and for some reason I was getting incorrect answers from both. It might have been an error on my part but I went with an existing library on the basis that it probably had more functionality and was better tested for edge cases:

我尝试了前两个答案(Dave Webb 和 Neil 的),但出于某种原因,我从两个答案中都得到了错误的答案。这可能是我的一个错误,但我使用了一个现有的库,因为它可能具有更多功能并且对边缘情况进行了更好的测试:

https://bitbucket.org/shelldweller/python-bizdatetime

https://bitbucket.org/shelldweller/python-bizdatetime

回答by jterrace

I adapted Dave Webb's answer into a function and added some test cases:

我将 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))

回答by Ben

I think the cleanest solution is to use the numpy function busday_count

我认为最干净的解决方案是使用 numpy 函数 busday_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 )

回答by vekerdyb

Note that the @neil's (otherwise great) code will fail for Sunday-Thursday intervals. Here is a fix:

请注意,@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)

回答by Ernesto Puerta

This is a function that I implemented for measuring how many working days it takes for code to be integrated across branches. It does not need iterating over the whole intermediate days, as other solutions do, but only for the first week.

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

This problem can be broken down into two different problems:

这个问题可以分解为两个不同的问题:

  1. Calculating the number of integral weeks in the interval: for an integral week, the number of weekend days is always 2. This is a trivial integer division: (todate - fromdate)/7

  2. Calculating the number of weekend days in the remaining interval: this can be easily solved with the counting approach (map-reduce like): sum(map(is_weekend, rem_days)).

  1. 计算区间内的整数周数:对于整数周,周末天数始终为 2。这是一个平凡的整数除法:(todate - fromdate)/7

  2. 计算在剩余的时间间隔周末天数:这可以通过计数方式(地图,减少等)很容易解决:sum(map(is_weekend, rem_days))

def count_working_days(fromdate, todate):
    from datetime import timedelta as td
    def is_weekend(d): return d.weekday() > 4

    # 1st problem
    num_weeks = (todate - fromdate).days/7

    # 2nd problem
    rem_days = (todate - fromdate).days%7
    rem_weekend_days = sum(is_weekend(fromdate + td(days=i+1)) for i in range(rem_days))

    return (todate - fromdate).days - 2*num_weeks - rem_weekend_days

And a sample of its working:

以及它的工作示例:

>>> for i in range(10): latency(datetime.now(), datetime.now() + timedelta(days=i))
...
0    1    1    1    2    3    4    5    6    6