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

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

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

Особенности работы с типом Дата в языке запросов

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

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

Следует помнить, что в языке запросов 1С нет прямого оператора вычитания дней в стиле SQL (например, `DATE - 1`), который работал бы предсказуемо во всех контекстах без дополнительных функций. Использование неподходящих методов может привести к тому, что ваш отчет покажет данные за вчерашний день, но с временным сдвигом, что исказит агрегированные итоги.

⚠️ Внимание: При работе с переходом на летнее/зимнее время или в разных часовых поясах сервера, простые арифметические операции могут давать сбой. Всегда используйте серверное время или явно указывайте часовой пояс в параметрах запроса, если это критично для бизнеса.

Платформа предоставляет мощный инструментарий для манипуляций, но требует от программиста дисциплины в определении границ периодов. Неправильное понимание того, что считается «началом дня», может привести к тому, что вы потеряете документы, проведенные ровно в 00:00:00 нужной даты.

Использование функции НАЧАЛОДНЯ для сброса времени

Самый надежный способ подготовить дату к вычитанию суток — это сначала привести её к началу дня. Функция НАЧАЛОДНЯ() является стандартом де-факто в разработке под 1С. Она принимает любую дату и время, а возвращает дату с обнуленной временной частью (00:00:00). Это фундаментальный шаг перед любыми календарными вычислениями.

После того как время сброшено, вы можете быть уверены, что последующее вычитание затронет именно календарные сутки, а не часы или минуты. Это особенно важно при формировании выборок за «вчера», «позавчера» или при расчете остатков на конец предыдущего дня. Без этой функции вы рискуете получить «плавающий» результат.

Рассмотрим пример использования в контексте запроса. Допустим, у нас есть параметр &ДатаОтчета, который содержит текущую дату и время (например, 15.05.2026 14:30:00). Нам нужно получить данные строго за предыдущие сутки. Сначала мы применяем функцию нормализации.

ВЫБРАТЬ

НАЧАЛОДНЯ(&ДатаОтчета) КАК НачалоТекущегоДня

ИЗ

РегистрНакопления.Продажи

Такой подход гарантирует, что мы работаем с целыми сутками. Далее к полученному значению можно применять функции смещения. Комбинация НАЧАЛОДНЯ и функций сдвига времени является наиболее читаемой и поддерживаемой конструкцией в коде 1С.

💡

Используйте функцию НАЧАЛОДНЯ() даже если вы уверены, что в параметре нет времени. Это защитит ваш код от ошибок в будущем, если логика формирования параметра изменится.

Применение функции ДОБАВИТЬКДАТЕ для вычитания суток

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

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

Вот как выглядит корректная конструкция для вычитания одного дня в теле запроса:

ВЫБРАТЬ

ДОБАВИТЬКДАТЕ(НАЧАЛОДНЯ(&ДатаОтчета), ДЕНЬ, -1) КАК ДатаВчера

ИЗ

Справочник.Номенклатура

Здесь мы комбинируем два подхода: сначала обнуляем время функцией НАЧАЛОДНЯ, а затем сдвигаем дату назад на один день с помощью ДОБАВИТЬКДАТЕ. Это классический паттерн, который обеспечивает предсказуемый результат независимо от того, в какое время суток был сформирован отчет.

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

  • 📅 Функция корректно обрабатывает переход через границу года (31 декабря → 30 декабря).
  • 📅 Автоматически учитывает високосные годы при вычитании дней от 1 марта.
  • 📅 Позволяет вычитать сразу несколько дней, передав отрицательное число (например, -7 для недели назад).

Использование этой функции в условии отбора (секция ГДЕ) позволяет эффективно использовать индексы базы данных, если поле в таблице имеет тип «Дата» и индекс построён корректно.

📊 Какой метод вы используете чаще всего?
Функция ДОБАВИТЬКДАТЕ
Ручное вычитание в коде перед запросом
Функция НАЧАЛОДНЯ + сдвиг
Другие методы

Альтернативные методы: СЕГОДНЯ и константы времени

В некоторых сценариях, когда отчет формируется строго за «вчерашний день» относительно момента запуска, можно использовать функцию СЕГОДНЯ(). Эта функция возвращает текущую дату с обнуленным временем на момент выполнения запроса на сервере. Вычитание дня от неё также выполняется через ДОБАВИТЬКДАТЕ.

Однако стоит быть осторожным: функция СЕГОДНЯ() зависит от системного времени сервера 1С. Если сервер находится в другом часовом поясе или если отчет должен формироваться по «рабочей дате» пользователя, а не по системному времени, этот метод может дать неверный результат. В таких случаях надежнее передавать дату параметром.

Еще один вариант — использование констант или предопределенных значений в коде встроенного языка перед формированием текста запроса. Вы можете вычислить нужную дату в переменную типа Date в коде 1С, а в запрос подставить уже готовое значение. Это переносит вычислительную нагрузку с СУБД на сервер приложений.

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

⚠️ Внимание: Функция СЕГОДНЯ() возвращает дату по времени сервера 1С. Если ваши пользователи работают из разных регионов, убедитесь, что это соответствует бизнес-логике отчета, иначе данные могут «уехать» на соседний день.

Выбор между вычислением в запросе и вычислением в коде часто зависит от конкретных требований к гибкости отчета. Если пользователю нужно быстро менять период «на лету», лучше оставить логику внутри запроса.

Работа с интервалами в условиях отбора (ГДЕ)

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

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

Пример правильной конструкции условия отбора:

ГДЕ

Документ.Дата >= ДОБАВИТЬКДАТЕ(НАЧАЛОДНЯ(&Период), ДЕНЬ, -1)

