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

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

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

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

В языке запросов 1С нет встроенной функции, которая возвращает текущую дату напрямую внутри текста запроса — в отличие от SQL, где есть GETDATE() или CURRENT_DATE. Поэтому дату передают в запрос как параметр, а её значение получают средствами встроенного языка до выполнения запроса. Это стандартный и единственно корректный подход, он работает одинаково в файловых и клиент-серверных базах.

Ключевой момент, который нужно понимать с самого начала: «текущая дата» в 1С — понятие неоднозначное. Есть дата сеанса пользователя, дата сервера приложений и дата клиентского компьютера, и в распределённой инфраструктуре они могут различаться. Выбор источника даты влияет на корректность отборов, расчётов остатков и формирования отчётов.

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

Почему в запросе 1С нет функции текущей даты

Язык запросов 1С — это декларативный язык выборки данных, а не язык программирования. Он умеет фильтровать, группировать и соединять данные, но не выполняет произвольные вычисления, зависящие от окружения сеанса. Поэтому в нём отсутствуют функции, возвращающие системное время.

Такое устройство сделано намеренно: один и тот же текст запроса должен давать предсказуемый результат при заданных параметрах. Момент времени, к которому привязан запрос, разработчик задаёт явно — это исключает ситуации, когда отчёт, запущенный в 23:59 и в 00:01, неожиданно возвращает разные данные без видимой причины.

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

Базовый способ: передать дату параметром

Стандартная последовательность действий выглядит так: создаётся объект Запрос, задаётся текст, устанавливается параметр с текущей датой, запрос выполняется. В тексте запроса параметр упоминается через символ амперсанда.

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

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

"ВЫБРАТЬ

| РеализацияТоваровУслуг.Ссылка КАК Документ,

| РеализацияТоваровУслуг.Дата КАК ДатаДокумента

|ИЗ

| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг

|ГДЕ

| РеализацияТоваровУслуг.Дата >= &НачалоДня

| И РеализацияТоваровУслуг.Дата <= &КонецДня";

ТекущаяДата = ТекущаяДатаСеанса();

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

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

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

Обратите внимание: для отбора документов «за сегодня» корректно использовать пару НачалоДня() / КонецДня(), а не сравнение с одной датой. Поле Дата документа содержит дату со временем с точностью до секунды, поэтому условие Дата = &ТекущаяДата почти никогда не сработает так, как ожидает разработчик.

Параметр можно использовать и для вывода самой даты в результат запроса — например, чтобы пометить строки отчёта моментом формирования:

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

"ВЫБРАТЬ

| &ТекущаяДата КАК ДатаФормирования,

| Товары.Ссылка КАК Номенклатура

|ИЗ

| Справочник.Номенклатура КАК Товары";

Порядок действий
  1. 1
    Создайте объект Запрос и задайте текст с параметром &ТекущаяДата
  2. 2
    Получите значение даты вызовом ТекущаяДатаСеанса()
  3. 3
    Передайте значение: Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДатаСеанса())
  4. 4
    При отборе за день используйте НачалоДня() и КонецДня() вместо точного сравнения
  5. 5
    Выполните запрос и проверьте содержимое выборки в отладчике

ТекущаяДатаСеанса() против ТекущаяДата(): что выбрать

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

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

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

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

ТекущаяДатаСеанса()

Рекомендуемый вариант. Единое время сеанса для всех пользователей базы, не зависит от настроек клиентских компьютеров. Подходит для запросов, отборов и проведения документов.

ТекущаяДата() на сервере

Возвращает часы сервера приложений. Допустимо в серверных процедурах, но при кластере из нескольких серверов возможны расхождения.

ТекущаяДата() на клиенте

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

Текущая дата в параметрах виртуальных таблиц

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

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

"ВЫБРАТЬ

| Остатки.Номенклатура КАК Номенклатура,

| Остатки.КоличествоОстаток КАК Остаток

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки(&Момент, ) КАК Остатки";

Запрос.УстановитьПараметр("Момент",

Новый Граница(ТекущаяДатаСеанса(), ВидГраницы.Включая));

Если передать просто дату без границы, движения, записанные ровно в эту секунду, попадут в выборку или нет — в зависимости от вида виртуальной таблицы. Явное указание ВидГраницы.Включая или ВидГраницы.Исключая делает поведение предсказуемым и защищает от трудноуловимых расхождений в отчётах.

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

Вычисления с датой прямо в запросе

Хотя функции получения текущей даты в языке запросов нет, с уже переданной датой можно выполнять арифметику средствами самого запроса. Для этого служат функции ДОБАВИТЬКДАТЕ() и РАЗНОСТЬДАТ(), а также функции выделения частей даты: НАЧАЛОПЕРИОДА() и КОНЕЦПЕРИОДА().

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

"ВЫБРАТЬ

| Заказы.Ссылка КАК Заказ,

| РАЗНОСТЬДАТ(Заказы.ДатаОтгрузки, &ТекущаяДата, ДЕНЬ) КАК ДнейПросрочки

|ИЗ

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

|ГДЕ

| Заказы.ДатаОтгрузки < &ТекущаяДата

| И НЕ Заказы.Отгружен";

