При автоматизации расписаний, графиков работы или журналов приемов часто возникает задача: скопировать введенное пользователем время в строки с другими датами (например, растиражировать график по четным или нечетным числам месяца). Однако разработчики сталкиваются с особенностью платформы 1С: при обычном присвоении значения реквизита типа Дата перезаписывается не только время, но и дата дня, из-за чего нарушается хронология строк.
Разберем природу типа данных Дата в 1С, выясним причину возникновения ошибки и рассмотрим надежные способы переноса времени с сохранением целевой даты строки.
В платформе 1С:Предприятие тип данных Дата всегда содержит в себе и календарную дату, и время с точностью до секунды (в формате ГГГГММДДччммсс). Даже если у реквизита в метаданных установлен состав даты Время или на форме задан формат отображения ДЛФ=T, физически значение все равно хранит полную дату.
Если мы копируем значение напрямую:
СтрТабПриемов.Время1 = Врем1;
то в реквизит Время1 текущей строки полностью записывается дата источника (например, среда 07-е число), затирая дату текущего дня (четверг 08-е число). Чтобы скопировать только временную составляющую, необходимо выполнить объединение календарной даты приемника и времени источника.
Любая дата в 1С представляет собой количество секунд. Чтобы получить «чистое» время, достаточно вычислить разницу в секундах между временем источника и началом дня этого же источника с помощью функции НачалоДня(). Полученное количество секунд прибавляется к началу целевого дня.
Рассмотрим формулу вычисления:
ИтоговаяДата = НачалоДня(ДатаПриемник) + (ВремяИсточник - НачалоДня(ВремяИсточник));
Разберем по шагам, как применить это решение в цикле заполнения табличной части:
НачалоДня(СтрТабПриемов.ДатаПриема).(Врем1 - НачалоДня(Врем1)).Посмотрим на пример процедур вставки по четным и нечетным дням с корректным вычислением даты:
&НаКлиенте
Процедура ВставитьПоЧетнымДням(Команда)
Для Каждого СтрТабПриемов Из Объект.ТабПриемов Цикл
Если День(СтрТабПриемов.ДатаПриема) % 2 = 0 Тогда
СтрТабПриемов.Время1 = НачалоДня(СтрТабПриемов.ДатаПриема) + (Врем1 - НачалоДня(Врем1));
СтрТабПриемов.Время2 = НачалоДня(СтрТабПриемов.ДатаПриема) + (Врем2 - НачалоДня(Врем2));
СтрТабПриемов.Кабинет = Каб;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура ВставитьПоНеЧетнымДням(Команда)
Для Каждого СтрТабПриемов Из Объект.ТабПриемов Цикл
Если День(СтрТабПриемов.ДатаПриема) % 2 <> 0 Тогда
СтрТабПриемов.Время1 = НачалоДня(СтрТабПриемов.ДатаПриема) + (Врем1 - НачалоДня(Врем1));
СтрТабПриемов.Время2 = НачалоДня(СтрТабПриемов.ДатаПриема) + (Врем2 - НачалоДня(Врем2));
СтрТабПриемов.Кабинет = Каб;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Альтернативный надежный метод сборки — явная передача компонентов года, месяца и дня из целевой даты, а часов, минут и секунд — из даты-источника.
Рассмотрим пример функции:
&НаКлиенте
Функция СкомпоноватьДатуИВремя(ДатаДня, ВремяИсточник)
Возврат Дата(
Год(ДатаДня),
Месяц(ДатаДня),
День(ДатаДня),
Час(ВремяИсточник),
Минута(ВремяИсточник),
Секунда(ВремяИсточник)
);
КонецФункции
Такой подход наглядно разделяет составляющие даты и полностью исключает ошибки переполнения при работе с датами.
Еще один вариант объединения даты и времени заключается в использовании функции Формат() с последующим преобразованием строки в дату канонического вида:
&НаКлиенте
Функция СобратьДатуЧерезСтроку(ДатаДня, ВремяИсточник)
СтрокаДаты = Формат(ДатаДня, "ДФ=yyyyMMdd") + Формат(ВремяИсточник, "ДФ=HHmmss");
Возврат Дата(СтрокаДаты);
КонецФункции
Проанализируем сопутствующие ошибки, которые часто встречаются при написании подобных алгоритмов:
% (например, День(ДатаПриема) % 2 = 0). Это работает быстрее и надежнее строковых функций поиска подстроки Найти("02468", ...).Элементы.Таблица.ТекущаяСтрока на управляемых формах возвращает числовой идентификатор строки, а не ее индекс в коллекции. Использование Объект.Таблица.Получить(...) по этому идентификатору вызывает исключение выхода за границы массива. Для получения данных строки на клиенте следует обращаться к свойству Элементы.ТабПриемов.ТекущиеДанные.Записать() внутри процедур копирования буфера обмена на форме. Копирование значений во временные переменные формы должно выполняться в оперативной памяти без лишних обращений к базе данных.