В практике разработчика 1С часто встречается задача постобработки данных, полученных из запроса. Типичный сценарий: мы получаем таблицу значений (ТЗ) с колонками типа Дата, содержащими время, и хотим привести их к строковому формату без времени (например, для передачи на сайт или в стороннюю систему). Однако при попытке присвоить результат функции Формат() в существующую колонку, значение может неожиданно стать Неопределено или очиститься. Разберем подробно, почему это происходит и как решить задачу несколькими способами.
Проанализируем ситуацию: когда мы получаем таблицу значений как результат выполнения запроса методом Выгрузить(), платформа 1С автоматически назначает колонкам этой таблицы строго определенные типы данных. Эти типы напрямую зависят от типов полей в базе данных, которые были выбраны в тексте запроса.
Если в запросе выбрано поле типа Дата, то и колонка в итоговой ТЗ будет иметь тип Дата. Функция Формат(стр.ДатаРождения, "ДФ=dd.MM.yyyy") возвращает значение типа Строка. В 1С нельзя записать строку в колонку, предназначенную строго для хранения даты. В зависимости от контекста, платформа либо попытается неявно преобразовать строку обратно в дату (если формат совпадает), либо просто очистит значение, установив его в Неопределено или пустую дату.
Почему же иногда это работает для одной колонки и не работает для другой? Посмотрим на описание типов колонок. Если колонка была получена из свойства или в результате сложного выражения, она могла получить составной тип (например, Дата и Строка), что позволяет записывать туда данные обоих типов. Если же тип строго ограничен одним значением, присвоение данных другого типа не удастся.
Один из самых простых, хотя и несколько "хитрых" способов — заставить систему создать колонку с составным типом (включающим строку) еще на этапе выполнения запроса. Рассмотрим пример, как можно модифицировать запрос, чтобы колонка принимала строковые значения:
ВЫБОР
КОГДА ФизЛицо.ДатаРождения ЕСТЬ NULL
ТОГДА ""
ИНАЧЕ ФизЛицо.ДатаРождения
КОНЕЦ КАК ДатаРождения
В данном случае, используя конструкцию ВЫБОР, мы указываем системе, что поле может содержать как дату, так и пустую строку. Платформа сформирует в таблице значений колонку с составным типом, и в коде 1С вы сможете спокойно перезаписать дату строкой, полученной через Формат().
Важный нюанс: чтобы гарантировать достаточную длину строки в колонке, иногда используют прием с добавлением пробелов:
ЕСТЬNULL(ФизЛицо.ДатаРождения, " ") КАК ДатаРождения
Здесь 10 пробелов резервируют место под строку длиной 10 символов (стандарт для даты формата ДД.ММ.ГГГГ).
Если изменять запрос нежелательно или невозможно, разберем алгоритм программной модификации структуры Таблицы Значений. Поскольку изменить тип уже существующей колонки в 1С нельзя, мы пойдем путем добавления новой колонки с последующей подменой данных.
Рассмотрим пошагово, как это реализовать:
Строка в существующей таблице.Дата.Пример кода для реализации этого метода:
// Добавляем новые колонки
Результат.Колонки.Добавить("ДатаРегистрацииСтрока", Новый ОписаниеТипов("Строка"));
Результат.Колонки.Добавить("ДатаРожденияСтрока", Новый ОписаниеТипов("Строка"));
Для каждого Стр Из Результат Цикл
// Заполняем новые колонки строковыми представлениями
Стр.ДатаРегистрацииСтрока = Формат(Стр.ДатаРегистрации, "ДФ=dd.MM.yyyy");
Стр.ДатаРожденияСтрока = Формат(Стр.ДатаРождения, "ДФ=dd.MM.yyyy");
КонецЦикла;
// Если нужно сохранить исходные имена колонок, удаляем старые и переименовываем новые
Результат.Колонки.Удалить("ДатаРегистрации");
Результат.Колонки.Удалить("ДатаРождения");
Результат.Колонки.ДатаРегистрацииСтрока.Имя = "ДатаРегистрации";
Результат.Колонки.ДатаРожденияСтрока.Имя = "ДатаРождения";
Иногда программисту требуется "срубить" время не ради строкового представления, а для корректной передачи даты. Выясним причину, по которой НАЧАЛОПЕРИОДА может выдавать ошибку в запросе. Обычно это происходит из-за пустых значений (NULL). Посмотрим, как правильно использовать функции работы с датой в коде и запросе.
В коде 1С функция НачалоДня(Дата) возвращает ту же дату, но со временем 00:00:00. Если ваша задача — передать данные на сайт, который понимает формат XML или JSON, можно воспользоваться встроенной функцией XMLСтрока(). Она автоматически преобразует дату в стандарт ISO без лишних манипуляций с форматом.
// Пример получения строки даты в формате ГГГГ-ММ-ДД
ЗначениеДляСайта = XMLСтрока(НачалоДня(ТекущаяДата()));
Если для вашей выгрузки критичен порядок полей в ТЗ (например, этого требует скрипт на стороне сайта), используйте метод Сдвинуть(). Разберем на примере:
Предположим, вы добавили новую колонку, и она оказалась в самом конце таблицы. Чтобы поставить ее на место второй колонки (индекс 1), используйте следующий код:
ИндексНужногоМеста = 1;
Колонка = Результат.Колонки.ДатаРожденияСтрока;
Смещение = ИндексНужногоМеста - Результат.Колонки.Индекс(Колонка);
Результат.Колонки.Сдвинуть(Колонка, Смещение);
Это позволит вам программно сформировать структуру таблицы, в точности соответствующую требованиям принимающей стороны, избегая при этом ошибок типизации.
Мы выяснили, что основной причиной ошибки является жесткая типизация колонок Таблицы Значений, создаваемых запросом. Для решения проблемы мы можем либо ослабить типизацию в самом запросе через ВЫБОР или ЕСТЬNULL, либо программно перестроить таблицу, создав колонки с типом Строка. Выбор метода зависит от сложности вашего запроса и требований к производительности системы. При работе с внешними системами также всегда стоит рассматривать использование XMLСтрока() как наиболее надежный стандарт преобразования данных.