Как скопировать только время в другую дату в 1С:Предприятие

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

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

Разберем природу типа данных Дата в 1С, выясним причину возникновения ошибки и рассмотрим надежные способы переноса времени с сохранением целевой даты строки.

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

В платформе 1С:Предприятие тип данных Дата всегда содержит в себе и календарную дату, и время с точностью до секунды (в формате ГГГГММДДччммсс). Даже если у реквизита в метаданных установлен состав даты Время или на форме задан формат отображения ДЛФ=T, физически значение все равно хранит полную дату.

Если мы копируем значение напрямую:

СтрТабПриемов.Время1 = Врем1;

то в реквизит Время1 текущей строки полностью записывается дата источника (например, среда 07-е число), затирая дату текущего дня (четверг 08-е число). Чтобы скопировать только временную составляющую, необходимо выполнить объединение календарной даты приемника и времени источника.

Способ 1. Расчет через разницу секунд от начала дня

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

Рассмотрим формулу вычисления:


ИтоговаяДата = НачалоДня(ДатаПриемник) + (ВремяИсточник - НачалоДня(ВремяИсточник));

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

  1. Получаем начало дня для текущей строки таблицы: НачалоДня(СтрТабПриемов.ДатаПриема).
  2. Вычисляем смещение времени от полуночи: (Врем1 - НачалоДня(Врем1)).
  3. Складываем полученные значения и записываем результат в реквизит строки.

Посмотрим на пример процедур вставки по четным и нечетным дням с корректным вычислением даты:


&НаКлиенте
Процедура ВставитьПоЧетнымДням(Команда)
    Для Каждого СтрТабПриемов Из Объект.ТабПриемов Цикл
        Если День(СтрТабПриемов.ДатаПриема) % 2 = 0 Тогда
            СтрТабПриемов.Время1 = НачалоДня(СтрТабПриемов.ДатаПриема) + (Врем1 - НачалоДня(Врем1));
            СтрТабПриемов.Время2 = НачалоДня(СтрТабПриемов.ДатаПриема) + (Врем2 - НачалоДня(Врем2));
            СтрТабПриемов.Кабинет = Каб;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

&НаКлиенте
Процедура ВставитьПоНеЧетнымДням(Команда)
    Для Каждого СтрТабПриемов Из Объект.ТабПриемов Цикл
        Если День(СтрТабПриемов.ДатаПриема) % 2 <> 0 Тогда
            СтрТабПриемов.Время1 = НачалоДня(СтрТабПриемов.ДатаПриема) + (Врем1 - НачалоДня(Врем1));
            СтрТабПриемов.Время2 = НачалоДня(СтрТабПриемов.ДатаПриема) + (Врем2 - НачалоДня(Врем2));
            СтрТабПриемов.Кабинет = Каб;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Способ 2. Сборка даты через системный конструктор Дата()

Альтернативный надежный метод сборки — явная передача компонентов года, месяца и дня из целевой даты, а часов, минут и секунд — из даты-источника.

Рассмотрим пример функции:


&НаКлиенте
Функция СкомпоноватьДатуИВремя(ДатаДня, ВремяИсточник)
    Возврат Дата(
        Год(ДатаДня),
        Месяц(ДатаДня),
        День(ДатаДня),
        Час(ВремяИсточник),
        Минута(ВремяИсточник),
        Секунда(ВремяИсточник)
    );
КонецФункции

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

Способ 3. Преобразование через строковое представление

Еще один вариант объединения даты и времени заключается в использовании функции Формат() с последующим преобразованием строки в дату канонического вида:


&НаКлиенте
Функция СобратьДатуЧерезСтроку(ДатаДня, ВремяИсточник)
    СтрокаДаты = Формат(ДатаДня, "ДФ=yyyyMMdd") + Формат(ВремяИсточник, "ДФ=HHmmss");
    Возврат Дата(СтрокаДаты);
КонецФункции

Рекомендации по оптимизации кода

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

  1. Проверка четности чисел: Для проверки четности дня используйте оператор остатка от деления % (например, День(ДатаПриема) % 2 = 0). Это работает быстрее и надежнее строковых функций поиска подстроки Найти("02468", ...).
  2. Получение текущей строки таблицы: Свойство Элементы.Таблица.ТекущаяСтрока на управляемых формах возвращает числовой идентификатор строки, а не ее индекс в коллекции. Использование Объект.Таблица.Получить(...) по этому идентификатору вызывает исключение выхода за границы массива. Для получения данных строки на клиенте следует обращаться к свойству Элементы.ТабПриемов.ТекущиеДанные.
  3. Исключение лишней записи объекта: Не вызывайте метод Записать() внутри процедур копирования буфера обмена на форме. Копирование значений во временные переменные формы должно выполняться в оперативной памяти без лишних обращений к базе данных.
← На главную