Почему при выгрузке табличной части в Таблицу Значений у даты появляется время и как это исправить?

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

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

Физическая природа типа «Дата» в платформе 1С

Для начала давайте проанализируем, как устроена работа с датами в 1С. В платформе «1С:Предприятие 8» примитивный тип данных Дата является комбинированным. Он всегда содержит в себе как календарную дату, так и время (с точностью до секунды). Физически в СУБД (будь то MS SQL Server, PostgreSQL или файловая база данных) и в оперативной памяти компьютера переменная этого типа не может существовать без времени.

Когда в конфигураторе для реквизита мы выбираем состав даты:

Таким образом, полностью «стереть» время или заставить переменную типа Дата в отладчике выглядеть строго как 12.05.2026 без временной части технически невозможно. Значение 12.05.2026 00:00:00 — это и есть представление «просто даты» в системе 1С.

Почему «не сработал» квалификатор даты в коде автора?

В ходе обсуждения на форуме был предложен вариант с явным указанием квалификаторов даты при создании колонки таблицы значений:


МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("Дата"));
ПараметрыДаты = Новый КвалификаторыДаты(ЧастиДаты.Дата);

ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("ДатаНачала", Новый ОписаниеТипов(МассивТипов, , , ПараметрыДаты));

Автор темы попытался применить этот код, но написал, что метод «не сработал», поскольку время 00:00:00 все равно осталось в колонке. Выясним причину этого заблуждения.

На самом деле код сработал абсолютно верно и корректно. Квалификатор ЧастиДаты.Дата гарантирует, что при попытке записать в эту колонку дату со временем (например, 15.04.2026 14:30:15), платформа автоматически «отсечет» время, превратив его в 15.04.2026 00:00:00. Но поскольку тип данных остался Дата, платформа все равно отображает дефолтное нулевое время в отладчике и при стандартном выводе через функцию Сообщить(). Автор ожидал увидеть полное отсутствие символов времени, что невозможно для данного типа данных.

Кроме того, важно знать особенность работы метода Выгрузить(). При вызове Объект.Этапы.Выгрузить() платформа 1С автоматически создает таблицу значений, колонки которой полностью наследуют типы и квалификаторы из метаданных исходной табличной части. Если в свойствах реквизита ТЧ в конфигураторе уже был выбран состав «Дата», то колонка выгруженной ТЗ автоматически получит ограничение ЧастиДаты.Дата. Дополнительно переопределять её вручную программным кодом не имеет смысла.

Преобразование в строку (Антипаттерн из Сообщения 2)

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


ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("ДатаНачала", , "ДатаНачала");
// Добавление остальных колонок...

Для Каждого СтрокаТч Из Объект.Этапы Цикл
    ТЗДобавить = ТЗ.Добавить();
    ТЗДобавить.ДатаНачала = Формат(СтрокаТч.ДатаНачала, "ДЛФ=D");
    // Заполнение остальных колонок...
КонецЦикла;

Этот способ действительно убирает «визуальное» время, так как в колонку записывается обычная строка (например, "15.04.2026"). Однако использование строкового представления дат во внутренних таблицах значений — это плохая практика разработки, которая может привести к серьезным ошибкам в бизнес-логике:

  1. Проблемы с сортировкой. Строки сортируются посимвольно (алфавитно), а не хронологически. При сортировке по такой колонке дата "01.12.2025" окажется выше (раньше), чем "02.01.2026", так как первый символ "0" и второй "1" меньше, чем "0" и "2". Это полностью ломает логику хронологических отчетов.
  2. Невозможность группировки. Если вы захотите использовать метод таблицы значений Свернуть(), строковые представления дат могут группироваться некорректно при наличии разных региональных настроек сеанса.
  3. Сложность вычислений. Вы не сможете выполнять арифметические операции (например, прибавить к дате несколько дней) или передавать это значение в запросы без обратного ресурсоемкого преобразования строки в дату.

Правильные подходы к решению задачи

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

Способ 1. Форматирование в момент визуализации (Лучшая практика)

Если ваша единственная цель — вывести данные на печать в табличный документ или отобразить их пользователю на форме, то преобразовывать дату в коде не нужно. Оставьте значение полноценной датой, а форматирование доверьте механизмам представления платформы.

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

  1. Откройте макет вашего табличного документа в конфигураторе.
  2. Выберите ячейку, куда выводится параметр даты (например, <p>ТекущаяДата</p>).
  3. Откройте палитру свойств ячейки (клавиша F4).
  4. Найдите свойство «Формат» и нажмите на кнопку выбора (три точки).
  5. В открывшемся конструкторе форматной строки перейдите на вкладку «Дата» и выберите нужный вам формат (например, локальный формат даты ДЛФ=D или задайте собственный шаблон в поле «Форматная строка», например, ДФ=dd.MM.yyyy).

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


ОбластьМакета = Макет.ПолучитьОбласть("Строка");
ОбластьМакета.Параметры.ДатаНачала = СтрокаТч.ДатаНачала;
// Устанавливаем формат отображения непосредственно для ячейки
ОбластьМакета.Область("R1C1").Формат = "ДФ=dd.MM.yyyy"; 
ТабДок.Вывести(ОбластьМакета);

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

Способ 2. Программное обнуление времени в коде

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

Посмотрим на пример работы этой функции:


// Очищаем время для корректного сравнения
ДатаСравнения = НачалоДня(СтрокаТч.ДатаНачала);
Если ДатаСравнения = НачалоДня(ТекущаяДата()) Тогда
    // Выполняем алгоритм, если даты совпадают без учета времени
КонецЕсли;

Способ 3. Обнуление времени в запросах

Если вы получаете данные для последующего анализа или выгрузки из базы данных с помощью механизма запросов, временную часть можно эффективно обнулить на уровне СУБД с помощью функции НАЧАЛОПЕРИОДА() с периодичностью ДЕНЬ.

Рассмотрим пример такого запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	НАЧАЛОПЕРИОДА(Этапы.ДатаНачала, ДЕНЬ) КАК ДатаБезВремени,
    |	Этапы.Номер КАК Номер
    |ИЗ
    |	Документ.ЭтапыПроизводства КАК Этапы";

РезультатЗапроса = Запрос.Выполнить().Выгрузить();
// В колонке "ДатаБезВремени" таблицы значений будут даты со временем 00:00:00

Резюме

Подведем итоги нашего разбора:

← На главную