Разработка и Конфигурация · 12 мин
Как получить текущую дату в запросе 1С
Как получить текущую дату в запросе 1С: передача через параметр, ТекущаяДатаСеанса(), разница даты сервера и клиента, типовые ошибки и примеры кода.
В языке запросов 1С нет встроенной функции, которая возвращает текущую дату напрямую внутри текста запроса — в отличие от SQL, где есть GETDATE() или CURRENT_DATE. Поэтому дату передают в запрос как параметр, а её значение получают средствами встроенного языка до выполнения запроса. Это стандартный и единственно корректный подход, он работает одинаково в файловых и клиент-серверных базах.
Ключевой момент, который нужно понимать с самого начала: «текущая дата» в 1С — понятие неоднозначное. Есть дата сеанса пользователя, дата сервера приложений и дата клиентского компьютера, и в распределённой инфраструктуре они могут различаться. Выбор источника даты влияет на корректность отборов, расчётов остатков и формирования отчётов.
Ниже разобраны практические способы передать текущую дату в запрос, особенности функций ТекущаяДатаСеанса() и ТекущаяДата(), работа с границами периода, типовые ошибки и способы проверить результат.
Почему в запросе 1С нет функции текущей даты
Язык запросов 1С — это декларативный язык выборки данных, а не язык программирования. Он умеет фильтровать, группировать и соединять данные, но не выполняет произвольные вычисления, зависящие от окружения сеанса. Поэтому в нём отсутствуют функции, возвращающие системное время.
Такое устройство сделано намеренно: один и тот же текст запроса должен давать предсказуемый результат при заданных параметрах. Момент времени, к которому привязан запрос, разработчик задаёт явно — это исключает ситуации, когда отчёт, запущенный в 23:59 и в 00:01, неожиданно возвращает разные данные без видимой причины.
Единственное исключение — виртуальные таблицы регистров (например, Остатки, Обороты, СрезПоследних), где период тоже задаётся параметром, но уже в параметрах виртуальной таблицы. Принцип тот же: платформа получает конкретную дату извне, а не вычисляет её сама.
Базовый способ: передать дату параметром
Стандартная последовательность действий выглядит так: создаётся объект Запрос, задаётся текст, устанавливается параметр с текущей датой, запрос выполняется. В тексте запроса параметр упоминается через символ амперсанда.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслуг.Ссылка КАК Документ,
| РеализацияТоваровУслуг.Дата КАК ДатаДокумента
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
|ГДЕ
| РеализацияТоваровУслуг.Дата >= &НачалоДня
| И РеализацияТоваровУслуг.Дата <= &КонецДня";
ТекущаяДата = ТекущаяДатаСеанса();
Запрос.УстановитьПараметр("НачалоДня", НачалоДня(ТекущаяДата));
Запрос.УстановитьПараметр("КонецДня", КонецДня(ТекущаяДата));
Результат = Запрос.Выполнить().Выгрузить();
Обратите внимание: для отбора документов «за сегодня» корректно использовать пару НачалоДня() / КонецДня(), а не сравнение с одной датой. Поле Дата документа содержит дату со временем с точностью до секунды, поэтому условие Дата = &ТекущаяДата почти никогда не сработает так, как ожидает разработчик.
Параметр можно использовать и для вывода самой даты в результат запроса — например, чтобы пометить строки отчёта моментом формирования:
Запрос.Текст =
"ВЫБРАТЬ
| &ТекущаяДата КАК ДатаФормирования,
| Товары.Ссылка КАК Номенклатура
|ИЗ
| Справочник.Номенклатура КАК Товары";
- 1Создайте объект Запрос и задайте текст с параметром &ТекущаяДата
- 2Получите значение даты вызовом ТекущаяДатаСеанса()
- 3Передайте значение: Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДатаСеанса())
- 4При отборе за день используйте НачалоДня() и КонецДня() вместо точного сравнения
- 5Выполните запрос и проверьте содержимое выборки в отладчике
ТекущаяДатаСеанса() против ТекущаяДата(): что выбрать
Функция ТекущаяДатаСеанса() возвращает дату и время текущего сеанса, которые платформа приводит к единому стандарту с учётом часового пояса сеанса. Именно эту функцию рекомендуется использовать в прикладном коде: все пользователи одной базы будут оперировать согласованным временем, независимо от настроек их компьютеров.
Функция ТекущаяДата() возвращает системную дату того компьютера, где выполняется код. В тонком клиенте это часы рабочей станции пользователя, на сервере — часы сервера приложений. Если у пользователя сбиты часы или неверно настроен часовой пояс, отбор «за сегодня» выберет не те документы.
В управляемых формах вызов ТекущаяДата() на клиенте и на сервере даст разные значения, если часы клиента и сервера расходятся. Поэтому в типовых конфигурациях и в практике разработки закрепилось правило: везде, где нужна «текущая дата» для бизнес-логики и запросов, применяется ТекущаяДатаСеанса().
Сравнение вариантов
Рекомендуемый вариант. Единое время сеанса для всех пользователей базы, не зависит от настроек клиентских компьютеров. Подходит для запросов, отборов и проведения документов.
Возвращает часы сервера приложений. Допустимо в серверных процедурах, но при кластере из нескольких серверов возможны расхождения.
Часы рабочей станции пользователя. Не подходит для отборов в запросах: сбитые часы клиента дадут неверные данные. Используется только для отображения локального времени в интерфейсе.
Текущая дата в параметрах виртуальных таблиц
Частая задача — получить остатки или срез последних «на сейчас». Период виртуальной таблицы тоже задаётся параметром, и туда передаётся та же дата сеанса.
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Номенклатура КАК Номенклатура,
| Остатки.КоличествоОстаток КАК Остаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(&Момент, ) КАК Остатки";
Запрос.УстановитьПараметр("Момент",
Новый Граница(ТекущаяДатаСеанса(), ВидГраницы.Включая));
Если передать просто дату без границы, движения, записанные ровно в эту секунду, попадут в выборку или нет — в зависимости от вида виртуальной таблицы. Явное указание ВидГраницы.Включая или ВидГраницы.Исключая делает поведение предсказуемым и защищает от трудноуловимых расхождений в отчётах.
Для регистра сведений с периодичностью «в пределах секунды» срез последних на ТекущаяДатаСеанса() вернёт актуальные значения. Но если записи в регистр делаются «будущей» датой (например, курсы валют, загруженные заранее на завтра), срез на текущий момент их не покажет — это норма, а не ошибка запроса.
Вычисления с датой прямо в запросе
Хотя функции получения текущей даты в языке запросов нет, с уже переданной датой можно выполнять арифметику средствами самого запроса. Для этого служат функции ДОБАВИТЬКДАТЕ() и РАЗНОСТЬДАТ(), а также функции выделения частей даты: НАЧАЛОПЕРИОДА() и КОНЕЦПЕРИОДА().
Запрос.Текст =
"ВЫБРАТЬ
| Заказы.Ссылка КАК Заказ,
| РАЗНОСТЬДАТ(Заказы.ДатаОтгрузки, &ТекущаяДата, ДЕНЬ) КАК ДнейПросрочки
|ИЗ
| Документ.ЗаказКлиента КАК Заказы
|ГДЕ
| Заказы.ДатаОтгрузки < &ТекущаяДата
| И НЕ Заказы.Отгружен";
Типичные приёмы: НАЧАЛОПЕРИОДА(&ТекущаяДата, МЕСЯЦ) даёт начало текущего месяца, ДОБАВИТЬКДАТЕ(&ТекущаяДата, ДЕНЬ, -7) — дату неделю назад, КОНЕЦПЕРИОДА(&ТекущаяДата, ДЕНЬ) — конец сегодняшнего дня. Это позволяет строить отборы «за текущий месяц» или «за последние 7 дней» без предварительных вычислений в коде.
Ограничение: РАЗНОСТЬДАТ() возвращает целое число полных единиц указанного типа. Разница между 23:00 вчера и 01:00 сегодня в днях равна 1, хотя прошло два часа. Если нужна точная длительность, считайте разность в секундах или минутах и делите в коде после выборки.
Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДатаСеанса());
// В тексте запроса:
// НАЧАЛОПЕРИОДА(&ТекущаяДата, МЕСЯЦ) — начало текущего месяца
// ДОБАВИТЬКДАТЕ(&ТекущаяДата, ДЕНЬ, -7) — неделю назад
// КОНЕЦПЕРИОДА(&ТекущаяДата, ДЕНЬ) — конец сегодняшнего дняТипичные ошибки и как их избежать
Самая распространённая ошибка — сравнение даты документа с текущей датой на равенство. Поле даты содержит время, поэтому условие Дата = &ТекущаяДата не найдёт ни одного документа, кроме случайного совпадения до секунды. Всегда используйте диапазон: начало и конец дня.
Вторая ошибка — использование ТекущаяДата() на клиенте для отбора в запросе. Если у пользователя часы отстают на сутки, он увидит «вчерашние» данные и может принять решение на их основе. Для бизнес-логики — только ТекущаяДатаСеанса().
Третья группа проблем связана с неинициализированными параметрами: если параметр &ТекущаяДата упомянут в тексте, но не установлен через УстановитьПараметр(), запрос завершится с ошибкой. Ещё одна тонкость — пустая дата '00010101' в параметре: отборы с ней ведут себя неочевидно, поэтому перед выполнением стоит проверять значение на заполненность.
Как проверить, что дата в запросе корректна
Простейшая проверка — вывести сам параметр в результат запроса и сравнить с ожидаемым значением. В консоли запросов или в отладчике выполните выборку ВЫБРАТЬ &ТекущаяДата и убедитесь, что дата соответствует текущему моменту, а не пустому значению и не вчерашнему дню.
При работе с отборами за день полезно проверить граничные условия: документ, созданный в 00:00:01, и документ в 23:59:59 должны оба попадать в выборку. Если утренний документ теряется — скорее всего, в параметр передана дата со временем вместо начала дня.
В клиент-серверном варианте имеет смысл сверить ТекущаяДатаСеанса() с системным временем сервера СУБД. Заметное расхождение — признак проблем с настройкой часовых поясов на сервере приложений, и это повод привлечь администратора, а не подгонять даты в коде.
Как проверить результат
Совпадает с текущим моментом с точностью до секунд
Пустая дата 01.01.0001 или вчерашний день
Оба документа входят в выборку за сегодня
Один из документов теряется — неверные границы периода
Расхождение не более пары минут
Заметная разница — проблема часовых поясов сервера
Частые вопросы
Можно ли получить текущую дату прямо в тексте запроса без параметра?
Нет. В языке запросов 1С нет функции, возвращающей текущую дату, — её всегда передают параметром из встроенного языка. Это осознанное ограничение платформы, обходить которое не нужно: параметр делает момент времени явным и контролируемым.
Чем отличается ТекущаяДатаСеанса() от ТекущаяДата()?
ТекущаяДатаСеанса() возвращает согласованное платформой время сеанса с учётом его часового пояса, одинаковое для всех пользователей базы. ТекущаяДата() возвращает часы того компьютера, где выполняется код, и зависит от локальных настроек. Для запросов и бизнес-логики используется ТекущаяДатаСеанса().
Как выбрать документы только за сегодня?
Передайте два параметра: НачалоДня(ТекущаяДатаСеанса()) и КонецДня(ТекущаяДатаСеанса()), а в условии запроса укажите Дата >= &НачалоДня И Дата <= &КонецДня. Сравнение на равенство с одной датой не подходит, потому что дата документа хранится со временем.
Почему срез последних не показывает свежую запись?
Проверьте, не записана ли она «будущей» датой относительно ТекущаяДатаСеанса() — например, при загрузке курсов на завтра. Также убедитесь, что период виртуальной таблицы задан явно и что часы сервера не расходятся с ожидаемым временем.
Как получить в запросе начало текущего месяца?
Передайте текущую дату параметром и примените функцию языка запросов: НАЧАЛОПЕРИОДА(&ТекущаяДата, МЕСЯЦ). Аналогично работают ДЕНЬ, НЕДЕЛЯ, КВАРТАЛ, ГОД, а парная функция КОНЕЦПЕРИОДА() возвращает конец указанного периода.
Что будет, если не установить параметр с датой?
Запрос завершится с ошибкой о незаполненном параметре при вызове Выполнить(). Поэтому параметры устанавливают до выполнения, а значение даты полезно предварительно проверять на заполненность, особенно если оно приходит извне — из настроек отчёта или параметров формы.
Что важно запомнить
Текущая дата в запрос 1С передаётся только параметром: ТекущаяДатаСеанса() в коде и &ТекущаяДата в тексте запроса. Для отборов за день используйте диапазон НачалоДня/КонецДня, для виртуальных таблиц — явные границы, а вычисления с датой выполняйте функциями НАЧАЛОПЕРИОДА, ДОБАВИТЬКДАТЕ и РАЗНОСТЬДАТ.