Как в 1С рассчитать рабочее время между двумя датами с учетом рабочего графика?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С часто возникает задача вычисления точной длительности выполнения задачи или операции. Если требуется посчитать астрономическое время, достаточно найти простую разницу дат. Однако если организация работает по фиксированному графику (например, с 10:00 до 19:00 без выходных), обычная разность дат учтет ночные часы, что приведет к некорректным результатам.

Разберем различные подходы к расчету рабочего времени: от аналитической формулы на встроенном языке 1С до универсальных запросов с пересечением интервалов и типовых механизмов платформы.

Аналитический расчет на встроенном языке 1С

Рассмотрим ситуацию, когда график работы непрерывный (без выходных и праздников), а рабочий день длится фиксированное количество часов (например, 9 часов — с 10:00 до 19:00). В этом случае можно обойтись без циклов и таблиц календарей, применив математический алгоритм.

Разберем по шагам логику расчета:

  1. Проверка входных параметров: убедимся, что дата начала не превышает дату окончания.
  2. Нормализация границ: если событие наступило раньше начала рабочего дня (до 10:00) или позже его окончания (после 19:00), приводим границы к рабочему окну соответствующих суток.
  3. Разделение логики: отдельно обрабатываем случай выполнения задачи в пределах одного календарного дня и случай, когда интервал охватывает несколько дней.
  4. Суммирование интервалов: при многодневном периоде складываем рабочие часы первого дня, рабочие часы последнего дня и полное рабочее время за все промежуточные сутки.

Посмотрим на пример универсальной функции на встроенном языке 1С:


Функция РассчитатьРабочееВремя(ДатаНачала, ДатаОкончания) Экспорт

    Если ДатаНачала >= ДатаОкончания Тогда
        Возврат 0;
    КонецЕсли;

    ДлительностьДняСекунд = 9 * 3600; // 9 рабочих часов в сутках
    СекундВСутках = 86400;

    // Нормализуем границы к рабочему времени (с 10:00 до 19:00)
    РабочееНачалоДня1 = НачалоДня(ДатаНачала) + 10 * 3600;
    РабочийКонецДня1  = НачалоДня(ДатаНачала) + 19 * 3600;
    ФактНачало = Мин(Макс(ДатаНачала, РабочееНачалоДня1), РабочийКонецДня1);

    РабочееНачалоДня2 = НачалоДня(ДатаОкончания) + 10 * 3600;
    РабочийКонецДня2  = НачалоДня(ДатаОкончания) + 19 * 3600;
    ФактОкончание = Мин(Макс(ДатаОкончания, РабочееНачалоДня2), РабочийКонецДня2);

    Если НачалоДня(ДатаНачала) = НачалоДня(ДатаОкончания) Тогда
        РабочихСекунд = Макс(0, ФактОкончание - ФактНачало);
    Иначе
        СекундВПервыйДень   = РабочийКонецДня1 - ФактНачало;
        СекундВПоследнийДень = ФактОкончание - РабочееНачалоДня2;
        
        // Число полных календарных дней между датами
        ЦелыхДнейМежду = ((НачалоДня(ДатаОкончания) - НачалоДня(ДатаНачала)) / СекундВСутках) - 1;
        
        РабочихСекунд = СекундВПервыйДень + (ЦелыхДнейМежду * ДлительностьДняСекунд) + СекундВПоследнийДень;
    КонецЕсли;

    Возврат РабочихСекунд / 3600; // Результат в часах

КонецФункции

Расчет через пересечение интервалов в запросе 1С

Если данные требуется обработать для большого массива записей прямо в запросе СУБД, используется метод наложения интервалов. Для этого интервал выполнения задачи соединяется с таблицей рабочих интервалов графика.

Проанализируем алгоритм: два временных интервала [A1, A2] и [B1, B2] пересекаются тогда и только тогда, когда МАКС(A1, B1) < МИН(A2, B2). Длительность пересечения при этом равна МИН(A2, B2) - МАКС(A1, B1).

Посмотрим на реализацию логики пересечения интервалов в тексте запроса:


ВЫБРАТЬ
    Задачи.Идентификатор КАК ИдентификаторЗадачи,
    СУММА(РАЗНОСТЬДАТ(
        ВЫБОР
            КОГДА Задачи.ДатаНачала > График.ДатаНачала
                ТОГДА Задачи.ДатаНачала
            ИНАЧЕ График.ДатаНачала
        КОНЕЦ,
        ВЫБОР
            КОГДА Задачи.ДатаОкончания < График.ДатаОкончания
                ТОГДА Задачи.ДатаОкончания
            ИНАЧЕ График.ДатаОкончания
        КОНЕЦ,
        СЕКУНДА
    )) / 3600 КАК ОтработаноЧасов
ИЗ
    ВТ_Задачи КАК Задачи
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ГрафикРаботы КАК График
        ПО (ВЫБОР
                КОГДА Задачи.ДатаНачала > График.ДатаНачала
                    ТОГДА Задачи.ДатаНачала
                ИНАЧЕ График.ДатаНачала
            КОНЕЦ < ВЫБОР
                КОГДА Задачи.ДатаОкончания < График.ДатаОкончания
                    ТОГДА Задачи.ДатаОкончания
                ИНАЧЕ График.ДатаОкончания
            КОНЕЦ)
СГРУППИРОВАТЬ ПО
    Задачи.Идентификатор

Краевые случаи и особенности расчетов

При использовании математических формул важно учитывать ограничения, которые могут привести к неверному результату:

  1. События вне рабочего диапазона: если задача поставлена в 08:30 (до открытия смены) или закрыта в 22:00 (после закрытия смены), без нормализации границ через функции Мин() и Макс() формула посчитает нерабочее время.
  2. События внутри нерабочего интервала: если задача открыта и закрыта ночью (например, между 21:00 и 23:00 одного дня), расчет должен возвращать 0.
  3. Несколько рабочих смен и обеды: при наличии обеденных перерывов аналитическая формула усложняется, поэтому надежнее использовать таблицы производственных календарей.

Использование типовых механизмов 1С и БСП

Если в системе настроен производственный календарь или требуется учитывать праздничные дни, переносы и сменные графики, рекомендуется использовать типовые инструменты:

  1. Подсистема «Календарные графики» БСП: в Библиотеке стандартных подсистем модуль КалендарныеГрафики содержит готовые экспортные процедуры для работы с графиками работы и расчета времени.
  2. Регистры расчета: специализированные объекты конфигурации с механизмом базовых периодов позволяют платформе автоматически рассчитывать пересечения интервалов действия и фактически отработанного времени.
← На главную