Разработка и Конфигурация · 12 мин
Дата как строка в запросе 1С: как преобразовать и сравнить
Как работать с датой, хранящейся строкой, в запросе 1С: функции ДАТАВРЕМЯ, ПОДСТРОКА, сравнение, преобразование строки в дату и типичные ошибки.
В запросах 1С нередко встречается ситуация, когда дата хранится не в реквизите типа «Дата», а в строковом поле — например, в регистре сведений с универсальным строковым значением, в комментарии, в данных, загруженных из внешней системы, или в составном реквизите. Прямое сравнение такой строки с датой невозможно: платформа либо вернёт ошибку о несоответствии типов, либо выполнит лексикографическое сравнение строк, которое не совпадает с хронологическим порядком.
Задача сводится к двум сценариям: либо преобразовать строку в дату прямо в запросе, либо наоборот — привести дату-константу к строковому виду и сравнивать строки. У каждого подхода есть ограничения: язык запросов 1С не содержит полноценной функции парсинга произвольной строки в дату, поэтому приходится использовать конструкции с ПОДСТРОКА, ВЫБОР и вычисляемыми полями, а иногда выносить преобразование за пределы запроса.
Ниже разобраны рабочие приёмы: как отфильтровать записи по строковой дате, как собрать дату из фрагментов строки, как сравнивать периоды и какие ошибки чаще всего приводят к неверным результатам или падению производительности.
Как устроена проблема: почему строка не сравнивается с датой
Тип «Дата» в 1С хранит значение с точностью до секунды и сравнивается хронологически. Строка сравнивается посимвольно по кодам символов. Поэтому условие СтроковоеПоле = &Дата либо вызовет ошибку несовместимости типов, либо (при неявном приведении) даст непредсказуемый результат, зависящий от СУБД.
Даже сравнение двух строк, содержащих даты, опасно. Строки «01.02.2026» и «15.01.2026» при лексикографическом сравнении упорядочатся неверно: «01.02.2026» окажется «меньше», хотя по хронологии это более поздняя дата. Корректно строки сравниваются только в форматах с фиксированной шириной и порядком «год-месяц-день», например «2026-02-01» или «20260201».
Отсюда практическое правило: прежде чем писать условие, определите точный формат хранения и проверьте, все ли значения в поле ему соответствуют. Один «мусорный» символ или пустая строка способны сломать преобразование для всей выборки при использовании вычисляемых выражений.
Способ 1: собрать дату из строки функциями запроса
Если строка имеет строго фиксированный формат, дату можно сконструировать функцией ДАТАВРЕМЯ(год, месяц, день), извлекая фрагменты функцией ПОДСТРОКА. Функция ПОДСТРОКА возвращает строку, поэтому результат нужно привести к числу через ВЫРАЗИТЬ(... КАК ЧИСЛО) либо передать как есть — в ряде случаев платформа выполнит неявное приведение, но явное надёжнее.
Пример для строки формата «ГГГГММДД» длиной 8 символов:
ВЫБРАТЬ
ДАТАВРЕМЯ(
ВЫРАЗИТЬ(ПОДСТРОКА(Таб.СтрокаДаты, 1, 4) КАК ЧИСЛО(4)),
ВЫРАЗИТЬ(ПОДСТРОКА(Таб.СтрокаДаты, 5, 2) КАК ЧИСЛО(2)),
ВЫРАЗИТЬ(ПОДСТРОКА(Таб.СтрокаДаты, 7, 2) КАК ЧИСЛО(2))
) КАК ДатаИзСтроки
ИЗ РегистрСведений.Данные КАК Таб
ГДЕ ДАТАВРЕМЯ(
ВЫРАЗИТЬ(ПОДСТРОКА(Таб.СтрокаДаты, 1, 4) КАК ЧИСЛО(4)),
ВЫРАЗИТЬ(ПОДСТРОКА(Таб.СтрокаДаты, 5, 2) КАК ЧИСЛО(2)),
ВЫРАЗИТЬ(ПОДСТРОКА(Таб.СтрокаДаты, 7, 2) КАК ЧИСЛО(2))
) МЕЖДУ &НачалоПериода И &КонецПериода
Для формата «ДД.ММ.ГГГГ» порядок фрагментов меняется: день — символы 1–2, месяц — 4–5, год — 7–10. Функция ДАТАВРЕМЯ при недопустимых значениях (месяц 13, день 32, нечисловые символы) вызовет ошибку выполнения запроса, поэтому выборку стоит предварительно ограничить условием на длину строки и отсутствие пустых значений.
Способ 2: сравнить строки без преобразования
Когда строка хранится в сортировочно-безопасном формате «ГГГГММДД» или «ГГГГ-ММ-ДД», преобразование в дату вообще не обязательно: диапазон можно задать строковыми границами. Параметры передаются как строки той же ширины, и условие МЕЖДУ "20260101" И "20261231" корректно отработает хронологически.
Этот приём быстрее, чем вычисляемое выражение: СУБД может использовать индекс по строковому полю, тогда как функция ПОДСТРОКА в условии отключает индекс и приводит к полному сканированию таблицы. На больших регистрах разница во времени выполнения существенна.
Ограничение очевидно: метод не работает для форматов «ДД.ММ.ГГГГ», «ММ/ДД/ГГГГ» и любых представлений с переменной шириной. Также нужно следить, чтобы в сравнении не участвовали строки с часовыми поясами или временем в разном виде.
Сравнение вариантов
Подходит для любого фиксированного формата, даёт настоящий тип Дата. Минусы: нельзя использовать индекс, ошибка на «грязных» данных, громоздкий текст запроса.
Самый быстрый вариант для форматов ГГГГММДД с ведущими нулями. Не подходит для форматов, где день идёт перед месяцем и годом.
Строка переводится в дату встроенным языком, в запрос передаётся параметр типа Дата. Универсально и безопасно, но требует обхода данных в коде и не работает для фильтрации прямо в СУБД.
Способ 3: преобразовать строку до запроса и передать параметром
Самый надёжный путь для произвольных форматов — выполнить парсинг средствами встроенного языка. Конструктор Дата("20260115") принимает строку в формате ГГГГММДД (и с временем ГГГГММДДЧЧММСС). Для строк вида «15.01.2026» используют разбор через СтрРазделить и сборку, либо функцию XMLЗначение(Тип("Дата"), "2026-01-15T00:00:00") для канонического представления.
СтрокаИзИсточника = "15.01.2026";
Части = СтрРазделить(СтрокаИзИсточника, ".");
Если Части.Количество() = 3 Тогда
ДатаПараметр = Дата(Части[2] + Части[1] + Части[0]);
КонецЕсли;
Запрос.УстановитьПараметр("ДатаОтбора", ДатаПараметр);
Обратная задача — передать дату как строку в запрос — решается функцией Формат(Дата, "ДФ=yyyyMMdd"). Важно явно задавать форматную строку: представление даты по умолчанию зависит от региональных настроек сеанса, и на разных серверах одна и та же дата может превратиться в «15.01.2026» или «1/15/2026».
Параметры запроса: дата, переданная строкой
Частая ситуация: разработчик передаёт в параметр строку, а сравнивает её с реквизитом типа «Дата». Платформа не выполнит неявное преобразование параметра — запрос упадёт с ошибкой несоответствия типов. Параметр всегда нужно приводить к типу Дата до передачи:
Запрос.Текст = "ВЫБРАТЬ * ИЗ Документ.Реализация КАК Д
|ГДЕ Д.Дата >= &Период";
// Неверно: Запрос.УстановитьПараметр("Период", "20260101");
// Верно:
Запрос.УстановитьПараметр("Период", Дата("20260101"));
Если источник параметра — пользовательский ввод или данные обмена, оберните преобразование в попытку и проверяйте результат на пустую дату (01.01.0001): многие внешние системы передают пустое значение как «0001-01-01» или пустую строку, что после парсинга даёт либо ошибку, либо дату начала отсчёта, искажающую отбор.
- 1Определите фактический формат строки: выберите несколько различных значений поля запросом.
- 2Проверьте наличие пустых строк, NULL и значений, не соответствующих шаблону.
- 3Если формат ГГГГММДД — используйте строковое сравнение МЕЖДУ с параметрами-строками той же ширины.
- 4Если формат иной и фиксированный — соберите дату через ДАТАВРЕМЯ и ПОДСТРОКА с приведением к ЧИСЛО.
- 5Если формат произвольный или данные «грязные» — преобразуйте строку в дату в коде и передайте параметром типа Дата.
- 6Проверьте результат на контрольной выборке с известными граничными значениями.
Производительность и проверка результата
Вычисляемые выражения в условии ГДЕ — главный источник проблем. Условие ГДЕ ПОДСТРОКА(Поле, 1, 8) = "20260115" заставляет СУБД вычислять подстроку для каждой строки таблицы, индекс не используется. На таблицах в сотни тысяч записей запрос может выполняться в десятки раз дольше, чем эквивалентное сравнение поля с параметром.
Приём оптимизации — вынести вычисляемое поле во временную таблицу один раз, проиндексировать его и дальше соединяться уже по готовому значению. Альтернатива на уровне конфигурации — добавить в объект нормальный реквизит типа «Дата» и заполнить его обработкой, если строковое хранение диктовалось обменом, а не требованием.
Контроль результата: сравните количество записей, попавших в выборку, с ожидаемым, проверьте граничные даты (первая и последняя в периоде), а также убедитесь, что время не «срезало» последний день — классическая ошибка, когда верхняя граница задана как начало дня, а у документов есть время.
Как проверить результат
Совпадает с контрольным подсчётом по тем же данным
Меньше ожидаемого — вероятно, отсеклись записи с нестандартным форматом или временем
Документы первого и последнего дня присутствуют
Последний день отсутствует — верхняя граница задана началом дня вместо конца
Все строки имеют ожидаемую дату, нет 01.01.0001
Встречаются пустые даты — исходные строки не парсятся
Типичные ошибки и их последствия
Самая распространённая ошибка — сравнение строки с датой напрямую и надежда на неявное приведение типов. Вторая по частоте — использование Формат() без форматной строки, из-за чего код работает на компьютере разработчика и ломается на сервере с другими региональными настройками. Третья — забвение про время: сравнение «начало дня = дата документа» не срабатывает для документов, проведённых после полуночи.
Отдельная группа проблем — данные обмена. Внешние системы присылают даты в ISO-формате с временной зоной («2026-01-15T14:30:00+03:00»), в виде Unix-времени числом или локализованных строк. Каждый такой случай требует отдельной нормализации до того, как значение попадёт в запрос.
Что важно запомнить
Прямой функции «строка в дату» в языке запросов 1С нет. Для фиксированных форматов дату собирают через ДАТАВРЕМЯ и ПОДСТРОКА, для формата ГГГГММДД достаточно строкового сравнения, для произвольных строк преобразование выполняют в коде и передают параметром типа Дата. Всегда проверяйте единообразие исходных данных и задавайте форматную строку явно.
Частые вопросы
Можно ли в запросе 1С напрямую преобразовать строку «15.01.2026» в дату одной функцией?
Нет, в языке запросов нет функции парсинга произвольной строки. Варианты: собрать дату через ДАТАВРЕМЯ с извлечением фрагментов ПОДСТРОКА (работает при фиксированном формате) или выполнить преобразование во встроенном языке до запроса и передать готовую дату параметром.
Почему условие ГДЕ СтроковоеПоле = &Дата выдаёт ошибку?
Потому что типы несовместимы: строка и дата сравниваются по разным правилам, и платформа не выполняет неявное приведение параметра. Либо приводите параметр к строке через Формат() с явным шаблоном, либо преобразуйте строковое поле к дате выражением ДАТАВРЕМЯ.
Как сравнить строковые даты формата «ДД.ММ.ГГГГ» без преобразования?
Надёжно — никак: лексикографический порядок таких строк не совпадает с хронологическим. Нужно либо собрать дату через ДАТАВРЕМЯ(ПОДСТРОКА(...,7,4), ПОДСТРОКА(...,4,2), ПОДСТРОКА(...,1,2)), либо переставить фрагменты конкатенацией в порядок ГГГГММДД и сравнивать уже эти строки.
Как передать в запрос дату, полученную строкой из файла обмена?
Разберите строку в коде: для «ГГГГММДД» подойдёт Дата(Строка), для «ГГГГ-ММ-ДД» — XMLЗначение(Тип("Дата"), Строка), для прочих форматов — разбор через СтрРазделить и сборка. Затем передайте результат через УстановитьПараметр как значение типа Дата.
Запрос с ПОДСТРОКА в условии работает очень медленно. Что делать?
Функция над полем в условии ГДЕ отключает использование индекса. Варианты: вынести вычисленное значение во временную таблицу и индексировать её, заменить условие на сравнение исходного поля со строковым параметром (если формат позволяет) или добавить в объект реквизит типа «Дата» и заполнить его обработкой.
Как учесть время, если строка содержит дату и время?
Функция ДАТАВРЕМЯ принимает шесть аргументов: год, месяц, день, час, минута, секунда — извлеките все фрагменты ПОДСТРОКА. Если время не нужно, сравнивайте с границами дня: от НачалоДня до КонецДня, вычисленных в коде, чтобы не потерять записи последнего дня периода.