Задать вопрос
@Mr-Governor
Губернирую

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

Всем привет.
Есть множество задач. Мне известна дата начала работы и дата окончания работы каждой задачи.
На каждый тип задачи есть определенное ограничение по времени ее выполнения (несколько дней).
Если задача выполнялась дольше выделенного времени, она считается просроченной.

Возникла задача рассчитывать время просрочки с учетом выходных, региональных и корпоративных праздничных дней. То есть, нерабочие дни в просрочку не складываются.

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

Может кто знает, как эффективней всего вычислять такие значения?
1. Как лучше хранить список нерабочих дней?
2. Как высчитывать просрочку для каждого периода?
  • Вопрос задан
  • 216 просмотров
Подписаться 1 Простой 5 комментариев
Пригласить эксперта
Ответы на вопрос 3
wataru
@wataru Куратор тега Алгоритмы
Разработчик на С++, экс-олимпиадник.
Можно без цикла для каждой задачи.
Самое простое - найти самый первый и самый последний день для всех задач. Потом в массиве длины равно разности этих дат плюс один сначала пометить единицами все дни, которые являются праздничными. Потом подсчитать частичные суммы (каждый элемент должен быть равен сумме единиц до этого элемента включительно).

Ну а потом для каждой задачи можно понять сколько там было праздников в ее интервале просто вычтя две частичные суммы из массива.

Второй вариант - выходные дни недели подсчитать ручками: если дата начала и дата коца в одной неделе, то выходных нет. Иначе, если начало не понедельник - то сдвинуть ее до следующего понедельника и прибавить следующие субботу и воскресение к счетчику. Потом, если дата конца не пятница - сдвинуть ее на предудущий понедельник. Теперь разность между датами кратна 7 и покрывает сколько-то недель целиком. Делите разность на 7 и умножайте на 2, чтобы подсчитать, сколько там суббот и воскресений (разность может быть и 0 и это нормально).

Потом надо ручками же подсчитать все праздники. Для этого составьте в массиве даты всех календарных праздников в затронутых годах отсортированные. Потом для каждой задачи в этом массиве бинпоиском найдите первый и последний праздник в отрезке. Вот вы уже знаете их количество (разность индексов +1). Так же можно еще вести список всех рабочих суббот и воскресений. Этот список дат можно, наверно, где-то из интернета автоматически скачивать, а можно и тупо ручками в январе вбивать в базу.
Ответ написан
Комментировать
snaiper04ek
@snaiper04ek
Не стреляйте в эникея, он админит как умеет
я бы захардкодил в массив за все рабочие дни за год(ну, или хотя бы сгенерировал на основании массива с выходными днями):
calendar(year2022(mounth1(1,2,3,4,5,8,9,10,11,12,15,16,17,18,19,22,23,24,25,26,28,29,30),mounth2(2,3,4,5,6,9,10...), mounth3(1, 2...), etc))
и спрашивал у него
days_to_work_on_task = 3
start_date = today
end_data = calendar[year2022[mounth2[today + days_to_work_on_task]]]
так как заведомо там все дни рабочие, можно тупо по порядку идти, приплюсовывая количество дней положенного на таску.
нужно обработать момент с выходом за рамки кортежа месяца, и за рамки кортежа года (считать на сколько вышел, и остаток переносить на другой месяц/год)

так же нашёл библиотеку с API производственного календаря, если не лень разобраться, можно оттуда тянуть данные: https://www.isdayoff.ru/libs/
Ответ написан
Комментировать
LaRN
@LaRN
Senior Developer
Можно сохранить в таблице БД все рабочие дни текущего года и далее простым запросом получать количество дней между двумя датами.
Select count(1) from tDate where Date between DateStart and DateEnd

Вариант с БД хорош тем, что не придется каждый раз менять код для случая, когда от года к году есть изменения в количестве нерабочих дней и не будет сложностей с вычислением количества дней в месяцах (28 или 29, 30 или 31)
Т.е. расчет предельно прозрачный.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы