Как исключить перерывы из временного интервала при расчете чистого времени выполнения задачи в отчете 1С

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

При разработке отчетов по производительности труда или анализу выполнения производственных этапов часто возникает задача рассчитать «чистое» время работы. Проблема заключается в том, что обычная разница между временем начала и окончания документа (или этапа) включает в себя обеденные перерывы, технологические паузы и время отдыха, которые не должны учитываться в фактических трудозатратах. В этой статье мы подробно разберем, как реализовать механизм исключения таких перерывов, используя возможности языка запросов 1С и программные методы.

Постановка задачи и логика решения

Представим ситуацию: у нас есть документ, фиксирующий выполнение работы с 08:00 до 17:00. В течение этого периода существует регламентированный обед с 12:00 до 13:00 и пятиминутные перерывы в конце каждого часа. Если просто вычесть время начала из времени окончания, мы получим 9 часов, хотя фактически работа велась меньше. Наша цель — вычесть все интервалы перерывов, которые полностью или частично попали внутрь рабочего интервала.

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

Шаг 1. Подготовка данных и соединение таблиц

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

Проанализируем пример запроса, где мы выбираем данные из временной таблицы ВТ_Работы и соединяем их с регистром РасписаниеПерерывов:


ВЫБРАТЬ
    Работы.Этап КАК Этап,
    Работы.ДатаНачала КАК ДатаН,
    Работы.ДатаОкончания КАК ДатаК,
    Перерывы.ДатаНачала КАК Перерыв_ДатаН,
    Перерывы.ДатаОкончания КАК Перерыв_ДатаК
ПОМЕСТИТЬ ВТ_Пересечения
ИЗ
    ВТ_Работы КАК Работы
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.РасписаниеПерерывов КАК Перерывы
        ПО (Перерывы.ДатаНачала < Работы.ДатаОкончания)
            И (Перерывы.ДатаОкончания > Работы.ДатаНачала)

Использование ЛЕВОЕ СОЕДИНЕНИЕ критически важно, так как если работа выполнялась в период, где нет перерывов, запись о работе все равно должна остаться в выборке (в этом случае поля перерыва будут содержать NULL).

Шаг 2. Корректировка границ перерывов (Трансформация интервалов)

Часто перерыв может начинаться раньше, чем работа, или заканчиваться позже нее. Чтобы корректно посчитать время перерыва, которое нужно вычесть, мы должны «обрезать» границы перерыва по границам работы. Для этого используем конструкцию ВЫБОР.

Рассмотрим подробнее логику:

  1. Если Перерыв_ДатаН меньше ДатаН, то для расчета используем ДатаН. В противном случае оставляем Перерыв_ДатаН.
  2. Если Перерыв_ДатаК больше ДатаК, то используем ДатаК. В противном случае оставляем Перерыв_ДатаК.

На языке запросов 1С это будет выглядеть следующим образом:


ВЫБРАТЬ
    Этап,
    ДатаН,
    ДатаК,
    ВЫБОР
        КОГДА Перерыв_ДатаН < ДатаН ТОГДА ДатаН
        ИНАЧЕ Перерыв_ДатаН
    КОНЕЦ КАК СкорректированныйПерерывН,
    ВЫБОР
        КОГДА Перерыв_ДатаК > ДатаК ТОГДА ДатаК
        ИНАЧЕ Перерыв_ДатаК
    КОНЕЦ КАК СкорректированныйПерерывК
ПОМЕСТИТЬ ВТ_ПодготовленныеДанные
ИЗ
    ВТ_Пересечения

Шаг 3. Расчет длительности и группировка

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

Важный нюанс: при суммировании длительности перерывов необходимо обработать значение NULL, которое возникает, если работа не попала ни на один перерыв. Используем функцию ЕСТЬNULL.


ВЫБРАТЬ
    Этап,
    ДатаН,
    ДатаК,
    РАЗНОСТЬДАТ(ДатаН, ДатаК, СЕКУНДА) КАК ОбщаяДлительностьСекунд,
    СУММА(ЕСТЬNULL(РАЗНОСТЬДАТ(СкорректированныйПерерывН, СкорректированныйПерерывК, СЕКУНДА), 0)) КАК СуммаПерерывовСекунд
ПОМЕСТИТЬ ВТ_ИтоговыеСекунды
ИЗ
    ВТ_ПодготовленныеДанные
СГРУППИРОВАТЬ ПО
    Этап,
    ДатаН,
    ДатаК

Шаг 4. Получение чистого времени

Теперь остается просто вычесть сумму перерывов из общей длительности. Полученный результат можно перевести обратно в часы или минуты для вывода в отчет. Проанализируем финальное вычисление:


ВЫБРАТЬ
    Этап,
    ДатаН,
    ДатаК,
    (ОбщаяДлительностьСекунд - СуммаПерерывовСекунд) КАК ЧистоеВремяСекунд
ИЗ
    ВТ_ИтоговыеСекунды

Альтернативный метод: Использование графиков работы

Если в вашей конфигурации (например, 1С:ERP или 1С:ЗУП) уже настроены графики работы, задачу можно решить более элегантно через встроенные функции программного интерфейса. Посмотрим на использование общего модуля КалендарныеГрафики.

Функция ПолучитьКоличествоРабочегоВремени позволяет получить количество секунд между двумя датами с учетом конкретного графика. Это избавляет от написания сложных запросов, так как платформа сама учитывает и перерывы, и праздничные дни, и сокращенные смены.

Пример программного кода:


ДлительностьСекунд = КалендарныеГрафики.ПолучитьКоличествоРабочегоВремени(ГрафикРаботы, ДатаНачала, ДатаОкончания);

Преимущества этого метода:

Особенности учета многодневных интервалов

Проанализируем ситуацию, когда этап начинается в 22:00 одного дня и заканчивается в 06:00 следующего. Если расписание перерывов хранится просто как «с 12:00 до 13:00», запрос может отработать некорректно. В таких случаях мы рекомендуем:

  1. Использовать полноценный календарь (регистр сведений), где каждая запись перерыва привязана к конкретной дате.
  2. Если перерывы цикличны (каждый день одинаковы), перед соединением в запросе необходимо «размножить» таблицу перерывов на все даты, попадающие в период отчета.
  3. При переходе через полночь важно проверять ДатаН и ДатаК не только по времени, но и по полной дате.

Рекомендации по оптимизации производительности

Если отчет строится по тысячам документов, левое соединение с регистром перерывов может замедлить выполнение. Разберем по шагам, как ускорить процесс:

  1. Индексация: Убедитесь, что поля ДатаНачала и ДатаОкончания в регистре перерывов проиндексированы.
  2. Предварительная фильтрация: Сначала выберите только те работы, которые попадают в период отчета, во временную таблицу, а затем присоединяйте перерывы.
  3. Использование временных таблиц: Разделение сложного запроса на несколько простых (как мы сделали в примерах выше) помогает планировщику SQL-сервера построить оптимальный план выполнения.

Таким образом, мы рассмотрели надежный способ исключения перерывов из временных интервалов. Использование РАЗНОСТЬДАТ в секундах и грамотная корректировка границ интервалов через ВЫБОР позволяют получить точные данные для любых управленческих отчетов.

← На главную