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

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

Нередко при обработке данных разработчики сталкиваются с ситуацией, когда при попытке преобразовать дату в строковый формат внутри таблицы значений колонка неожиданно очищается, а функция ТипЗнч() возвращает Неопределено. Разберем механизм возникновения этой ошибки и рассмотрим корректные подходы к ее устранению.

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

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


ТаблицаЗначений = Запрос.Выполнить().Выгрузить();

Для Каждого Стр Из ТаблицаЗначений Цикл
    Стр.ДатаДокумента = Формат(Стр.ДатаДокумента, "ДФ=dd.MM.yyyy");
    Сообщить(ТипЗнч(Стр.ДатаДокумента)); // Выводит: Неопределено
КонецЦикла;

В этом примере результат запроса выгружается в объект ТаблицаЗначений. Метод Выгрузить() автоматически создает колонки с жесткой типизацией на основе типов полей выборки. Если в запросе поле имело тип Дата, соответствующая колонка таблицы значений получает объект ОписаниеТипов, содержащий только тип Дата.

Функция Формат() всегда возвращает значение типа Строка. Когда мы пытаемся присвоить строку жестко типизированной колонке с типом Дата, платформа 1С не вызывает исключение во время выполнения. Вместо этого платформа выполняет попытку неявного приведения типа. Поскольку произвольная строка формата dd.MM.yyyy не может быть автоматически приведена к системной дате, платформа подставляет пустое значение несовместимого типа — Неопределено.

Важно помнить: свойство ТипЗначения у объекта КолонкаТаблицыЗначений доступно только для чтения. Изменить состав допустимых типов у уже существующей колонки невозможно. Рассмотрим способы решения данной задачи.

Способ 1. Добавление новой строковой колонки

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


// Добавляем новую колонку строкового типа
ТаблицаЗначений.Колонки.Добавить("ДатаСтрокой", Новый ОписаниеТипов("Строка"));

Для Каждого Стр Из ТаблицаЗначений Цикл
    Стр.ДатаСтрокой = Формат(Стр.ДатаДокумента, "ДФ=dd.MM.yyyy");
КонецЦикла;

Этот подход прозрачен, не нарушает типизацию исходных данных и позволяет использовать строковое представление даты без риска очистки поля.

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

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

  1. Переименуем исходную типизированную колонку (например, во временное имя).
  2. Добавим новую колонку с прежним именем ДатаДокумента, указав строковый тип (или оставив ее нетипизированной).
  3. Заполним новую колонку отформатированными значениями из временной колонки.
  4. Удалим временную типизированную колонку методом ТаблицаЗначений.Колонки.Удалить().

Посмотрим на пример реализации:


// Шаг 1. Переименовываем исходную колонку
ТаблицаЗначений.Колонки.ДатаДокумента.Имя = "ДатаДокумента_Временная";

// Шаг 2. Создаем новую строковую колонку с исходным именем
ТаблицаЗначений.Колонки.Добавить("ДатаДокумента", Новый ОписаниеТипов("Строка"));

// Шаг 3. Заполняем строковыми значениями
Для Каждого Стр Из ТаблицаЗначений Цикл
    Стр.ДатаДокумента = Формат(Стр.ДатаДокумента_Временная, "ДФ=dd.MM.yyyy");
КонецЦикла;

// Шаг 4. Удаляем временную колонку
ТаблицаЗначений.Колонки.Удалить("ДатаДокумента_Временная");

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

Если задача заключается только в получении строкового вида даты без необходимости производить над ней дальнейшие математические операции с датами, воспользуемся возможностями языка запросов. Функция ПРЕДСТАВЛЕНИЕ() позволяет получить строковый вид поля прямо на уровне СУБД:


ВЫБРАТЬ
    ПРЕДСТАВЛЕНИЕ(НАЧАЛОПЕРИОДА(Документ.Дата, ДЕНЬ)) КАК ДатаСтрокой,
    Документ.Номер КАК Номер
ИЗ
    Документ.РеализацияТоваровУслуг КАК Документ

При выгрузке такого запроса колонка ДатаСтрокой сразу будет иметь строковый тип, и дополнительный обход таблицы в цикле не потребуется.

Способ 4. Разделение хранения данных и их представления (Best Practice для Excel)

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

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

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

Если для формирования файла на сервере используется ТабличныйДокумент (который можно напрямую сохранить в XLSX без использования COM-соединения и без установленного MS Excel), формат настраивается на уровне области ячеек:


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

// Сохраняем на сервере напрямую в XLSX
ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.XLSX);

Если же выгрузка выполняется через COM-объект приложения Excel, дату передают как есть, а формат отображения задают на уровне диапазона (Range):


Лист.Cells(НомерСтроки, 1).Value = Стр.ДатаДокумента;
Лист.Cells(НомерСтроки, 1).NumberFormat = "dd.mm.yyyy";

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

← На главную