Работа с датами в запросах 1С — одна из самых частых задач при разработке отчетов, обработок и интеграций. Казалось бы, что может быть проще, чем получить текущую дату? Однако даже здесь есть нюансы: разные версии платформы, особенности СУБД (PostgreSQL, MS SQL, файловая база) и контекст выполнения запроса могут влиять на результат. Новички часто допускают ошибки, используя не те функции или забывая про параметры, что приводит к некорректной фильтрации данных.
В этой статье мы разберем все актуальные способы получения текущей даты в запросах 1С:Предприятие 8.3, включая редкие случаи, когда стандартные методы не работают. Вы узнаете, чем отличается ТекущаяДата() от Дата(), как передавать дату через параметры и почему иногда лучше использовать виртуальные таблицы. Материал будет полезен как начинающим разработчикам, так и опытным программистам, столкнувшимся с неочевидными багами.
1. Стандартная функция ТекущаяДата() — простой, но не всегда безопасный способ
Самый очевидный метод — использовать встроенную функцию ТекущаяДата() прямо в тексте запроса. Она возвращает текущие дату и время на сервере 1С в момент выполнения запроса. Пример:
ВЫБРАТЬ
ТекущаяДата() КАК ТекущаяДатаСервера
На первый взгляд, все просто. Но здесь кроются два подводных камня:
- 🔹 Зависимость от серверного времени. Если сервер и клиент находятся в разных часовых поясах, результат может отличаться от ожидаемого. Например, при работе через RDP или в распределенных базах.
- 🔹 Кэширование запросов. В некоторых случаях платформа 1С может кэшировать результат запроса, и
ТекущаяДата()вернет устаревшее значение. Это актуально для фоновых заданий или длительных операций.
Чтобы избежать проблем с кэшированием, рекомендуется явно указывать параметр РАЗРЕШИТЬ КЭШИРОВАНИЕ = ЛОЖЬ в настройках запроса. Пример:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТекущаяДата() КАК ТекущаяДата
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.ДатаСоздания > ТекущаяДата() - 30";
Запрос.УстановитьПараметр("Кэшировать", Ложь); // Отключаем кэширование
Результат = Запрос.Выполнить();
Если вам нужно получить дату без времени (только дату), используйте конструкцию НАЧАЛОДНЯ(ТекущаяДата()). Это избавит от проблем с сравнением дат, где время может мешать точной фильтрации.
2. Функция Дата() — когда нужна конкретная дата, а не "сейчас"
Функция Дата() в запросах 1С работает иначе, чем ТекущаяДата(). Она не возвращает текущую дату, а служит для создания даты из отдельных компонентов (год, месяц, день). Однако ее можно использовать для получения "сегодняшней" даты, если передать текущие значения:
ВЫБРАТЬ
Дата(Год(ТекущаяДата()), Месяц(ТекущаяДата()), День(ТекущаяДата())) КАК СегодняБезВремени
Такой подход полезен, когда:
- 📅 Нужно сравнивать даты без учета времени (например, для фильтрации документов "за сегодня").
- ⏱️ Требуется "обнулить" время, чтобы избежать погрешностей при сравнении с датами из справочников, где время может быть
00:00:00. - 🔄 Необходимо гарантированно получить дату на начало дня, независимо от текущего времени.
Если передать в нее неверные аргументы (например, 31 февраля), запрос завершится с ошибкой. Поэтому всегда проверяйте корректность передаваемых значений.
Что будет, если передать несуществующую дату в функцию Дата()?
При передаче некорректных значений (например, Дата(2023, 2, 30) для 30 февраля) запрос завершится с ошибкой:
Ошибка при вызове метода контекста (Дата): Неверная дата.
В отличие от встроенного языка 1С, где некорректная дата преобразуется в Дата(1,1,1), в запросах это приводит к исключению.
3. Передача текущей даты через параметры — лучший способ для сложных запросов
Опытные разработчики 1С предпочитают передавать текущую дату в запрос через параметры. Это дает несколько преимуществ:
- ⚡ Прозрачность кода. Видно, какие данные передаются в запрос, что упрощает отладку.
- 🔄 Гибкость. Легко заменить текущую дату на любую другую без изменения текста запроса.
- 🛡️ Защита от кэширования. Параметры не кэшируются, в отличие от функций внутри запроса.
Пример передачи текущей даты через параметр:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Документ.ЗаказКлиента.Ссылка КАК Ссылка,
| Документ.ЗаказКлиента.Дата КАК ДатаЗаказа
|ИЗ
| Документ.ЗаказКлиента КАК Документ.ЗаказКлиента
|ГДЕ
| Документ.ЗаказКлиента.Дата >= &ТекущаяДата";
Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДата());
Результат = Запрос.Выполнить();
Такой подход особенно важен в следующих сценариях:
- 📊 Отчеты с динамическими периодами, где пользователь может выбрать произвольную дату вместо "сегодня".
- 🔄 Фоновые задания, где время выполнения запроса может отличаться от времени формирования задачи.
- 🌍 Распределенные базы, где серверное время на разных узлах может расходиться.
Убедитесь, что параметр имеет корректный тип (Дата, а не Строка)
Проверьте часовой пояс сервера и клиента при работе с распределенными базами
Отключите кэширование, если запрос выполняется многократно с разными параметрами
Используйте именованные параметры (&Имя) вместо позиционных (?), чтобы избежать путаницы-->
4. Использование виртуальных таблиц — альтернатива для отчетов
В некоторых случаях текущую дату удобно получать через виртуальные таблицы, особенно если она нужна для сравнения с данными из регистров. Например, виртуальная таблица РегистрНакопления.Остатки позволяет получить остатки на текущую дату без явного указания даты в запросе.
Пример:
ВЫБРАТЬ
ОстаткиТоваровОстатки.Номенклатура КАК Номенклатура,
ОстаткиТоваровОстатки.КоличествоОстаток КАК Остаток
ИЗ
РегистрНакопления.ОстаткиТоваров.Остатки(
&ТекущаяДата,
Номенклатура В (
ВЫБРАТЬ
Справочник.Номенклатура.Ссылка
ИЗ
Справочник.Номенклатура
ГДЕ
Справочник.Номенклатура.ЭтоГруппа = ЛОЖЬ
)
) КАК ОстаткиТоваровОстатки
Преимущества этого подхода:
- 📈 Автоматическое обновление. Виртуальные таблицы всегда возвращают актуальные данные на момент выполнения.
- 🔍 Упрощение кода. Не нужно писать сложные соединения (
JOIN) для получения остатков. - 🛠️ Поддержка платформой. Виртуальные таблицы оптимизированы и работают быстрее, чем ручные запросы к регистрам.
Однако есть и ограничения. Виртуальные таблицы не поддерживаются в файловом варианте базы 1С (только для SQL-серверов). Кроме того, их синтаксис может отличаться в разных версиях платформы, поэтому перед использованием проверьте совместимость.
Виртуальные таблицы — самый эффективный способ работы с остатками и оборотами на текущую дату, но они доступны только в клиент-серверном варианте 1С.
5. Особенности работы с разными СУБД: MS SQL vs PostgreSQL vs файловая база
Поведение функций даты в запросах 1С может отличаться в зависимости от используемой СУБД. Рассмотрим ключевые различия:
| СУБД | Функция ТекущаяДата() | Часовой пояс | Особенности |
|---|---|---|---|
| MS SQL Server | Использует GETDATE() |
Серверное время | Поддерживает виртуальные таблицы, высокая производительность |
| PostgreSQL | Использует CURRENT_TIMESTAMP |
Настраивается в конфигурации сервера | Может требовать явного приведения типов в сложных запросах |
| Файловая база | Встроенная функция 1С | Локальное время компьютера | Нет поддержки виртуальных таблиц, медленнее при больших объемах данных |
Например, в PostgreSQL иногда возникают проблемы с неявным приведением типов. Если вы получаете ошибку вида Ошибка оператора: operator does not exist: timestamp without time zone = date, явно преобразуйте типы:
ВЫБРАТЬ
Документ.РеализацияТоваровУслуг.Ссылка КАК Ссылка
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ.РеализацияТоваровУслуг
ГДЕ
ДАТАВРЕМЯ(Документ.РеализацияТоваровУслуг.Дата, "00:00:00") = ДАТАВРЕМЯ(&ТекущаяДата, "00:00:00")
Для MS SQL аналогичная проблема решается проще:
ВЫБРАТЬ
Документ.РеализацияТоваровУслуг.Ссылка КАК Ссылка
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ.РеализацияТоваровУслуг
ГДЕ
CONVERT(DATE, Документ.РеализацияТоваровУслуг.Дата) = CONVERT(DATE, &ТекущаяДата)
Если вы разрабатываете универсальное решение для разных СУБД, используйте параметры вместо встроенных функций даты. Это избавит от необходимости писать разный код для каждой базы.
6. Распространенные ошибки и как их избежать
Даже опытные разработчики иногда допускают ошибки при работе с датами в запросах. Вот TOP-5 проблем и способы их решения:
-
Сравнение даты с временем и без времени
Ошибка:
ГДЕ ДатаДокумента = ТекущаяДата()не сработает, если вДатаДокументаесть время (например,10.05.2023 14:30:00), аТекущаяДата()возвращает10.05.2023 15:45:22.Решение: Используйте
НАЧАЛОДНЯ()для обеих сторон сравнения:ГДЕ НАЧАЛОДНЯ(ДатаДокумента) = НАЧАЛОДНЯ(ТекущаяДата()) -
Игнорирование часовых поясов
Ошибка: В распределенной базе сервер и клиент находятся в разных часовых поясах, из-за чего
ТекущаяДата()возвращает неожидаемое значение.Решение: Явно передавайте дату через параметры или настройте синхронизацию времени на серверах.
-
Кэширование запросов с ТекущаяДата()
Ошибка: Запрос с
ТекущаяДата()кэшируется, и при повторном выполнении возвращает устаревшую дату.Решение: Отключите кэширование или используйте параметры.
Еще одна типичная ошибка — попытка использовать функции даты в ПОЛНОЕ СОЕДИНЕНИЕ (FULL JOIN) или других сложных конструкциях, где 1С может некорректно обработать контекст. В таких случаях лучше разбить запрос на несколько простых частей.
Почему иногда ТекущаяДата() возвращает вчерашнюю дату?
Это может происходить в двух случаях:
1. Запрос выполняется в фоновом задании, которое было создано вчера, но выполнилось сегодня. В этом случае ТекущаяДата() берется на момент создания задания, а не выполнения.
2. Включено кэширование запроса, и платформа возвращает сохраненный результат.
Чтобы избежать этого, всегда передавайте дату через параметры в фоновых задачах.
7. Продвинутые техники: динамические периоды и работа с временными зонами
Для сложных отчетов иногда требуется не просто текущая дата, а динамический период (например, "последние 30 дней", "текущий квартал"). В таких случаях удобно использовать комбинацию функций даты и арифметических операций.
Примеры:
// Последние 30 дней
ВЫБРАТЬ
Документ.ЗаказПокупателя.Ссылка,
Документ.ЗаказПокупателя.Дата
ИЗ
Документ.ЗаказПокупателя КАК Документ.ЗаказПокупателя
ГДЕ
Документ.ЗаказПокупателя.Дата >= ТекущаяДата() - 30
// Текущий квартал
ВЫБРАТЬ
Документ.РеализацияТоваровУслуг.Ссылка,
Документ.РеализацияТоваровУслуг.Дата
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ.РеализацияТоваровУслуг
ГДЕ
Документ.РеализацияТоваровУслуг.Дата >= НАЧАЛОКВАРТАЛА(ТекущаяДата())
И Документ.РеализацияТоваровУслуг.Дата < КОНЕЦКВАРТАЛА(ТекущаяДата()) + 1
Для работы с временными зонами в 1С 8.3.20+ появилась поддержка типа ЧасовойПояс. Пример использования:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТекущаяДата() КАК ДатаПоСерверу,
| ТекущаяДатаВЧасовомПоясе(&ЧасовойПояс) КАК ДатаВУказанномПоясе";
Запрос.УстановитьПараметр("ЧасовойПояс", ЧасовойПояс.Мск); // или другой пояс
Результат = Запрос.Выполнить();
Это актуально для международных компаний, где пользователи работают в разных странах, но данные должны привязываться к единому часовому поясу (например, по головному офису).
Для динамических периодов всегда используйте функции НАЧАЛОДНЯ(), КОНЕЦДНЯ(), НАЧАЛОМЕСЯЦА() и т.д. Они учитывают особенности календаря (например, последний день февраля в високосный год).
FAQ: Ответы на частые вопросы
❓ Почему ТекущаяДата() в запросе и ТекущаяДата() во встроенном языке возвращают разные значения?
ТекущаяДата() в запросе выполняется на сервере 1С и зависит от его времени. Во встроенном языке функция выполняется на клиенте (если код запущен на клиенте) или на сервере (если код серверный). Разница может возникать из-за:
- Разных часовых поясов сервера и клиента.
- Задержки синхронизации времени в домене (для Windows-серверов).
- Использования виртуальных машин с неверными настройками времени.
Чтобы избежать расхождений, явно передавайте дату через параметры или настройте синхронизацию времени на всех узлах кластера.
❓ Можно ли в запросе получить дату создания документа "сегодня"?
Да, но нужно учитывать время. Если документ создан сегодня в 10:00, а запрос выполняется в 15:00, то простое сравнение ДатаДокумента = ТекущаяДата() не сработает, потому что в ТекущаяДата() будет время (15:00), а в ДатаДокумента — 10:00.
Правильный вариант:
ГДЕ НАЧАЛОДНЯ(Документ.Ссылка.Дата) = НАЧАЛОДНЯ(ТекущаяДата())
Или через параметр:
ГДЕ Документ.Ссылка.Дата >= НАЧАЛОДНЯ(&ТекущаяДата)
И Документ.Ссылка.Дата < НАЧАЛОДНЯ(&ТекущаяДата) + 86400 // +1 день в секундах
❓ Как получить текущую дату в запросе к внешней базе данных (не 1С)?
Если вы выполняете запрос к внешней базе (например, через HTTPСервис или ADO), функции ТекущаяДата() не будет. В этом случае:
- Получите дату во встроенном языке:
ТекущаяДата = ТекущаяДата(); - Передайте ее в запрос как параметр.
- Используйте синтаксис внешней СУБД для работы с датами (например,
GETDATE()для MS SQL илиNOW()для MySQL).
Пример для MS SQL:
Запрос.Текст = "SELECT * FROM Orders WHERE OrderDate >= @CurrentDate";
Запрос.УстановитьПараметр("CurrentDate", ТекущаяДата());
❓ Почему при сравнении дат в запросе не работают индексы?
Если вы используете функции над полем даты (например, НАЧАЛОДНЯ(Документ.Дата)), 1С не может воспользоваться индексами по этому полю. Это приводит к полному сканированию таблицы (Table Scan) и замедлению запроса.
Решения:
- Используйте параметры с явным указанием границ:
ГДЕ Документ.Дата >= НАЧАЛОДНЯ(&ДатаНачала)И Документ.Дата < НАЧАЛОДНЯ(&ДатаОкончания) + 86400
- Создайте вычисляемое поле в таблице базы данных с датой без времени и проиндексируйте его.
❓ Как проверить, поддерживает ли моя база виртуальные таблицы?
Виртуальные таблицы доступны только в клиент-серверном варианте 1С (MS SQL, PostgreSQL, IBM DB2). В файловой базе они не работают.
Чтобы проверить поддержку:
- Откройте конфигуратор и перейдите в
Администрирование → Поддержка → Тестирование и исправление. - Посмотрите тип СУБД в информации о базе.
- Попробуйте выполнить простой запрос с виртуальной таблицей:
ВЫБРАТЬ РАЗРЕШЕННЫЕ РОЛИ ИЗ ВиртуальнаяТаблица.РолиПользователейЕсли запрос выполняется без ошибок — виртуальные таблицы поддерживаются.