К статье
Практический материал

Разработка и Конфигурация · 9 мин

Как указать текущую дату в запросе 1С

Как указать текущую дату в запросе 1С: функция ТекущаяДатаСеанса, передача параметра, сравнение дат, типичные ошибки и примеры кода для разработчика.

Задача подставить текущую дату в запрос возникает постоянно: нужно выбрать документы за сегодня, отобрать актуальные цены, проверить просроченные задачи или построить отчёт «на сейчас». В языке запросов 1С для этого есть встроенный механизм, но у него есть тонкости, из-за которых запросы нередко возвращают не то, что ожидал разработчик.

Главная тонкость — разница между датой сервера, датой клиента и датой сеанса. В файловой базе на одном компьютере они обычно совпадают, а в клиент-серверном режиме или при работе пользователей из разных часовых поясов — могут различаться. Поэтому важно не просто «вставить дату», а понимать, откуда она берётся и в каком виде попадает в сравнение.

Ниже разобраны оба рабочих способа — функция ТекущаяДатаСеанса() в тексте запроса и передача даты параметром, а также сравнение дат без времени, работа в СКД и типичные ошибки, которые приводят к пустым или неверным выборкам.

Способ 1: функция ТекущаяДатаСеанса() прямо в тексте запроса

Язык запросов 1С поддерживает функцию ТекущаяДатаСеанса() — она вычисляется на сервере в момент выполнения запроса и возвращает дату и время текущего сеанса с учётом часового пояса сеанса. Это самый короткий способ, не требующий передачи параметров.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| ЗаказКлиента.Ссылка КАК Заказ,

| ЗаказКлиента.Дата КАК Дата

|ИЗ

| Документ.ЗаказКлиента КАК ЗаказКлиента

|ГДЕ

| ЗаказКлиента.ДатаОтгрузки < &ТекущаяДата";

Однако функцию внутри текста используют так — без параметра вообще:

Запрос.Текст =

"ВЫБРАТЬ

| Задача.Ссылка КАК Задача

|ИЗ

| Задача.ЗадачаИсполнителя КАК Задача

|ГДЕ

| Задача.СрокИсполнения < ТекущаяДатаСеанса()";

Функция вызывается без аргументов, скобки обязательны. Результат — значение типа Дата с точностью до секунды. Если поле в базе хранит дату с временем (а документы 1С хранят именно так), сравнение идёт с точностью до секунды, и это нужно учитывать при отборе «за сегодня».

Способ 2: передать дату через параметр запроса

Второй подход — вычислить дату в коде и передать её в запрос параметром. Это даёт полный контроль над значением: можно отсечь время, сдвинуть дату на начало дня или на нужное количество дней назад.

Запрос = Новый Запрос;

Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДатаСеанса());

Запрос.Текст =

"ВЫБРАТЬ

| Платеж.Ссылка КАК Платеж

|ИЗ

| Документ.ПоступлениеОплаты КАК Платеж

|ГДЕ

| Платеж.Дата <= &ТекущаяДата";

Результат = Запрос.Выполнить();

Если нужно сравнивать только день без времени, дату приводят к началу дня до передачи в запрос:

Запрос.УстановитьПараметр("НачалоСегодня", НачалоДня(ТекущаяДатаСеанса()));

Запрос.УстановитьПараметр("КонецСегодня", КонецДня(ТекущаяДатаСеанса()));

Параметр предпочтительнее, когда одна и та же дата используется в нескольких местах запроса или в пакете запросов: значение фиксируется один раз, и все части пакета работают с одинаковым моментом времени. С функцией ТекущаяДатаСеанса() каждый запрос пакета теоретически может получить значение, отличающееся на секунды.

Сравнение вариантов

ТекущаяДатаСеанса() в тексте запроса

Коротко, не нужен параметр. Подходит для простых разовых отборов. Нельзя заранее отсечь время.

Параметр запроса

Полный контроль: можно передать начало дня, конец дня, произвольный сдвиг. Обязателен, когда одно значение нужно в нескольких запросах.

Параметр в СКД (СтандартнаяДатаНачала)

Для отчётов и динамических списков: пользователь сам управляет датой, по умолчанию подставляется текущая.

Как сравнить даты без учёта времени

Документ в 1С хранит дату с точностью до секунды, поэтому условие Документ.Дата = &ТекущаяДата почти никогда не сработает: совпадение до секунды практически невозможно. Для отбора «за сегодня» используют диапазон или приведение к периоду.

Первый вариант — диапазон от начала до конца дня:

"ГДЕ

| Документ.Дата МЕЖДУ &НачалоСегодня И &КонецСегодня"

Второй вариант — функция языка запросов НАЧАЛОПЕРИОДА, которая усекает дату до указанного периода:

"ГДЕ

| НАЧАЛОПЕРИОДА(Документ.Дата, ДЕНЬ) = НАЧАЛОПЕРИОДА(&ТекущаяДата, ДЕНЬ)"

У второго варианта есть цена: функция применяется к полю таблицы, и индекс по дате при таком условии не используется, что на больших таблицах заметно замедляет запрос. Для массовых отборов предпочтителен диапазон МЕЖДУ по индексированному полю.

Типичные ошибки
01
Сравнение даты документа на равенство с текущей датой — совпадение до секунды почти никогда не наступает, выборка пустая. Используйте диапазон день/месяц.
02
Использование ТекущаяДата() в серверном коде — метод недоступен на сервере в тонком и веб-клиенте, нужна ТекущаяДатаСеанса().
03
НАЧАЛОПЕРИОДА по полю таблицы в условии ГДЕ — теряется индекс, запрос на большой таблице начинает выполняться заметно дольше.
04
Передача в параметр строки вместо даты — сравнение работает непредсказуемо, передавайте именно значение типа Дата.

