Работа с датами и временными интервалами в языке запросов 1С — это базовая, но крайне важная тема для любого разработчика. Часто возникают ситуации, когда необходимо жестко ограничить выборку данных определенным периодом или вычислить интервал «на лету», например, за последние несколько минут. В этой статье мы подробно разберем, как правильно использовать литералы дат, как работать с функциями смещения времени и почему в запросах нельзя просто так получить текущую дату.
В отличие от классического SQL, где даты могут записываться в разных форматах (например, через решетки или кавычки), в языке запросов 1С существует строго определенная конструкция — ДАТАВРЕМЯ. Она позволяет жестко зашить конкретный момент времени прямо в текст запроса. Рассмотрим синтаксис этой конструкции:
ДАТАВРЕМЯ(Год, Месяц, День, Час, Минута, Секунда)
Проанализируем несколько примеров использования этого литерала:
ГДЕ Продажи.Период = ДАТАВРЕМЯ(2023, 10, 25, 14, 30, 0)
ГДЕ Продажи.Период >= ДАТАВРЕМЯ(2023, 10, 25)
// Это эквивалентно 25.10.2023 00:00:00
ГДЕ Документ.ДатаОплаты = ДАТАВРЕМЯ(1, 1, 1)
Один из частых вопросов: как задать интервал вида «3 минуты назад»? В языке запросов 1С нет функции NOW(), но есть мощный инструмент ДОБАВИТЬКДАТЕ. Эта функция позволяет прибавлять или отнимать определенное количество временных единиц (секунд, минут, дней и т.д.) от заданной даты.
Синтаксис функции: ДОБАВИТЬКДАТЕ(ИсходнаяДата, ТипПериода, Количество).
Рассмотрим ситуацию, когда нам нужно найти записи за последние 3 минуты относительно какой-то даты. Чтобы «отнять» время, мы просто используем отрицательное число в параметре количества. Посмотрим на пример кода:
ВЫБРАТЬ
События.Наименование,
События.Период
ИЗ
РегистрСведений.События КАК События
ГДЕ
События.Период МЕЖДУ ДОБАВИТЬКДАТЕ(&ТекущийМомент, МИНУТА, -3) И &ТекущийМомент
Здесь мы используем параметр &ТекущийМомент. Важно помнить, что внутри самого текста запроса получить текущее системное время невозможно. Это сделано для обеспечения стабильности выполнения запроса на стороне СУБД.
Разберем важный нюанс: почему в запросе 1С нет функции типа ТекущаяДата()? Это архитектурное ограничение. Если бы такая функция существовала, результат одного и того же запроса мог бы различаться в зависимости от миллисекунды его запуска, что затрудняет кэширование и оптимизацию планов запросов СУБД.
Правильный подход: всегда передавайте текущую дату как параметр перед выполнением запроса.
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ * ИЗ Справочник.Номенклатура ГДЕ ДатаСоздания > &ТекДата";
Запрос.УстановитьПараметр("ТекДата", ТекущаяДата());
Результат = Запрос.Выполнить();
Когда мы работаем с интервалами, нам часто нужно «округлить» дату до начала дня, месяца или года. Для этого используются функции НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА. Это гораздо эффективнее, чем пытаться манипулировать строками или числами.
Пример использования для получения данных с начала текущего дня:
ГДЕ Продажи.Период >= НАЧАЛОПЕРИОДА(&ПараметрДата, ДЕНЬ)
Функция КОНЕЦПЕРИОДА работает аналогично, но устанавливает время на последнюю секунду указанного периода (например, 23:59:59 для дня).
Если задача стоит не в фильтрации, а в расчете длительности (например, сколько минут прошло между заказом и отгрузкой), мы используем функцию РАЗНОСТЬДАТ.
Синтаксис: РАЗНОСТЬДАТ(Дата1, Дата2, ТипПериода).
Важное замечание: функция считает количество границ периодов. Это означает, что разница в днях между «сегодня 23:59:59» и «завтра 00:00:01» будет равна 1, хотя фактически прошло всего 2 секунды. Это нужно учитывать при расчетах высокой точности.
Проанализируем ситуацию с точки зрения производительности. Когда мы пишем условие ГДЕ, важно, чтобы СУБД могла использовать индексы. Если вы примените функцию к полю таблицы, индекс может «перестать работать».
Как делать не стоит (медленно):
ГДЕ ДОБАВИТЬКДАТЕ(ДатаДокумента, ДЕНЬ, 1) > &НужнаяДата
Здесь СУБД придется вычислить функцию для каждой строки таблицы, прежде чем сравнить ее.
Как делать правильно (быстро):
ГДЕ ДатаДокумента > ДОБАВИТЬКДАТЕ(&НужнаяДата, ДЕНЬ, -1)
Здесь функция вычисляется один раз (для параметра), а затем СУБД быстро находит нужные строки по индексу поля ДатаДокумента.
В контексте виртуальных таблиц (например, остатков или оборотов) часто недостаточно просто даты. Если в одну и ту же секунду введено несколько документов, порядок их следования определяется ссылкой. Для корректного получения итогов используются объекты Граница и МоментВремени.
Хотя эти объекты нельзя создать внутри текста запроса (через ДАТАВРЕМЯ), их крайне важно передавать в параметры, если вам нужны остатки включая или исключая движения конкретного документа.
// Пример передачи границы в параметр запроса
Граница = Новый Граница(ДокументСсылка.МоментВремени(), ВидГраницы.Включая);
Запрос.УстановитьПараметр("ПериодГраница", Граница);
Мы рассмотрели основные способы работы с временными данными в 1С. Подведем итог:
ДАТАВРЕМЯ(Г, М, Д...) для констант.ДОБАВИТЬКДАТЕ для вычисления интервалов.ГДЕ.Границу.Эти правила позволят вам писать эффективные и надежные запросы для любых задач автоматизации.