Как в запросе 1С установить конец дня со временем 23:59:58?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с запросами в 1С часто возникает задача получить данные за определенный период, например, за один день. Стандартная функция языка запросов КОНЕЦПЕРИОДА(&Период, "ДЕНЬ") отлично справляется с этой задачей, но устанавливает время на 23:59:59. Это может стать проблемой, если в базе есть документы, созданные ровно в это время, и нам нужно отфильтровать данные, не включая последнюю секунду дня.

Проанализируем ситуацию: нам нужно установить правую границу периода так, чтобы она была равна дате с временем 23:59:58. Это позволит использовать в условии запроса строгое неравенство (<) и быть уверенными, что документы с временем 23:59:59 не попадут в выборку. Рассмотрим несколько способов решения этой задачи.

Решение 1: Вычитание одной секунды с помощью ДОБАВИТЬКДАТЕ

Самый логичный и простой способ — получить стандартный конец дня и вычесть из него одну секунду. Для этого в языке запросов 1С есть универсальная функция ДОБАВИТЬКДАТЕ(). Она позволяет прибавлять или вычитать различные интервалы времени (секунды, минуты, часы, дни и т.д.) из указанной даты.

Синтаксис функции: ДОБАВИТЬКДАТЕ(<Дата>, <ТипИнтервала>, <Количество>)

Где:

Чтобы получить время 23:59:58, мы сначала вычисляем конец дня, а затем вычитаем одну секунду. Вот как это выглядит в коде запроса:

ДОБАВИТЬКДАТЕ(КОНЕЦПЕРИОДА(&Период, ДЕНЬ), СЕКУНДА, -1)

Разберем по шагам, что здесь происходит:

  1. КОНЕЦПЕРИОДА(&Период, ДЕНЬ) — эта часть получает дату из параметра &Период и устанавливает ее на конец дня. Например, если &Период был '2023-10-26 15:30:00', результат будет '2023-10-26 23:59:59'.
  2. ДОБАВИТЬКДАТЕ(..., СЕКУНДА, -1) — эта часть берет полученную дату ('2023-10-26 23:59:59') и вычитает из нее одну секунду. Итоговый результат: '2023-10-26 23:59:58'.

Посмотрим на пример использования в полноценном запросе. Допустим, нам нужно выбрать все документы "РеализацияТоваровУслуг" за день, но не включая те, что созданы в последнюю секунду.


ВЫБРАТЬ
    РеализацияТоваровУслуг.Ссылка,
    РеализацияТоваровУслуг.Дата
ИЗ
    Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ГДЕ
    РеализацияТоваровУслуг.Дата >= НАЧАЛОПЕРИОДА(&Период, ДЕНЬ)
    И РеализацияТоваровУслуг.Дата < ДОБАВИТЬКДАТЕ(КОНЕЦПЕРИОДА(&Период, ДЕНЬ), СЕКУНДА, -1)

Обратите внимание на использование оператора < (меньше). Этот подход гарантирует, что мы получим данные до 23:59:57 включительно, что и требовалось.

Решение 2: Добавление секунд к началу дня

Есть и альтернативный путь, который приводит к тому же результату. Вместо того чтобы отнимать от конца дня, можно прибавлять к его началу. Мы знаем, что в сутках 24 часа, 1440 минут или 86400 секунд. Чтобы получить время 23:59:59, нужно к началу дня добавить 86399 секунд. А чтобы получить 23:59:58 — 86398 секунд.

Однако есть более изящный вариант, связанный с добавлением одного дня и вычитанием одной секунды.


// Сначала добавляем 1 день к началу периода, получаем начало следующего дня
// Например, для '26.10.2023' получим '27.10.2023 00:00:00'
ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&Период, ДЕНЬ), ДЕНЬ, 1)

// Теперь из начала следующего дня вычитаем одну секунду
// Получаем '26.10.2023 23:59:59'
ДОБАВИТЬКДАТЕ(ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&Период, ДЕНЬ), ДЕНЬ, 1), СЕКУНДА, -1)

// И, наконец, вычитаем еще одну секунду, чтобы получить нужное нам значение
ДОБАВИТЬКДАТЕ(ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&Период, ДЕНЬ), ДЕНЬ, 1), СЕКУНДА, -2)

Хотя этот способ рабочий, он более громоздкий и менее читаемый, чем первый. Рекомендуется использовать первый вариант с вычитанием одной секунды из КОНЕЦПЕРИОДА как более простой и понятный.

Важный аспект: Границы периода в виртуальных таблицах

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

Виртуальные таблицы (например, РегистрНакопления.ТоварыНаСкладах.Остатки, РегистрСведений.КурсыВалют.СрезПоследних) имеют специальные параметры для периодов. Когда вы передаете в такой параметр дату, вычисленную через КОНЕЦПЕРИОДА(&Период, ДЕНЬ), система воспринимает эту границу как включительную.

Проанализируем пример:


ВЫБРАТЬ
    Остатки.Номенклатура,
    Остатки.КоличествоОстаток
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(
        &Граница, // Сюда передаем КОНЕЦПЕРИОДА(&Период, ДЕНЬ)
        ...) КАК Остатки

Если в параметр &Граница передать '2023-10-26 23:59:59', то система рассчитает остатки включая все движения, которые были совершены в эту секунду. Механизм платформы устроен так, чтобы корректно обрабатывать эту граничную точку. В этом случае вычитать одну секунду не нужно и даже вредно, так как вы можете потерять данные о движениях, сделанных в последнюю секунду дня.

Прямая фильтрация в условии ГДЕ — это совсем другая ситуация. Здесь вы работаете с обычными операторами сравнения (=, <, >, <=, >=).


...
ГДЕ
    МойДокумент.Дата <= &КонДата

Если в &КонДата находится '2023-10-26 23:59:59', то условие МойДокумент.Дата <= &КонДата будет работать корректно и включит документы с временем 23:59:59. Однако, если по какой-то причине в коде заложено использование строгого неравенства (<), то для включения всего дня, кроме последней секунды, как раз и понадобится наше решение с вычитанием секунды.

Вывод:

Таким образом, функция ДОБАВИТЬКДАТЕ — это мощный и гибкий инструмент для манипуляции датами в запросах 1С, который позволяет точно настраивать временные интервалы под конкретные задачи.

← На главную