Подсчитать количество дней между датами, игнорируя выходные - PullRequest
44 голосов
/ 01 сентября 2010

Как рассчитать количество дней между двумя датами без учета выходных?

Ответы [ 14 ]

63 голосов
/ 06 октября 2014

Я думаю, что самое чистое решение - использовать функцию 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 )
49 голосов
/ 01 сентября 2010
>>> 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 до todate.

Затем мы можем создать список из генератора, отфильтровывая выходные дни, используя функцию weekday() , а размер списка дает желаемое количество дней.Однако, чтобы сохранить весь список в памяти, что может быть проблемой, если даты находятся на большом расстоянии друг от друга, мы используем другое выражение генератора, которое отфильтровывает выходные, но возвращает 1 вместо каждой даты. Затем мы можем просто сложить все эти 1, чтобы получить длину без необходимости сохранения всего списка.

Обратите внимание, что если fromdate == todate, это вычисляет 0, а не 1.

10 голосов
/ 01 сентября 2010

Ответы, данные до сих пор, будут работать, но крайне неэффективны, если даты находятся на большом расстоянии друг от друга (из-за цикла).

Это должно работать:

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 рабочих дней), а затем обрабатывает оставшиеся дни.

7 голосов
/ 28 октября 2013

Ленивый способ - pip install workdays, чтобы получить пакет python, который делает именно это.

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

6 голосов
/ 10 апреля 2018

Первый импорт numpy как np.Функция np.busday_count подсчитывает количество действительных дней между двумя датами, исключая день даты окончания.

Если дата окончания предшествует дате начала, счет будет отрицательным.Подробнее о np.busday_count читайте в документации здесь .

import numpy as np
np.busday_count('2018-04-10', '2018-04-11')

Обратите внимание, что функция принимает строки, нет необходимости создавать экземпляры datetime объектов перед вызовом функции.

4 голосов
/ 21 сентября 2015

Обратите внимание, что код @ 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)
3 голосов
/ 01 сентября 2010

Исправлена ​​работа субботы и воскресенья в те же выходные.

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)
2 голосов
/ 24 февраля 2014

Я адаптировал ответ Дейва Уэбба в функцию и добавил несколько тестовых случаев:

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))
2 голосов
/ 01 сентября 2010
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

Я думаю, что-то подобное должно работать. У меня нет инструментов, чтобы проверить это прямо сейчас.

1 голос
/ 21 июня 2019

Вы можете использовать следующую надежную функцию, чтобы получить количество рабочих дней между любыми двумя данными датами:

import datetime

def working_days(start_dt,end_dt):
    num_days = (end_dt -start_dt).days +1
    num_weeks =(num_days)//7
    a=0
    #condition 1
    if end_dt.strftime('%a')=='Sat':
        if start_dt.strftime('%a') != 'Sun':
            a= 1
    #cindition 2
    if start_dt.strftime('%a')=='Sun':
        if end_dt.strftime('%a') !='Sat':
            a =1
    #condition 3
    if end_dt.strftime('%a')=='Sun':
        if start_dt.strftime('%a') not in ('Mon','Sun'):
            a =2
    #condition 4        
    if start_dt.weekday() not in (0,6):
        if (start_dt.weekday() -end_dt.weekday()) >=2:
            a =2
    working_days =num_days -(num_weeks*2)-a

    return working_days

Пример использования:

start_dt = datetime.date(2019,6,5)
end_dt = datetime.date(2019,6,21)

working_days(start_dt,end_dt)

Здесь обе даты началаи дата окончания включена, исключая все выходные.
Надеюсь, это поможет !!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...