При работе с запросами в 1С часто возникает задача получить данные за определенный период, например, за один день. Стандартная функция языка запросов КОНЕЦПЕРИОДА(&Период, "ДЕНЬ") отлично справляется с этой задачей, но устанавливает время на 23:59:59. Это может стать проблемой, если в базе есть документы, созданные ровно в это время, и нам нужно отфильтровать данные, не включая последнюю секунду дня.
Проанализируем ситуацию: нам нужно установить правую границу периода так, чтобы она была равна дате с временем 23:59:58. Это позволит использовать в условии запроса строгое неравенство (<) и быть уверенными, что документы с временем 23:59:59 не попадут в выборку. Рассмотрим несколько способов решения этой задачи.
Самый логичный и простой способ — получить стандартный конец дня и вычесть из него одну секунду. Для этого в языке запросов 1С есть универсальная функция ДОБАВИТЬКДАТЕ(). Она позволяет прибавлять или вычитать различные интервалы времени (секунды, минуты, часы, дни и т.д.) из указанной даты.
Синтаксис функции: ДОБАВИТЬКДАТЕ(<Дата>, <ТипИнтервала>, <Количество>)
Где:
<Дата> — исходная дата, к которой применяется операция.<ТипИнтервала> — один из предопределенных типов: СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, МЕСЯЦ, ГОД и т.д.<Количество> — целое число, которое нужно прибавить. Для вычитания используется отрицательное число.Чтобы получить время 23:59:58, мы сначала вычисляем конец дня, а затем вычитаем одну секунду. Вот как это выглядит в коде запроса:
ДОБАВИТЬКДАТЕ(КОНЕЦПЕРИОДА(&Период, ДЕНЬ), СЕКУНДА, -1)
Разберем по шагам, что здесь происходит:
КОНЕЦПЕРИОДА(&Период, ДЕНЬ) — эта часть получает дату из параметра &Период и устанавливает ее на конец дня. Например, если &Период был '2023-10-26 15:30:00', результат будет '2023-10-26 23:59:59'.ДОБАВИТЬКДАТЕ(..., СЕКУНДА, -1) — эта часть берет полученную дату ('2023-10-26 23:59:59') и вычитает из нее одну секунду. Итоговый результат: '2023-10-26 23:59:58'.Посмотрим на пример использования в полноценном запросе. Допустим, нам нужно выбрать все документы "РеализацияТоваровУслуг" за день, но не включая те, что созданы в последнюю секунду.
ВЫБРАТЬ
РеализацияТоваровУслуг.Ссылка,
РеализацияТоваровУслуг.Дата
ИЗ
Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ГДЕ
РеализацияТоваровУслуг.Дата >= НАЧАЛОПЕРИОДА(&Период, ДЕНЬ)
И РеализацияТоваровУслуг.Дата < ДОБАВИТЬКДАТЕ(КОНЕЦПЕРИОДА(&Период, ДЕНЬ), СЕКУНДА, -1)
Обратите внимание на использование оператора < (меньше). Этот подход гарантирует, что мы получим данные до 23:59:57 включительно, что и требовалось.
Есть и альтернативный путь, который приводит к тому же результату. Вместо того чтобы отнимать от конца дня, можно прибавлять к его началу. Мы знаем, что в сутках 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С сама правильно обработает включительную границу.ГДЕ внимательно следите за оператором сравнения. Если используется <=, можно использовать КОНЕЦПЕРИОДА. Если же требуется использовать <, то вычитание одной секунды через ДОБАВИТЬКДАТЕ является правильным решением для получения нужного результата.Таким образом, функция ДОБАВИТЬКДАТЕ — это мощный и гибкий инструмент для манипуляции датами в запросах 1С, который позволяет точно настраивать временные интервалы под конкретные задачи.