При разработке отчетов или выгрузок (например, в формат CSV) программисты 1С часто сталкиваются с жестким ограничением языка запросов: в нем отсутствуют встроенные функции форматирования даты, такие как Format или Convert, привычные по SQL. Стандартная функция НАЧАЛОПЕРИОДА(Дата, ДЕНЬ) лишь обнуляет время, но не меняет тип данных — на выходе мы все равно получаем Дата, которая при выгрузке в текстовый файл превращается в строку с "хвостом" 00:00:00.
Рассмотрим подробнее, как решить эту задачу, если постобработка результата запроса в коде 1С крайне нежелательна, а система-приемник требует строго 10 символов даты (дд.мм.гггг).
Проанализируем самый сложный, но действенный метод: выделение каждой цифры числа (дня, месяца и года) с помощью арифметических операций и функции ВЫРАЗИТЬ, а затем получение нужного символа из константной строки. Это решение позволяет получить чистую строку прямо в SQL-запросе.
Разберем логику по шагам. Основная сложность заключается в том, что в запросе 1С нет функции получения остатка от деления или функции Целое. Однако мы можем имитировать их с помощью конструкции ВЫРАЗИТЬ(Число / Делитель - 0.5 КАК ЧИСЛО(10, 0)), которая принудительно округляет результат вниз.
Ниже приведен пример реализации такого "монструозного", но эффективного запроса:
ВЫБРАТЬ
Реестр.Ссылка,
Реестр.Дата КАК ИсходнаяДата
ПОМЕСТИТЬ ВТ_Данные
ИЗ
Документ.РеестрОтгрузки КАК Реестр
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Данные.Ссылка,
// Вычисляем составляющие даты
ДЕНЬ(Данные.ИсходнаяДата) КАК Д_Число,
МЕСЯЦ(Данные.ИсходнаяДата) КАК М_Число,
ГОД(Данные.ИсходнаяДата) КАК Г_Число
ПОМЕСТИТЬ ВТ_Компоненты
ИЗ
ВТ_Данные КАК Данные
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
// Сборка Дня (две цифры)
ПОДСТРОКА("0123456789", ВЫРАЗИТЬ(К.Д_Число / 10 - 0.5 КАК ЧИСЛО(10, 0)) + 1, 1) +
ПОДСТРОКА("0123456789", К.Д_Число - ВЫРАЗИТЬ(К.Д_Число / 10 - 0.5 КАК ЧИСЛО(10, 0)) * 10 + 1, 1) + "." +
// Сборка Месяца (две цифры)
ПОДСТРОКА("0123456789", ВЫРАЗИТЬ(К.М_Число / 10 - 0.5 КАК ЧИСЛО(10, 0)) + 1, 1) +
ПОДСТРОКА("0123456789", К.М_Число - ВЫРАЗИТЬ(К.М_Число / 10 - 0.5 КАК ЧИСЛО(10, 0)) * 10 + 1, 1) + "." +
// Сборка Года (четыре цифры)
ПОДСТРОКА("0123456789", ВЫРАЗИТЬ(К.Г_Число / 1000 - 0.5 КАК ЧИСЛО(10, 0)) + 1, 1) +
ПОДСТРОКА("0123456789", ВЫРАЗИТЬ((К.Г_Число - ВЫРАЗИТЬ(К.Г_Число / 1000 - 0.5 КАК ЧИСЛО(10, 0)) * 1000) / 100 - 0.5 КАК ЧИСЛО(10, 0)) + 1, 1) +
ПОДСТРОКА("0123456789", ВЫРАЗИТЬ((К.Г_Число - ВЫРАЗИТЬ(К.Г_Число / 100 - 0.5 КАК ЧИСЛО(10, 0)) * 100) / 10 - 0.5 КАК ЧИСЛО(10, 0)) + 1, 1) +
ПОДСТРОКА("0123456789", К.Г_Число - ВЫРАЗИТЬ(К.Г_Число / 10 - 0.5 КАК ЧИСЛО(10, 0)) * 10 + 1, 1) КАК ДатаСтрокой
ИЗ
ВТ_Компоненты КАК К
Важный нюанс: В функции ПОДСТРОКА мы добавляем + 1 к индексу, так как нумерация символов в строке начинается с единицы, а наши вычисленные цифры могут быть равны нулю.
Если ваша задача — вывести дату без времени в отчете или если запрос является частью схемы компоновки данных, то использовать "математические монстры" не нужно. Выясним, какие инструменты предоставляет СКД для изящного решения проблемы.
ДФ=dd.MM.yyyy. Это обеспечит визуальное отображение даты без времени везде, где используется этот набор данных.Формат(ДатаОтгрузки, "ДФ=dd.MM.yyyy"). В отличие от текста запроса, выражения СКД поддерживают функции встроенного языка.МойОбщийМодуль.ПреобразоватьДату(Дата). Это дает неограниченные возможности по форматированию, включая вывод месяца прописью или специфических разделителей.Рассмотрим ситуацию с использованием ПРЕДСТАВЛЕНИЕ(ПолеДата). Многие пытаются применить к этой конструкции ПОДСТРОКА, но получают ошибку. Проанализируем причину: ПРЕДСТАВЛЕНИЕ — это виртуальная функция, которая выполняется не СУБД, а сервером 1С при получении результата. Поэтому внутри запроса манипулировать этой строкой нельзя.
Однако: Если вы выполняете запрос и выгружаете его в таблицу значений через Запрос.Выполнить().Выгрузить(), то в колонке, для которой в запросе было указано ПРЕДСТАВЛЕНИЕ, уже будет лежать Строка. Ее формат будет зависеть от региональных настроек пользователя/сервера. Если в настройках ОС дата установлена без времени, то и в ТЗ она попадет в нужном виде.
Существует еще один необычный метод получения остатков и деления, использующий функции работы с датами. Мы можем перевести числовое значение дня или месяца в секунды, добавить их к пустой дате (01.01.0001) и затем вычленять из результата нужные компоненты. Рассмотрим пример для получения цифр:
ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, 6 * ДЕНЬ(&Дата))) / 6 + 0.5, 1)
Этот метод основан на том, что при делении на 6 и последующем добавлении 0.5 функция ВЫРАЗИТЬ (которая неявно вызывается внутри некоторых механизмов округления) может давать более стабильный результат для некоторых версий СУБД. Однако этот метод считается менее прозрачным и сложнее в отладке, чем прямое деление.
Подведем итог: какой метод выбрать?
Во-первых, если есть возможность сделать постобработку в коде — делайте ее там. Цикл по таблице значений с вызовом функции Формат() отработает быстрее и надежнее, чем сложный SQL-запрос с десятками вызовов ПОДСТРОКА.
Во-вторых, если вы работаете с СКД — используйте свойство "Формат" или "Вычисляемые поля". Это стандарт платформы, который гарантирует корректность данных.
В-третьих, если вы абсолютно ограничены только языком запроса (например, в некоторых специфических внешних источниках или при прямой передаче текста запроса в сторонние обработчики), используйте Решение 1 с математическим разложением. Это единственный способ получить гарантированную строку нужного формата непосредственно в выборке.