Текущая дата в СКД и динамических списках

В отчётах на системе компоновки данных и в динамических списках жёстко зашивать ТекущаяДатаСеанса() в текст запроса не принято. Вместо этого добавляют параметр с типом СтандартнаяДатаНачала — тогда пользователь отчёта может сам выбрать дату, а по умолчанию подставляется текущая.

Порядок настройки в схеме компоновки: на закладке «Параметры» добавьте параметр, например Период, установите ему тип значения «Стандартная дата начала». В тексте запроса используйте его обычным образом: ГДЕ Документ.Дата <= &Период. При необходимости внутри выражений СКД доступна функция ТекущаяДатаСеанса() и выражение &ТекущаяДата через вычисляемые поля.

Для динамических списков (например, список просроченных задач на рабочем столе) параметр устанавливают программно при создании формы:

Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

Список.Параметры.УстановитьЗначениеПараметра("ТекущаяДата", ТекущаяДатаСеанса());

КонецПроцедуры

Порядок действий для отбора «за сегодня»
  1. 1
    Определите, где выполняется запрос: простой запрос, СКД или динамический список.
  2. 2
    Для простого запроса вычислите НачалоДня(ТекущаяДатаСеанса()) и КонецДня(ТекущаяДатаСеанса()) и передайте оба параметра.
  3. 3
    В тексте запроса используйте условие Дата МЕЖДУ &НачалоСегодня И &КонецСегодня.
  4. 4
    Выполните запрос и проверьте, что в выборку попали документы за текущий день и не попали вчерашние.
  5. 5
    Для СКД замените параметры на СтандартнаяДатаНачала, чтобы пользователь мог менять дату без доработки кода.

Часовые пояса и дата сеанса

ТекущаяДатаСеанса() возвращает время сервера, приведённое к часовому поясу сеанса пользователя. Если база работает в клиент-серверном режиме и пользователи сидят в разных регионах, «сегодня» для двух пользователей может быть разным календарным днём. Это нормальное поведение, но его нужно учитывать в регламентных заданиях: у фонового задания нет пользовательского сеанса, и дата берётся по часовому поясу сервера или информационной базы.

Если учёт ведётся строго по одному часовому поясу (например, головной офис), в регламентных операциях дату лучше вычислять явно относительно заданного пояса, а не полагаться на дату сеанса фонового задания. Иначе документы, созданные около полуночи, могут попадать не в тот отчётный день.

Проверка результата и отладка

Быстрее всего проверить отбор по текущей дате в консоли запросов: задайте параметр вручную, выполните запрос и посмотрите, какие записи попали в выборку. Затем замените параметр на ТекущаяДатаСеанса() и сравните результат — он должен совпадать с точностью до момента выполнения.

Если выборка пустая, проверьте три вещи: тип параметра (должна быть Дата, а не Строка), наличие времени в сравниваемых значениях и часовой пояс сеанса. Чаще всего «запрос не работает» означает, что дата документа содержит время, а условие построено на точное равенство.

Контрольные точки

Как проверить результат

Тип параметра в консоли запросов
Норма

Дата (с временем или без)

Тревожный признак

Строка — сравнение идёт посимвольно

Документы за сегодня в выборке
Норма

Есть все документы текущего дня

Тревожный признак

Пусто или попадают чужие дни — ошибка в границах диапазона

Скорость выполнения на большой таблице
Норма

Запрос отрабатывает быстро, условие по индексированному полю

Тревожный признак

Заметная задержка — вероятно, НАЧАЛОПЕРИОДА в условии по полю

Итог

Что важно запомнить

В запросе 1С текущую дату получают функцией ТекущаяДатаСеанса() или передают параметром. Для отбора «за сегодня» используйте диапазон от начала до конца дня, а не равенство. В СКД и динамических списках применяйте параметр типа СтандартнаяДатаНачала, а в серверном коде — только ТекущаяДатаСеанса(), никогда ТекущаяДата().

Частые вопросы

Чем ТекущаяДатаСеанса() отличается от ТекущаяДата()?

ТекущаяДатаСеанса() возвращает время сервера, приведённое к часовому поясу сеанса, и работает везде, включая серверный код. ТекущаяДата() возвращает время клиентского компьютера и доступна только на клиенте. В запросах и серверных процедурах используйте только ТекущаяДатаСеанса().

Почему условие Дата = &ТекущаяДата ничего не находит?

Даты документов хранятся с точностью до секунды, и совпадение с моментом выполнения запроса практически невозможно. Замените равенство на диапазон: Дата МЕЖДУ НачалоДня(дата) И КонецДня(дата).

Можно ли в запросе вычесть дни из текущей даты?

Да, есть функции ДОБАВИТЬКДАТЕ и РАЗНОСТЬДАТ. Например, неделю назад: ДОБАВИТЬКДАТЕ(ТекущаяДатаСеанса(), ДЕНЬ, -7). Альтернатива — вычислить дату в коде и передать параметром.

Как задать текущую дату в отчёте на СКД, чтобы пользователь мог её менять?

Добавьте в схеме компоновки параметр с типом «Стандартная дата начала» и используйте его в тексте запроса. По умолчанию подставится текущая дата, а пользователь сможет выбрать другую в настройках отчёта.

Работает ли ТекущаяДатаСеанса() в регламентных заданиях?

Работает, но возвращает время по часовому поясу сервера или информационной базы, так как пользовательского сеанса у фонового задания нет. Если учёт привязан к конкретному региону, вычисляйте дату явно относительно нужного часового пояса.