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

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

Как вычесть дни из даты в 1С

Как вычесть дни из даты в 1С: оператор сложения с секундами, ДобавитьКДате, конец и начало дня, вычитание в запросах, учёт рабочих дней и частые ошибки.

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

Оба подхода дают корректный результат, но ведут себя по-разному при переходе через границу месяца, работе с временем и в запросах. Ниже разобраны синтаксис, примеры кода, вычитание в запросах 1С, расчёт по рабочим дням и типичные ошибки, из-за которых дата «уезжает» на час или на день.

Как 1С хранит дату и почему дни вычитаются в секундах

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

В сутках 86 400 секунд (24 × 60 × 60). Чтобы вычесть N дней, нужно вычесть N × 86400:

НоваяДата = ИсходнаяДата - 7 * 86400; // минус 7 дней

Такой способ короткий и быстрый, но требует аккуратности: если исходная дата содержит время (например, 15.03 14:30:00), результат сохранит то же время. Если нужна дата без времени, дополнительно применяют НачалоДня() или КонецДня().

Вычитание дней функцией ДобавитьКДате

Глобальная функция ДобавитьКДате умеет сдвигать дату на заданное количество единиц: секунд, минут, часов, дней, месяцев, кварталов, лет. Чтобы вычесть дни, передайте отрицательное число:

НоваяДата = ДобавитьКДате(ИсходнаяДата; "ДЕНЬ"; -7);

Преимущество функции — корректная работа с календарными границами. При сдвиге на месяцы и годы она учитывает разную длину месяцев: например, ДобавитьКДате(31.01; "МЕСЯЦ"; -1) вернёт последний день декабря, а не несуществующую дату. С арифметикой в секундах такого сдвига для месяцев добиться нельзя.

Для самих дней оба способа эквивалентны по результату. Выбор — вопрос читаемости: ДобавитьКДате самодокументируется, а умножение на 86400 требует комментария.

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

Дата - N * 86400

Быстро и коротко. Подходит только для дней, часов, минут. Не работает для месяцев и лет из-за разной длины периодов.

ДобавитьКДате(Дата; "ДЕНЬ"; -N)

Универсально и читаемо, корректно обрабатывает границы месяцев и лет. Чуть длиннее в записи.

ДОБАВИТЬКДАТЕ в запросе

Единственный способ сдвинуть дату на стороне СУБД без выгрузки данных в код.

Как получить начало или конец дня после вычитания

Частая практическая задача — получить не просто дату «минус N дней», а начало или конец того дня: например, для условия отбора в отчёте или запросе. Для этого используются функции НачалоДня() и КонецДня():

НачалоПериода = НачалоДня(ТекущаяДата() - 7 * 86400);   // 00:00:00 семь дней назад

КонецПериода = КонецДня(ТекущаяДата() - 1 * 86400); // 23:59:59 вчерашнего дня

КонецДня возвращает 23:59:59, что удобно для условий вида «Дата МЕЖДУ &Начало И &Конец». Альтернатива — сравнение «Дата < НачалоДня(СледующийДень)», которое не зависит от точности хранения времени.

Типичные ошибки
01
{'title': 'Вычитание числа дней без перевода в секунды', 'text': 'Выражение Дата - 7 вычитает 7 секунд, а не 7 дней. Признак ошибки: дата визуально не меняется.'}
02
{'title': 'Использование секунд для месяцев', 'text': 'Дата - 30 * 86400 не равно «минус месяц»: в месяцах 28–31 день. Для месяцев применяйте ДобавитьКДате.'}
03
{'title': 'Потеря времени при сравнении', 'text': 'Если документ датирован 14:30, а отбор строится с полуночи, документ выпадает из периода. Используйте НачалоДня/КонецДня.'}
04
{'title': 'Игнорирование пустой даты', 'text': 'Вычитание из пустой даты (01.01.0001) даёт отрицательное значение и ошибку. Проверяйте ЗначениеЗаполнено(Дата).'}

