Работа с датами в запросах 1С:Предприятие — одна из самых востребованных задач при разработке отчетов, обработок и интеграционных решений. Даже простая выборка документов за период может превратиться в головоломку, если не знать нюансов синтаксиса и особенностей преобразования типов. В этой статье мы разберем все способы выражения дат в запросах: от базовых конструкций ДАТАВРЕМЯ() до сложных условий с использованием виртуальных таблиц и временных функций.
Особое внимание уделим типичным ошибкам, которые приводят к некорректным результатам или падению производительности. Например, почему МЕЖДУ может пропустить крайние даты, как правильно сравнивать даты с временем, и почему нельзя слепо копировать SQL-синтаксис в 1С-запросы. Материал будет полезен как начинающим разработчикам, так и опытным специалистам, которые хотят оптимизировать свои запросы.
1. Базовый синтаксис дат в запросах 1С
В языке запросов 1С даты можно выражать несколькими способами, каждый из которых имеет свои особенности. Основной инструмент — функция ДАТАВРЕМЯ(), которая создает значение типа Дата из отдельных компонентов (год, месяц, день) или из строки.
Примеры базового использования:
- 📅
ДАТАВРЕМЯ(2026, 5, 15)— создаст дату 15 мая 2026 года без времени - ⏰
ДАТАВРЕМЯ(2026, 5, 15, 14, 30, 0)— та же дата, но с временем 14:30:00 - 📝
ДАТАВРЕМЯ("20260515")— альтернативный строковый формат (YYYYMMDD)
Например, ДАТАВРЕМЯ("15.05.2026") вызовет ошибку — сначала строку нужно привести к корректному формату с помощью ФОРМАТ() или других функций.
2. Работа с текущей датой и относительными периодами
Для динамических запросов, где нужно оперировать текущей датой или относительными периодами (например, "за последний месяц"), используются специальные функции:
| Функция | Описание | Пример результата (на 15.05.2026) |
|---|---|---|
ТЕКУЩАЯДАТА() | Возвращает текущую дату и время на сервере | 15.05.2026 14:30:00 |
НАЧАЛОПЕРИОДА() | Возвращает начало периода (день, месяц, квартал, год) | НАЧАЛОПЕРИОДА(ТЕКУЩАЯДАТА(), "МЕСЯЦ") → 01.05.2026 00:00:00 |
КОНЕЦПЕРИОДА() | Возвращает конец периода | КОНЕЦПЕРИОДА(ТЕКУЩАЯДАТА(), "ДЕНЬ") → 15.05.2026 23:59:59 |
ДОБАВИТЬМЕСЯЦ() | Сдвигает дату на указанное количество месяцев | ДОБАВИТЬМЕСЯЦ(ТЕКУЩАЯДАТА(), -1) → 15.04.2026 |
Эти функции особенно полезны в отчетах, где период формируется динамически. Например, чтобы получить документы за текущий месяц, можно написать:
ВЫБРАТЬ
Документ.Ссылка КАК Ссылка
ИЗ
Документ.ЗаказПокупателя КАК Документ
ГДЕ
Документ.Дата МЕЖДУ НАЧАЛОПЕРИОДА(ТЕКУЩАЯДАТА(), "МЕСЯЦ")
И КОНЕЦПЕРИОДА(ТЕКУЩАЯДАТА(), "МЕСЯЦ")
⚠️ Внимание: Функция ТЕКУЩАЯДАТА() возвращает дату и время на сервере 1С, а не на клиентском компьютере. Если сервер и клиент находятся в разных часовых поясах, это может привести к неожиданным результатам. Всегда проверяйте настройки часового пояса в кластере серверов.
3. Сравнение дат и интервалы: МЕЖДУ vs отдельные условия
Один из самых распространенных вопросов — как правильно задать интервал дат в запросе. На первый взгляд, конструкция МЕЖДУ кажется удобной:
ГДЕ
Документ.Дата МЕЖДУ &НачалоПериода И &КонецПериода
Однако у этого подхода есть критическая особенность: оператор МЕЖДУ включает обе границы интервала, но только если время в датах равно 00:00:00. Если в &КонецПериода указано время (например, 23:59:59), то документы с этой датой не попадут в выборку!
Безопасная альтернатива — использовать два отдельных условия:
ГДЕ
Документ.Дата >= &НачалоПериода
И Документ.Дата < ДОБАВИТЬКДАТЕ(&КонецПериода, СЕКУНДА, 1)
- ✅ Плюсы: работает корректно с любым временем в границах
- ⚡ Минусы: менее читаемый код, особенно при вложенных условиях
ГДЕ Документ.Дата >= ДАТАВРЕМЯ(2026, 5, 15)
И Документ.Дата < ДАТАВРЕМЯ(2026, 5, 16)
Это гарантированно включит все документы за 15 мая, независимо от времени их проведения.-->
4. Преобразование строк в даты и обратно
Часто данные о датах хранятся в строковом формате (например, в файлах обмена или внешних источниках). Чтобы использовать их в запросах, нужно правильно преобразовать строки в тип Дата. Для этого служат функции ВЫРАЗИТЬ() и ФОРМАТ().
Пример преобразования строки формата "DD.MM.YYYY":
ВЫБРАТЬ
ВЫРАЗИТЬ(ФОРМАТ("15.05.2026", "ДФ=yyyyMMdd") КАК ДАТА) КАК ПреобразованнаяДата
Обратное преобразование (дата в строку) выполняется с помощью ФОРМАТ() или ПРЕДСТАВИТЬ():
ВЫБРАТЬ
ФОРМАТ(Документ.Дата, "ДФ=dd.MM.yyyy") КАК ДатаСтрокой
⚠️ Внимание: При обмене данными с внешними системами (например, через REST API или JSON) даты часто передаются в форматеISO 8601(например,"2026-05-15T14:30:00"). Для корректного преобразования таких строк используйте комбинациюСТРЗАМЕНИТЬ()иФОРМАТ(), чтобы привести строку к форматуYYYYMMDDHHMMSS.
Что будет если передать некорректную строку в ВЫРАЗИТЬ?
Если строка не соответствует ожидаемому формату даты (например, "32.01.2026" или "abc"), функция ВЫРАЗИТЬ() вернет NULL, а не вызовет ошибку. Это может привести к скрытым багам, если не проверять результат на пустое значение.
5. Работа с виртуальными таблицами и датами
Виртуальные таблицы (например, Документ.ЗаказПокупателя.Обороты или РегистрНакопления.ТоварыНаСкладах.Остатки) часто требуют особого подхода к фильтрации по датам. Здесь нельзя использовать стандартные функции вроде НАЧАЛОПЕРИОДА() — нужно явно указывать параметры.
Пример корректного запроса к виртуальной таблице остатков:
ВЫБРАТЬ
ОстаткиТоваров.Номенклатура КАК Номенклатура,
ОстаткиТоваров.КоличествоОстаток КАК Остаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(
&НачалоПериода,
&КонецПериода,
Номенклатура В (&СписокНоменклатуры)
) КАК ОстаткиТоваров
Ключевые моменты:
- 🔹 Виртуальные таблицы всегда требуют явного указания периода (даже если он равен одному дню)
- 🔹 Параметры периода передаются как отдельные аргументы, а не через
ГДЕ - 🔹 Для таблиц оборотов можно использовать
Периодичность(например,ДЕНЬ,МЕСЯЦ)
☑️ Проверка запроса к виртуальной таблице
6. Оптимизация запросов с датами
Запросы с фильтрацией по датам могут становиться "узким местом" производительности, особенно в больших базах. Вот ключевые правила оптимизации:
- Индексы: Убедитесь, что поля дат проиндексированы в метаданных (свойство
Индексировать). Без индекса фильтрация по дате приводит к полному сканированию таблицы. - Параметры vs константы: Используйте параметры запроса (
&Параметр) вместо жестко заданных дат — это позволяет 1С кэшировать план выполнения. - Избегайте функций в ГДЕ: Конструкции вроде
ГДЕ ГОД(Документ.Дата) = 2026не используют индексы. Заменяйте их наГДЕ Документ.Дата >= ДАТАВРЕМЯ(2026,1,1) И Документ.Дата < ДАТАВРЕМЯ(2026,1,1).
Для сложных отчетов с группировкой по периодам (неделям, кварталам) используйте материализованные представления или внешние источники данных, если объем данных превышает 100 000 записей.
Самый быстрый способ фильтрации по дате — использование параметров запроса с индексированными полями и прямым сравнением (>=, <), без функций преобразования.
7. Типовые ошибки и их решения
Даже опытные разработчики сталкиваются с неожиданными ошибками при работе с датами. Вот самые распространенные ловушки:
| Ошибка | Причина | Решение |
|---|---|---|
| Ошибка приведения типа к дате | Передача пустой строки или некорректного формата в ДАТАВРЕМЯ() | Используйте ВЫРАЗИТЬ(ЗНАЧЕНИЕЗАПОЛНЕНО(..)) КАК ДАТА с проверкой на NULL |
| Не попадают документы за крайнюю дату | Использование МЕЖДУ с датами, содержащими время | Заменяйте на два отдельных условия с ДОБАВИТЬКДАТЕ() |
| Разные результаты на сервере и клиенте | Часовые пояса или настройки сеанса | Явно указывайте часовой пояс в ДАТАВРЕМЯ() или используйте ТЕКУЩАЯДАТАСЕРВЕРА() |
Особенно коварна ситуация, когда запрос не падает с ошибкой, но возвращает неверные данные. Например, при сравнении даты с временем (14:30:00) и даты без времени (00:00:00) результат может отличаться от ожидаемого. Всегда проверяйте формат данных в отладчике!
FAQ: Частые вопросы по датам в запросах 1С
Как в запросе получить первый и последний день месяца?
Используйте комбинацию НАЧАЛОПЕРИОДА() и КОНЕЦПЕРИОДА():
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(&ЛюбаяДата, "МЕСЯЦ") КАК ПервыйДень,
КОНЕЦПЕРИОДА(&ЛюбаяДата, "МЕСЯЦ") КАК ПоследнийДень
Если нужны первый/последний день текущего месяца, замените &ЛюбаяДата на ТЕКУЩАЯДАТА().
Почему запрос с МЕЖДУ не включает документы за последнюю дату?
Это происходит, если в переменной &КонецПериода указано ненулевое время. Например, ДАТАВРЕМЯ(2026,5,15,23,59,59) не попадёт в интервал МЕЖДУ.. И ДАТАВРЕМЯ(2026,5,15,23,59,59), потому что МЕЖДУ включает только даты с временем 00:00:00.
Решение: используйте два отдельных условия или обнуляйте время с помощью НАЧАЛОДНЯ().
Как сравнить дату без учёта времени?
Преобразуйте дату к началу дня с помощью НАЧАЛОДНЯ():
ГДЕ НАЧАЛОДНЯ(Документ.Дата) = НАЧАЛОДНЯ(&СравниваемаяДата)
Это гарантированно сравнит только календарные даты, игнорируя часы, минуты и секунды.
Можно ли в запросе использовать даты в формате "15 мая 2026"?
Нет, язык запросов 1С не поддерживает текстовые месяцы ("январь", "май" и т.д.). Используйте либо числовые параметры (ДАТАВРЕМЯ(2026,5,15)), либо строковый формат YYYYMMDD (ДАТАВРЕМЯ("20260515")).
Для вывода даты в текстовом формате используйте ФОРМАТ(Дата, "ДФ='d MMMM yyyy'") уже после выполнения запроса.
Как оптимизировать запрос с группировкой по неделям?
Используйте функцию НАЧАЛОНЕДЕЛИ() в комбинации с ГРУППИРОВКА ПО:
ВЫБРАТЬ
НАЧАЛОНЕДЕЛИ(Документ.Дата) КАК Неделя,
СУММА(Документ.Сумма) КАК Итого
ИЗ
Документ.ЗаказПокупателя КАК Документ
ГДЕ
Документ.Дата МЕЖДУ &НачалоПериода И &КонецПериода
СГРУППИРОВАТЬ ПО
НАЧАЛОНЕДЕЛИ(Документ.Дата)
Для ускорения добавьте в запрос условие по индексированному полю даты до применения функции НАЧАЛОНЕДЕЛИ().