Типичные приёмы: НАЧАЛОПЕРИОДА(&ТекущаяДата, МЕСЯЦ) даёт начало текущего месяца, ДОБАВИТЬКДАТЕ(&ТекущаяДата, ДЕНЬ, -7) — дату неделю назад, КОНЕЦПЕРИОДА(&ТекущаяДата, ДЕНЬ) — конец сегодняшнего дня. Это позволяет строить отборы «за текущий месяц» или «за последние 7 дней» без предварительных вычислений в коде.

Ограничение: РАЗНОСТЬДАТ() возвращает целое число полных единиц указанного типа. Разница между 23:00 вчера и 01:00 сегодня в днях равна 1, хотя прошло два часа. Если нужна точная длительность, считайте разность в секундах или минутах и делите в коде после выборки.

bsl
Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДатаСеанса());
// В тексте запроса:
// НАЧАЛОПЕРИОДА(&ТекущаяДата, МЕСЯЦ) — начало текущего месяца
// ДОБАВИТЬКДАТЕ(&ТекущаяДата, ДЕНЬ, -7) — неделю назад
// КОНЕЦПЕРИОДА(&ТекущаяДата, ДЕНЬ) — конец сегодняшнего дня

Типичные ошибки и как их избежать

Самая распространённая ошибка — сравнение даты документа с текущей датой на равенство. Поле даты содержит время, поэтому условие Дата = &ТекущаяДата не найдёт ни одного документа, кроме случайного совпадения до секунды. Всегда используйте диапазон: начало и конец дня.

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

Третья группа проблем связана с неинициализированными параметрами: если параметр &ТекущаяДата упомянут в тексте, но не установлен через УстановитьПараметр(), запрос завершится с ошибкой. Ещё одна тонкость — пустая дата '00010101' в параметре: отборы с ней ведут себя неочевидно, поэтому перед выполнением стоит проверять значение на заполненность.

Типичные ошибки
01
Сравнение Дата = &ТекущаяДата — время в дате не совпадает, выборка пустая. Используйте диапазон НачалоДня/КонецДня
02
ТекущаяДата() на клиенте — сбитые часы пользователя искажают отбор. Применяйте ТекущаяДатаСеанса()
03
Параметр упомянут в тексте, но не установлен — запрос падает с ошибкой при выполнении
04
Передача пустой даты в виртуальную таблицу — получение остатков на начало времён и тяжёлый запрос
05
Ожидание, что РАЗНОСТЬДАТ в днях учитывает часы — функция считает только полные сутки

Как проверить, что дата в запросе корректна

Простейшая проверка — вывести сам параметр в результат запроса и сравнить с ожидаемым значением. В консоли запросов или в отладчике выполните выборку ВЫБРАТЬ &ТекущаяДата и убедитесь, что дата соответствует текущему моменту, а не пустому значению и не вчерашнему дню.

При работе с отборами за день полезно проверить граничные условия: документ, созданный в 00:00:01, и документ в 23:59:59 должны оба попадать в выборку. Если утренний документ теряется — скорее всего, в параметр передана дата со временем вместо начала дня.

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

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

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

Значение параметра &ТекущаяДата в отладчике
Норма

Совпадает с текущим моментом с точностью до секунд

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

Пустая дата 01.01.0001 или вчерашний день

Документы на границах дня (00:00 и 23:59)
Норма

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

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

Один из документов теряется — неверные границы периода

Время сеанса и время сервера СУБД
Норма

Расхождение не более пары минут

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

Заметная разница — проблема часовых поясов сервера

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

Можно ли получить текущую дату прямо в тексте запроса без параметра?

Нет. В языке запросов 1С нет функции, возвращающей текущую дату, — её всегда передают параметром из встроенного языка. Это осознанное ограничение платформы, обходить которое не нужно: параметр делает момент времени явным и контролируемым.

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

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

Как выбрать документы только за сегодня?

Передайте два параметра: НачалоДня(ТекущаяДатаСеанса()) и КонецДня(ТекущаяДатаСеанса()), а в условии запроса укажите Дата >= &НачалоДня И Дата <= &КонецДня. Сравнение на равенство с одной датой не подходит, потому что дата документа хранится со временем.

Почему срез последних не показывает свежую запись?

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

Как получить в запросе начало текущего месяца?

Передайте текущую дату параметром и примените функцию языка запросов: НАЧАЛОПЕРИОДА(&ТекущаяДата, МЕСЯЦ). Аналогично работают ДЕНЬ, НЕДЕЛЯ, КВАРТАЛ, ГОД, а парная функция КОНЕЦПЕРИОДА() возвращает конец указанного периода.

Что будет, если не установить параметр с датой?

Запрос завершится с ошибкой о незаполненном параметре при вызове Выполнить(). Поэтому параметры устанавливают до выполнения, а значение даты полезно предварительно проверять на заполненность, особенно если оно приходит извне — из настроек отчёта или параметров формы.

Итог

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

Текущая дата в запрос 1С передаётся только параметром: ТекущаяДатаСеанса() в коде и &ТекущаяДата в тексте запроса. Для отборов за день используйте диапазон НачалоДня/КонецДня, для виртуальных таблиц — явные границы, а вычисления с датой выполняйте функциями НАЧАЛОПЕРИОДА, ДОБАВИТЬКДАТЕ и РАЗНОСТЬДАТ.