Как я могу рассчитать количество дней между двумя датами, игнорирующими выходные?
Укажите количество дней между датами, игнорируя выходные
Ответ 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, который делает именно это.
Ответ 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
Я попробовал два первых ответа (Дейв Уэбб и Нейл), и почему-то я получал неверные ответы от обоих. Возможно, это была ошибка с моей стороны, но я пошел с существующей библиотекой на том основании, что она, вероятно, имела больше функциональности и была лучше проверена для краевых случаев:
Ответ 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