Подтвердить что ты не робот

Укажите количество дней между датами, игнорируя выходные

Как я могу рассчитать количество дней между двумя датами, игнорирующими выходные?

4b9b3361

Ответ 1

Я думаю, что самым чистым решением является использование функции 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 )

Ответ 2

>>> 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 вместо каждой даты. Затем мы можем просто добавить все эти 1s вместе, чтобы получить длину, не сохраняя весь список.

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

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

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

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

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

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

Ответ 6

Обратите внимание, что код @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)

Ответ 7

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

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)

Ответ 8

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

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

Ответ 9

Я адаптировал 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))

Ответ 10

Я попробовал два первых ответа (Дейв Уэбб и Нейл), и почему-то я получал неверные ответы от обоих. Возможно, это была ошибка с моей стороны, но я пошел с существующей библиотекой на том основании, что она, вероятно, имела больше функциональности и была лучше проверена для краевых случаев:

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

Ответ 11

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

Эта проблема может быть разбита на две разные проблемы:

  • Вычисление числа интегральных недель в интервале: для целой недели количество выходных дней равно 2. Это тривиальное целочисленное деление: (todate - fromdate)/7

  • Вычисление количества дней выходных дней в оставшемся интервале: это можно легко решить с помощью подхода подсчета (например, для отображения карты): 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

И пример его работы:

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

Ответ 12

Мое решение также учитывает последний день. Поэтому, если для начала и конца установлен один и тот же день недели, тогда asnwer будет равен 1 (например, 17 октября). Если начало и конец 2 последовательных будних дня, тогда ответ будет 2 (например, 17 и 18 октября). Он рассчитан на целые недели (в каждом из них у нас будет 2 дня выходных дней), а затем проверяйте дни напоминания, если они содержат выходные дни.

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

Ответ 13

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

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)

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

Ответ 14

Используйте этот пакет, называемый бизнес-продолжительностью в PyPi.

Пример кода:

from business_duration import businessDuration

import pandas as pd

import datetime

start = pd.to_datetime("2010-1-1 00:00:00")

end = pd.to_datetime("2010-3-31 00:00:00")

businessDuration(startdate=start,enddate=end,unit='day')

Out [6]: 62.99927083333333