Разработка и Конфигурация · 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 дней», а начало или конец того дня: например, для условия отбора в отчёте или запросе. Для этого используются функции НачалоДня() и КонецДня():
НачалоПериода = НачалоДня(ТекущаяДата() - 7 * 86400); // 00:00:00 семь дней назад
КонецПериода = КонецДня(ТекущаяДата() - 1 * 86400); // 23:59:59 вчерашнего дня
КонецДня возвращает 23:59:59, что удобно для условий вида «Дата МЕЖДУ &Начало И &Конец». Альтернатива — сравнение «Дата < НачалоДня(СледующийДень)», которое не зависит от точности хранения времени.
Вычитание дней в запросе 1С
В языке запросов арифметика с датами недоступна, поэтому используется функция ДОБАВИТЬКДАТЕ с отрицательным третьим параметром:
ВЫБРАТЬ
ДОБАВИТЬКДАТЕ(Заказы.ДатаОтгрузки, ДЕНЬ, -3) КАК ДатаНапоминания
ИЗ
Документ.ЗаказПокупателя КАК Заказы
Допустимые единицы сдвига: СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, НЕДЕЛЯ, МЕСЯЦ, КВАРТАЛ, ГОД, ДЕКАДА, ПОЛУГОДИЕ. Параметр может быть выражением или параметром запроса, что позволяет задавать количество дней динамически.
Если нужно сравнить дату документа с «текущей датой минус N дней», передайте границу параметром из кода: это проще и быстрее, чем вычисления в самом запросе, и позволяет использовать индексы при сравнении.
Запрос.УстановитьПараметр("Граница", НачалоДня(ТекущаяДатаСеанса() - 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 секунд, либо через ДобавитьКДате с отрицательным значением; в запросах — через ДОБАВИТЬКДАТЕ. Для месяцев и лет используйте только ДобавитьКДате, для рабочих дней — производственный календарь, а время в дате контролируйте через НачалоДня и КонецДня.