В процессе разработки на платформе 1С:Предприятие 8 программисты часто сталкиваются с необходимостью фильтрации данных по текущему моменту времени прямо в тексте запроса. Типичный пример — выборка просроченных задач или документов, дата которых больше текущей. Однако попытка написать в консоли запросов или коде конструкцию вида ГДЕ Дата > ТекущаяДата приводит к ошибке, так как язык запросов 1С не содержит встроенной функции получения системного времени. В этой статье мы подробно разберем, почему это так, и рассмотрим все доступные способы решения этой задачи — от стандартных до продвинутых.
Рассмотрим самый правильный и производительный метод — использование параметров. Платформа 1С намеренно разделяет подготовку текста запроса и передачу в него динамических данных. Это позволяет системе управления базами данных (СУБД) эффективно кэшировать планы выполнения запросов.
Проанализируем ситуацию: если бы функция ГЕТДАТА() (аналог SQL GETDATE()) существовала в языке запросов, SQL-серверу было бы сложнее строить оптимальный план, так как значение менялось бы каждую миллисекунду. Использование параметра &ТекДата позволяет системе один раз построить план и переиспользовать его.
Для реализации этого метода в коде выполним следующие шаги:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПоступлениеТоваровУслугТовары.Ссылка КАК Ссылка
|ИЗ
| Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТоваровУслугТовары
|ГДЕ
| ПоступлениеТоваровУслугТовары.Ссылка.Дата > &ТекущаяДата";
// Установка параметра
Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДата());
РезультатЗапроса = Запрос.Выполнить();
Если ваша задача связана с построением отчета, то ручная установка параметров в коде может быть избыточной. Система компоновки данных предоставляет более изящные механизмы. Разберем, как автоматизировать получение даты в схеме компоновки.
Посмотрим на вкладку «Параметры» в конструкторе СКД. Для параметра с именем ТекДата мы можем настроить поле «Выражение». Здесь доступны функции встроенного языка. Рассмотрим два варианта заполнения:
ТекущаяДата() или ТекущаяДатаСеанса(). Платформа сама вычислит значение в момент инициализации отчета.Пример кода в общем модуле РаботаСДатамиПолныйДоступ:
Функция ПолучитьНачалоТекущегоДня() Экспорт
Возврат НачалоДня(ТекущаяДатаСеанса());
КонецФункции
В СКД в поле «Выражение» для параметра укажем: РаботаСДатамиПолныйДоступ.ПолучитьНачалоТекущегоДня(). Это гарантирует, что отчет всегда будет открываться с актуальной датой без вмешательства пользователя.
При работе с управляемыми формами часто требуется фильтровать данные в динамических списках (например, скрывать будущие задачи). Выясним причину, по которой обычный параметр может не подойти: динамический список не обновляется «сам по себе» при наступлении следующей секунды. Если вы установили параметр при открытии формы, он останется статичным.
Для решения этой проблемы проанализируем два подхода:
ПодключитьОбработчикОжидания, который раз в минуту будет обновлять параметр &ТекущаяДата в компоновщике настроек динамического списка.ПараметрыСеанса. Они хранятся в памяти сервера для каждого пользователя индивидуально.Однако помните: использование параметров сеанса непосредственно в тексте запроса динамического списка возможно, но это требует их предварительной инициализации в модуле сеанса. Это избавляет от «грязного» кода и позволяет избежать использования констант, которые влияют на всех пользователей сразу.
Иногда возникают ситуации, когда доступа к установке параметров нет (например, при использовании сторонних инструментов или жестко заданных строковых запросов). В этом случае можно прибегнуть к формированию строки запроса с использованием функции ДАТАВРЕМЯ.
Рассмотрим пример формирования такой строки:
ТекДата = ТекущаяДата();
ТекстЗапроса = "ГДЕ Документ.Дата > ДАТАВРЕМЯ("
+ Формат(Год(ТекДата), "ЧГ=0") + ","
+ Месяц(ТекДата) + ","
+ День(ТекДата) + ","
+ Час(ТекДата) + ","
+ Минута(ТекДата) + ","
+ Секунда(ТекДата) + ")";
Важное предостережение: Всегда получайте ТекущуюДату() в отдельную переменную перед сборкой строки. Если вы будете вызывать Год(ТекущаяДата()), Месяц(ТекущаяДата()) и так далее прямо в конкатенации, существует риск (хоть и микроскопический), что в момент перехода секунды вы получите год из одного момента времени, а месяц или день — из следующего. Это приведет к критической ошибке в данных.
Проанализируем крайне важный нюанс производительности. Если ваш запрос обращается к виртуальным таблицам (например, РегистрНакопления.ОстаткиИОбороты), никогда не используйте условие по текущей дате в секции ГДЕ.
Сравним два подхода:
ГДЕ отсечь лишнее. СУБД сначала сформирует огромный временный набор данных, что замедлит работу в десятки раз.Пример правильного запроса:
ВЫБРАТЬ
Продажи.СуммаОборот
ИЗ
РегистрНакопления.Продажи.Обороты(, &КонецПериода, , ) КАК Продажи
В данном случае СУБД сразу отсечет ненужные записи на уровне обращения к индексам, что обеспечит максимальную скорость работы.
В завершение разберем критическую деталь, которую часто упускают. В системе 1С существует два основных понятия времени:
ТекущаяДата() — возвращает время сервера, на котором выполняется код.ТекущаяДатаСеанса() — учитывает часовой пояс пользователя, заданный в настройках сеанса.Если ваша компания работает в разных часовых поясах (например, сервер в Москве, а пользователь во Владивостоке), использование ТекущаяДата() приведет к тому, что задачи для пользователя будут появляться или исчезать с задержкой или преждевременно. Поэтому в запросах, связанных с оперативной работой пользователей, всегда рекомендуется использовать именно ТекущуюДатуСеанса().
Подводя итог, использование текущей даты в запросе — это не просто вставка функции, а осознанный выбор между производительностью (параметры), удобством (СКД) и корректностью (часовые пояса). Рассмотрим каждый из предложенных методов в контексте вашей конкретной задачи и выберем наиболее оптимальный.