Как правильно заполнить табличную часть с разбивкой времени по интервалам в 1С 8.3?

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

При разработке механизмов планирования, журналов записи клиентов или медицинских расписаний часто возникает задача: взять общий интервал времени приема из одной табличной части (например, с 09:00 до 18:00) и разбить его на отдельные слоты фиксированной длительности (например, по 30 или 40 минут) во второй табличной части. При реализации подобного алгоритма разработчики нередко сталкиваются с логическими ошибками в условиях, некорректной работой с типом Дата и возникновением бесконечных циклов.

Разберем по шагам, почему возникают эти ошибки, как правильно проверять заполнение полей времени и как выстроить корректный алгоритм генерации строк расписания.

Анализ типичных ошибок при проверке дат и условий

Рассмотрим фрагмент кода, с которого часто начинаются проблемы:


Если ЗначениеЗаполнено(СтрокаТабПриемов.Время1) или (СтрокаТабПриемов.Время2) Тогда
    Продолжить;
КонецЕсли;

В данном фрагменте допущены сразу две критические ошибки:

  1. Неправильная структура логического выражения: конструкция или (СтрокаТабПриемов.Время2) пытается привести значение поля Время2 (имеющего тип Дата) к типу Булево. Платформа 1С не выполняет неявное приведение дат к логическому типу, из-за чего возникает исключение времени выполнения: «Преобразование значения к типу Булево не может быть выполнено». Функция проверки должна вызываться для каждого операнда отдельно.
  2. Инвертированная логика условия: цель проверки — пропустить незаполненные строки. Написав условие без оператора Не, мы заставляем цикл вызывать оператор Продолжить как раз тогда, когда время заполнено. В результате обработка полезных данных полностью пропускается.

Также отметим распространенную ошибку начинающих разработчиков — попытку вызова метода Пустая() у даты (например, СтрокаТабПриемов.Время1.Пустая()). Метод Пустая() существует только у ссылочных типов данных (справочники, документы и др.). Для проверки даты на значение 01.01.0001 00:00:00 следует использовать глобальную функцию ЗначениеЗаполнено() либо прямое сравнение с Дата(1, 1, 1).

Правильный вариант проверки заполненности обоих полей времени выглядит следующим образом:


Если Не ЗначениеЗаполнено(СтрокаТабПриемов.Время1) Или Не ЗначениеЗаполнено(СтрокаТабПриемов.Время2) Тогда
    Продолжить; // Пропускаем строки, где не указано начало или окончание
КонецЕсли;

Особенности арифметики дат в платформе 1С

Тип данных Дата в 1С хранит одновременно дату и время с точностью до секунды. Любые математические операции сложения и вычитания с числом платформа производит в секундах:

  1. Прибавление интервала: выражение ТекущаяДата + 60 увеличивает время ровно на одну минуту, а ТекущаяДата + (40 * 60) — на 40 минут. Никаких сложных строковых преобразований и ручных вычислений остатков делать не требуется.
  2. Разница между датами: выражение Дата2 - Дата1 возвращает число секунд между двумя моментами времени.

Если выполнять избыточные операции вроде ч1 = мЧ; ч2 = мЧ - ч1;, переменная ч2 всегда будет равна 0, а пересчет минут через деление на 100 приведет к некорректным значениям времени.

Пошаговая реализация корректного алгоритма разбивки времени

Проанализируем правильную реализацию цикла генерации интервалов с учетом защиты от зацикливания и граничных условий:


// 1. Очищаем результирующую таблицу перед заполнением
Объект.ТабВремя.Очистить();

// 2. Проверяем валидность параметров генерации
Если Объект.Продолжительность <= 0 Тогда
    Сообщить("Укажите положительную продолжительность приема в минутах!");
    Возврат;
КонецЕсли;

ШагИнтервалаСекунд = Объект.Продолжительность * 60;

// 3. Обходим строки исходной таблицы
Для Каждого СтрокаТабПриемов Из Объект.ТабПриемов Цикл

    // Проверяем заполненность реквизитов
    Если Не ЗначениеЗаполнено(СтрокаТабПриемов.Время1) Или Не ЗначениеЗаполнено(СтрокаТабПриемов.Время2) Тогда
        Продолжить;
    КонецЕсли;
    
    // Проверяем корректность временного диапазона
    Если СтрокаТабПриемов.Время1 >= СтрокаТабПриемов.Время2 Тогда
        Продолжить;
    КонецЕсли;

    ТекущееВремя = СтрокаТабПриемов.Время1;
    
    // 4. Генерируем слоты в цикле
    Пока ТекущееВремя < СтрокаТабПриемов.Время2 Цикл
        
        ВремяОкончанияСлота = ТекущееВремя + ШагИнтервалаСекунд;
        
        // Ограничиваем слот временем окончания приема
        Если ВремяОкончанияСлота > СтрокаТабПриемов.Время2 Тогда
            ВремяОкончанияСлота = СтрокаТабПриемов.Время2;
        КонецЕсли;
        
        НоваяСтрока = Объект.ТабВремя.Добавить();
        НоваяСтрока.ДатаПриема = СтрокаТабПриемов.ДатаПриема;
        НоваяСтрока.НазвДня    = СтрокаТабПриемов.НазвДня;
        НоваяСтрока.Кабинет    = СтрокаТабПриемов.Кабинет;
        НоваяСтрока.Кресло     = СтрокаТабПриемов.Кресло;
        НоваяСтрока.ВремяН     = ТекущееВремя;
        НоваяСтрока.ВремяК     = ВремяОкончанияСлота;
        
        // Сдвигаем текущее время на шаг вперед
        ТекущееВремя = ВремяОкончанияСлота;
        
    КонецЦикла;

КонецЦикла;

Если Объект.ТабВремя.Количество() = 0 Тогда
    Сообщить("В таблице расписания нет корректно заполненных интервалов!");
КонецЕсли;

Важные рекомендации для надежной работы алгоритма

  1. Защита от бесконечного цикла: обязательно проверяйте, что реквизит Продолжительность строго больше нуля до входа в цикл Пока. Если к дате прибавлять 0, условие выхода никогда не выполнится, что приведет к зависанию клиента 1С.
  2. Очистка перед заполнением: всегда вызывайте ТабВремя.Очистить(), чтобы избежать дублирования строк при повторном нажатии на кнопку формирования.
  3. Контроль выхода за границу интервала: если общее время приема не кратно длительности слота (например, интервал 50 минут при шаге 40 минут), последний слот должен быть либо ограничен временем Время2, либо отброшен в зависимости от бизнес-логики задачи.
← На главную