И Документ.Дата < НАЧАЛОДНЯ(&Период)

Обратите внимание на знаки сравнения: для начала используется «больше или равно» (>=), а для конца — строго «меньше» (<). Это исключает попадание документов, проведенных ровно в 00:00:00 текущего дня, которые формально относятся уже к новому периоду.

Использование такой конструкции позволяет базе данных эффективно использовать индексы по полю Дата. Если вы примените функцию к полю таблицы (например, НАЧАЛОДНЯ(Документ.Дата)), индекс может не сработать, что приведет к полному сканированию таблицы и тормозам на больших объемах данных.

☑️ Проверка условий отбора

Выполнено: 0 / 4

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

При разработке высоконагруженных отчетов вопрос производительности выходит на первый план. Разные способы вычитания дня могут по-разному влиять на план выполнения запроса оптимизатором СУБД (MS SQL, PostgreSQL или встроенной DBMS 1С). Понимание этих различий помогает избежать проблем со скоростью работы в будущем.

Ниже приведена таблица, сравнивающая основные подходы к вычитанию дня в контексте их влияния на производительность и читаемость кода.

Метод Производительность Читаемость Риски
ДОБАВИТЬКДАТЕ в запросе Высокая Отличная Минимальные
Вычисление в коде 1С Высокая Хорошая Зависимость от клиента
Ручная арифметика (Дата - 1) Средняя Низкая Ошибки со временем
Функция СЕГОДНЯ() Высокая Отличная Часовые пояса

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

Ручная арифметика (попытка вычесть число из даты без функций) является самым рискованным методом. В разных версиях платформы и разных СУБД поведение оператора вычитания для типа Дата может отличаться, что делает такой код непереносимым и хрупким.

Почему индексы не работают?

Если вы напишете условие ГДЕ НАЧАЛОДНЯ(Таблица.Дата) = &Значение, то база данных не сможет использовать индекс по полю Дата, так как функция применяется к самому полю. Всегда применяйте функции к параметрам, а не к полям таблиц.

Частые ошибки и способы их предотвращения

Одной из самых распространенных ошибок является путаница между типами «Дата» и «Строка». При формировании динамического запроса (через конструктор или вручную в коде) программисты иногда пытаются подставить дату как строку, что приводит к ошибкам преобразования типов или неверной интерпретации формата (ДД.ММ.ГГГГ против ГГГГ-ММ-ДД).

Всегда используйте параметры запроса (&ИмяПараметра) для передачи дат. Это позволяет платформе 1С автоматически выполнить правильное преобразование типов и экранирование значений. Прямая вставка значений в текст запроса через конкатенацию строк — это путь к SQL-инъекциям и ошибкам локали.

Еще одна ошибка — игнорирование времени в регистрах накопления. В некоторых конфигурациях документы могут проводиться с точностью до минуты или секунды, и простое сравнение дат без учета функции НАЧАЛОДНЯ может отсечь часть документов, проведенных в первые секунды дня.

  • 🔍 Всегда проверяйте тип значения параметра перед выполнением запроса.
  • 🔍 Используйте явное приведение типов, если источник данных не гарантирован.
  • 🔍 Тестируйте запросы на границах периодов (переход месяца, года, високосный год).

Для предотвращения ошибок рекомендуется использовать отладчик запросов, встроенный в Конфигуратор 1С. Он позволяет увидеть итоговый текст запроса, который уходит в СУБД, и проверить, корректно ли подставились параметры даты.

⚠️ Внимание: Интерфейс и возможности конструктора запросов могут отличаться в зависимости от версии платформы 1С (8.2, 8.3, 8.3.20+). Если вы не находите нужной функции в визуальном конструкторе, вводите её вручную в текстовом режиме.

FAQ: Часто задаваемые вопросы

Как вычесть месяц или год вместо дня?

Для вычитания месяца или года используется та же функция ДОБАВИТЬКДАТЕ, но меняется второй параметр. Вместо ДЕНЬ укажите МЕСЯЦ или ГОД. Например: ДОБАВИТЬКДАТЕ(Дата, МЕСЯЦ, -1) вычтет один календарный месяц, корректно обрабатывая разное количество дней в месяцах.

Почему мой запрос возвращает пустую выборку при вычитании дня?

Скорее всего, проблема в временной части даты. Если вы ищете документы за вчерашний день, но в условии стоит строгое равенство (=), а документы имеют время (например, 10:00), то условие не выполнится. Используйте диапазон от начала вчерашнего дня до начала сегодняшнего.

Можно ли вычесть день в обычном выражении 1С (не в запросе)?

Да, в обычном коде 1С (на клиенте или сервере) можно использовать ту же функцию ДобавитьКДате(). Синтаксис идентичен: НоваяДата = ДобавитьКДате(ИсходнаяДата, "День", -1). Также работает оператор вычитания, если вычесть количество секунд в сутках, но функция надежнее.

Как получить конец вчерашнего дня (23:59:59)?

Функции «КонецДня» в языке запросов нет. Стандартный прием: взять начало следующего дня и вычесть одну секунду. Формула: ДОБАВИТЬКДАТЕ(НАЧАЛОДНЯ(&Сегодня), СЕКУНДА, -1). Это даст вам временную метку 23:59:59 предыдущих суток.

Влияет ли часовой пояс сервера на функцию СЕГОДНЯ()?

Да, функция СЕГОДНЯ() возвращает дату согласно времени операционной системы сервера 1С. Если сервер в Москве, а пользователь во Владивостоке, «сегодня» для отчета будет московским. Для пользовательских отчетов лучше использовать ТЕКУЩАЯДАТА() с учетом/session или передавать дату параметром из формы.