Вычитание дней в запросе 1С

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

ВЫБРАТЬ

ДОБАВИТЬКДАТЕ(Заказы.ДатаОтгрузки, ДЕНЬ, -3) КАК ДатаНапоминания

ИЗ

Документ.ЗаказПокупателя КАК Заказы

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

Если нужно сравнить дату документа с «текущей датой минус N дней», передайте границу параметром из кода: это проще и быстрее, чем вычисления в самом запросе, и позволяет использовать индексы при сравнении.

bsl
Запрос.УстановитьПараметр("Граница", НачалоДня(ТекущаяДатаСеанса() - 30 * 86400));

Вычитание рабочих дней по производственному календарю

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

Общий алгоритм самостоятельной реализации: в цикле сдвигать дату на один день назад и проверять по календарю, является ли день рабочим; счётчик рабочих дней увеличивать только для рабочих. Цикл продолжается, пока не наберётся нужное количество.

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

Проверка результата и граничные случаи

После вычитания дат полезно проверить результат на контрольных примерах: переход через начало месяца (01.03 минус 1 день должен дать последний день февраля), переход через новый год и високосный февраль. Оба рассмотренных способа корректно обрабатывают эти ситуации, ошибки обычно возникают из-за ручной арифметики с месяцами.

Отдельный случай — разница между двумя датами. Оператор вычитания двух дат возвращает разность в секундах; чтобы получить количество дней между датами, разделите результат на 86400 и при необходимости округлите через Цел(). Учитывайте, что при наличии времени результат может быть дробным.

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

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

Сдвиг на дни через границу месяца
Норма

01.03 минус 1 день = последний день февраля

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

Получена несуществующая дата или ошибка преобразования

Время в результирующей дате
Норма

Время соответствует ожиданию (00:00:00 после НачалоДня)

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

Неожиданное время мешает отбору в отчёте

Пустая исходная дата
Норма

Перед вычитанием выполнена проверка ЗначениеЗаполнено

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

Вычитание из 01.01.0001 приводит к ошибке

Частые вопросы о вычитании дат в 1С

Как вычесть из даты один день в 1С?

Используйте выражение Дата - 86400 или ДобавитьКДате(Дата; "ДЕНЬ"; -1). Оба варианта вернут предыдущие сутки с сохранением времени исходной даты.

Как узнать разницу между двумя датами в днях?

Вычтите одну дату из другой — получите разницу в секундах. Разделите её на 86400: Цел((Дата2 - Дата1) / 86400). Если даты содержат время, предварительно примените НачалоДня к обеим, чтобы получить целое число календарных дней.

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

Арифметика в секундах для месяцев не подходит из-за разной длины месяцев. Используйте ДобавитьКДате(Дата; "МЕСЯЦ"; -1) или ДобавитьКДате(Дата; "ГОД"; -1) — функция корректно обработает границы, например 31 марта минус месяц даст последний день февраля.

Почему выражение Дата - 7 не меняет дату?

Потому что вычитаются 7 секунд, а не 7 дней. Дату нужно сдвигать на 7 * 86400 секунд либо использовать ДобавитьКДате с типом ДЕНЬ.

Как вычесть дни в запросе динамического списка?

В тексте запроса примените ДОБАВИТЬКДАТЕ(ПолеДаты, ДЕНЬ, -N). Если количество дней задаёт пользователь, передайте его через параметр запроса и подставьте параметр в третий аргумент функции.

Как учесть часовые пояса при вычитании?

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

Итог

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

Дни вычитаются либо как N * 86400 секунд, либо через ДобавитьКДате с отрицательным значением; в запросах — через ДОБАВИТЬКДАТЕ. Для месяцев и лет используйте только ДобавитьКДате, для рабочих дней — производственный календарь, а время в дате контролируйте через НачалоДня и КонецДня.