У меня простая проблема, но я уже пробовал ее решить несколькими способами и не получил ожидаемого результата. Мне нужно посчитать количество рабочих дней между двумя датами, но без учета первого дня.
Пример: начальная_дата: 08.15.2024 (четверг) Final_date: 20.08.2024 (вторник)
В Excel, если я рассчитаю календарные дни =DAYS(dt_initial;dt_final), я получу в общей сложности 5 дней. Другими словами, считается суббота и воскресенье, но это не то, что мне нужно. Если я попытаюсь не учитывать выходные =DIAWORKALHOTAL.INTL(dt_initial;dt_final;1), я получу результат 4. То есть он включает в себя 15-е число в счете.
Мне бы хотелось найти способ считать со следующего дня, то есть в приведенном выше примере результат будет = 3 (дни 16, 19 и 20).
Если кто-нибудь знает способ решить эту проблему, будь то в Excel, PowerBI или даже с помощью Python, не могли бы вы сообщить мне?
Как я уже упоминал, в Excel я уже пробовал использовать =DIAWORKALHOTAL.INTL(dt_initial;dt_final;1), но он возвращает счетчик с учетом начальной даты (первый день).
В PowerBI я попробовал приведенный ниже пример, но столкнулся с той же проблемой:
рабочие_дни = ЧИСТРАБДНИ(таблица[начальная_дата],таблица[конечная_дата], 1)
=DIAWORKALHOTAL.INTL(dt_initial + 1;dt_final;1),
Спасибо :) Но мне кажется это не совсем работает. Пример: Начальная дата: 19.08.24 (понедельник) Конечная дата: 21.08.2024 (среда) Применяя эту логику, результат: 2 (это хорошо, потому что в данном случае результат — это то, что я хочу). Но посмотрим на другой пример: Начальная дата: 19.08.24 (понедельник) Конечная дата: 20.08.2024 (вторник) Применяя логику +1, результат: 0, верно? Но правильным является 1. Другой пример: Начальная дата: 19.08.24 (понедельник) Конечная дата: 19.08.2024 (понедельник) Тот же день, поэтому правильный результат равен 0. Но применив логику +1, результат будет быть -1
Что произойдет, если первое свидание, например, суббота? с 24.8.24 по 26.8.24? Каков будет ожидаемый результат?
@jessie, ты хотя бы попробовал =DIAWORKALHOTAL.INTL(dt_initial + 1;dt_final;1)
, прежде чем ответить на комментарий? =DIAWORKALHOTAL.INTL(date(2024, 8, 19)+ 1;date(2024, 8, 20);1)
вернет 1, а не ноль. =DIAWORKALHOTAL.INTL
не рассчитывает «длительность», а просто возвращает количество дней, удовлетворяющих определенному условию (рабочий день). поэтому =DIAWORKALHOTAL.INTL(date(2024, 8, 20);date(2024, 8, 20);1)
вернет 1. но я согласен, если дата начала > дата окончания, DIAWORKALHOTAL.INTL не будет работать.
@Джесси - отличный вопрос, кстати. См. ответ ниже - это самый экономный (простой) способ дать правильный ответ (для начала = конца того же дня и т. д.), который я пока вижу (но через etfc может быть получено больше).
Ниже/здесь ссылка:
=IF(C4<C3,"",NETWORKDAYS(C3,C4)-(WEEKDAY(C3,2)<=5))
Причина, по которой другие вычисления не работали (те, что в комментариях и т. д.), в первую очередь связана с несколько «милым» подходом, заключающимся в попытке игнорировать первый день, установив дату начала += 1 (день после даты начала).
Как вы заметили, это падает, когда начало = конец. Мой подход решает эту проблему (и более обобщенные варианты) надлежащим/правильным образом, а в остальном он столь же прост/экономичен в использовании/настройке.
Чтобы продемонстрировать, что это правильное решение, приведена таблица результатов (на основе таблицы данных/доступна по ссылке выше) в диапазоне дат начала/окончания.
К вашему сведению - не уверен, откуда взялась функция OPs, приведенная ниже, но сказал, что Excel/Python и т. д. также будут приветствоваться. Я придерживался Excel (судя по названию ☺)
Результат поиска Google для функции, предоставленной OP/первым комментатором.
(обратите внимание, что ссылки AI ссылаются на этот конкретный пост!)
Я считаю, что вам просто нужно это:
=NETWORKDAYS.INTL(dt_initial, dt_final,1)-NETWORKDAYS.INTL(dt_initial,dt_initial,1)
NETWORKDAYS.INTL(dt_initial, dt_final,1)
рассчитывает рабочие дни между начальной и конечной датой включительно.
NETWORKDAYS.INTL(dt_initial,dt_initial,1)
проверяет, является ли initial_date
рабочим днем или нет, если да, вычтите единицу из NETWORKDAYS.INTL(dt_initial, dt_final,1)
, если нет, оставьте NETWORKDAYS.INTL(dt_initial, dt_final,1)
как есть.
Вы можете использовать мою функцию DateDiffWorkdays
:
Date1 = #2024-08-19#
Date2 = #2024-08-20#
? DateDiffWorkdays(Date1, Date2)
1
Date1 = #2024-08-19#
Date2 = #2024-08-21#
? DateDiffWorkdays(Date1, Date2)
2
Date1 = #2024-08-15#
Date2 = #2024-08-20#
? DateDiffWorkdays(Date1, Date2)
3
Функция:
' Returns the count of full workdays between Date1 and Date2.
' The date difference can be positive, zero, or negative.
' Optionally, if WorkOnHolidays is True, holidays are regarded as workdays.
'
' Note that if one date is in a weekend and the other is not, the reverse
' count will differ by one, because the first date never is included in the count:
'
' Mo Tu We Th Fr Sa Su Su Sa Fr Th We Tu Mo
' 0 1 2 3 4 4 4 0 0 -1 -2 -3 -4 -5
'
' Su Mo Tu We Th Fr Sa Sa Fr Th We Tu Mo Su
' 0 1 2 3 4 5 5 0 -1 -2 -3 -4 -5 -5
'
' Sa Su Mo Tu We Th Fr Fr Th We Tu Mo Su Sa
' 0 0 1 2 3 4 5 0 -1 -2 -3 -4 -4 -4
'
' Fr Sa Su Mo Tu We Th Th We Tu Mo Su Sa Fr
' 0 0 0 1 2 3 4 0 -1 -2 -3 -3 -3 -4
'
' Execution time for finding working days of three years is about 4 ms.
'
' Requires table Holiday with list of holidays.
'
' 2015-12-19. Gustav Brock. Cactus Data ApS, CPH.
'
Public Function DateDiffWorkdays( _
ByVal Date1 As Date, _
ByVal Date2 As Date, _
Optional ByVal WorkOnHolidays As Boolean) _
As Long
Dim Holidays() As Date
Dim Diff As Long
Dim Sign As Long
Dim NextHoliday As Long
Dim LastHoliday As Long
Sign = Sgn(DateDiff("d", Date1, Date2))
If Sign <> 0 Then
If WorkOnHolidays = True Then
' Holidays are workdays.
Else
' Retrieve array with holidays between Date1 and Date2.
Holidays = DatesHoliday(Date1, Date2, False) 'CBool(Sign < 0))
' Ignore error when using LBound and UBound on an unassigned array.
On Error Resume Next
NextHoliday = LBound(Holidays)
LastHoliday = UBound(Holidays)
' If Err.Number > 0 there are no holidays between Date1 and Date2.
If Err.Number > 0 Then
WorkOnHolidays = True
End If
On Error GoTo 0
End If
' Loop to sum up workdays.
Do Until DateDiff("d", Date1, Date2) = 0
Select Case Weekday(Date1)
Case vbSaturday, vbSunday
' Skip weekend.
Case Else
If WorkOnHolidays = False Then
' Check for holidays to skip.
If NextHoliday <= LastHoliday Then
' First, check if NextHoliday hasn't been advanced.
If NextHoliday < LastHoliday Then
If Sgn(DateDiff("d", Date1, Holidays(NextHoliday))) = -Sign Then
' Weekend hasn't advanced NextHoliday.
NextHoliday = NextHoliday + 1
End If
End If
' Then, check if Date1 has reached a holiday.
If DateDiff("d", Date1, Holidays(NextHoliday)) = 0 Then
' This Date1 hits a holiday.
' Subtract one day to neutralize the one
' being added at the end of the loop.
Diff = Diff - Sign
' Adjust to the next holiday to check.
NextHoliday = NextHoliday + 1
End If
End If
End If
Diff = Diff + Sign
End Select
' Advance Date1.
Date1 = DateAdd("d", Sign, Date1)
Loop
End If
DateDiffWorkdays = Diff
End Function
Для этого требуются некоторые вспомогательные функции — слишком много кода, чтобы публиковать здесь — все их можно найти в модулях моего репозитория на GitHub: VBA.Date.
Обратите внимание, что это также позволяет исключить праздники из таблицы праздников.
Я добавил для вас демо-версию Excel в папку demos
: DateWork.xlsm
.
Привет, вопросы по Stack Overflow должны быть на английском языке, но вы можете задать их на испанском здесь: es.stackoverflow.com