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

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

Как отнять месяц от даты в 1С

Как отнять месяц от даты в 1С с помощью ДобавитьМесяц(Дата, -1). Разбор нюансов конца месяца, запросов, примеры кода и типичные ошибки.

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

Функция корректно обрабатывает переходы через год, високосные феврали и ситуации, когда в целевом месяце нет такого числа. Например, при вычитании месяца из 31 марта результатом будет 28 или 29 февраля, а не ошибка. Однако у этого поведения есть нюансы, которые важно понимать, чтобы не получить неожиданные даты в расчётах.

Функция ДобавитьМесяц с отрицательным параметром

Основной способ отнять месяц в коде встроенного языка — вызвать ДобавитьМесяц(Дата, КоличествоМесяцев) и передать вторым параметром отрицательное число. Функция возвращает новое значение типа Дата, исходная переменная при этом не изменяется.

ИсходнаяДата = Дата(2026, 3, 15);

НоваяДата = ДобавитьМесяц(ИсходнаяДата, -1);

// Результат: 15.02.2026

Можно отнимать сразу несколько месяцев, передавая -2, -3, -12 и так далее. Переход через границу года платформа выполняет автоматически: ДобавитьМесяц(Дата(2026, 1, 10), -1) вернёт 10.12.2023. Время, если оно присутствует в значении даты, сохраняется без изменений.

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

bsl
ПрошлыйМесяц = ДобавитьМесяц(ТекущаяДатаСеанса(), -1);

Особенность конца месяца: из 31 марта в февраль

Главный нюанс при вычитании месяца — ситуация, когда в целевом месяце нет дня с таким номером. Платформа в этом случае возвращает последний день целевого месяца. Например, ДобавитьМесяц(Дата(2026, 3, 31), -1) даст 29.02.2026 в високосном году и 28.02.2023 в обычном.

Это поведение не всегда очевидно при серии операций. Если отнять месяц от 31 марта (получится 28/29 февраля), а затем прибавить месяц обратно, результатом будет 28/29 марта, а не исходное 31 марта. Обратная операция не гарантирует возврата к исходной дате — это важно учитывать в алгоритмах, где даты проходят цепочку пересчётов.

Если бизнес-логика требует сохранить «крайний день месяца», определяйте это условие явно: сравнивайте исходную дату с КонецМесяца(ИсходнаяДата) и в этом случае принудительно берите конец целевого месяца.

Как отнять месяц в запросе

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

ВЫБРАТЬ

ДОБАВИТЬКДАТЕ(&ДатаОтчета, МЕСЯЦ, -1) КАК ДатаМесяцНазад

Типичный сценарий — отбор документов за предыдущий месяц относительно переданной даты. Для этого вычисляют границы периода через параметры и накладывают условие на дату документа.

Порядок действий для отбора за прошлый месяц
  1. 1
    Передайте в запрос параметр с опорной датой
  2. 2
    Вычислите начало периода: НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&Дата, МЕСЯЦ, -1), МЕСЯЦ)
  3. 3
    Вычислите конец периода: КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&Дата, МЕСЯЦ, -1), МЕСЯЦ)
  4. 4
    Наложите условие: Документ.Дата МЕЖДУ &НачалоПериода И &КонецПериода
  5. 5
    Выполните запрос и проверьте попадание граничных дат в результат

Помните, что в запросах параметры дат без времени трактуются как начало дня (00:00:00). Если документ проведён в последний день месяца в 14:30, условие «меньше или равно концу дня без времени» его не захватит — используйте КОНЕЦПЕРИОДА или сравнение «меньше начала следующего периода».

Почему нельзя просто вычесть 30 дней

В 1С даты можно вычитать и складывать с числом секунд: Дата - 30 24 60 * 60. Такой приём иногда встречается в старом коде, но для месяцев он некорректен. Февраль содержит 28–29 дней, а часть месяцев — 31. При вычитании фиксированных 30 дней результат будет «плавать» на 1–3 дня в зависимости от исходной даты.

Для отчётных периодов такая погрешность критична: документы граничных дат попадут не в тот период, итоги по оборотам разойдутся с предыдущими закрытыми месяцами, а сверка с контрагентами покажет расхождения. Поэтому для календарных смещений всегда применяйте ДобавитьМесяц, а арифметику с секундами оставьте для точных интервалов (часы, минуты, конкретное число дней).

Типичные ошибки
01
Вычитание 30 дней вместо ДобавитьМесяц — дата смещается на 1–3 дня в зависимости от месяца
02
Ожидание, что ДобавитьМесяц(ДобавитьМесяц(Дата, -1), 1) вернёт исходную дату — для 31-го числа это не так
03
Сравнение дат в запросе без учёта времени — документы последнего дня выпадают из выборки
04
Присвоение результата той же переменной без сохранения исходной даты, когда она ещё нужна ниже по коду

Получение начала и конца предыдущего месяца

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

ДатаМесяцНазад = ДобавитьМесяц(ТекущаяДатаСеанса(), -1);

НачалоПрошлогоМесяца = НачалоМесяца(ДатаМесяцНазад);

КонецПрошлогоМесяца = КонецМесяца(ДатаМесяцНазад);

Такая пара границ корректна для любой исходной даты, включая январь (переход на декабрь прошлого года) и даты с 29 по 31 число. Именно этот вариант рекомендуется для формирования отчётов за прошлый месяц и для регламентных заданий, запускаемых первого числа.

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

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

Вычитание месяца из 15.03
Норма

Получено 15.02

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

Получено 13.02 или 14.02 — признак вычитания 30 дней

Вычитание месяца из 31.03
Норма

Получено 28/29.02 — последний день февраля

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

Ошибка выполнения или дата в марте

Вычитание месяца из 10.01
Норма

Получено 10.12 прошлого года

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

Год не изменился — смещение выполнено вручную с ошибкой

Альтернативные подходы и когда они уместны

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

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

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

ДобавитьМесяц(Дата, -1)

Стандартный способ в коде. Корректные переходы через год и короткие месяцы. Не работает в запросах.

ДОБАВИТЬКДАТЕ(Дата, МЕСЯЦ, -1)

Единственный корректный способ в языке запросов. Требует аккуратности с границами периода и временем.

Вычитание 30 дней в секундах

Просто, но даёт погрешность 1–3 дня. Допустимо только для грубых прикидок, не для учётных данных.

Итог

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

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

Частые вопросы

Что вернёт ДобавитьМесяц, если отнять месяц от пустой даты?

Функция вернёт пустую дату (01.01.0001), ошибки не возникнет. Однако дальнейшее использование такого значения в отборах и сравнениях может дать неожиданные результаты, поэтому пустоту результата стоит проверять функцией ЗначениеЗаполнено перед использованием.

Как отнять месяц от даты, введённой пользователем на форме?

Получите значение реквизита формы в переменную, примените ДобавитьМесяц(Значение, -1) и присвойте результат обратно реквизиту или в новое поле. Реквизит должен иметь тип Дата, иначе потребуется преобразование из строки функцией Дата().

Можно ли отнять месяц в СКД (системе компоновки данных)?

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

Как получить дату ровно год назад?

Вызовите ДобавитьМесяц(Дата, -12) — это корректнее, чем вычитание 365 дней, поскольку учитывает високосные годы. Из 29 февраля результатом будет 28 февраля невисокосного года.

Почему после вычитания месяца дата сравнивается неправильно в условии?

Чаще всего причина в составляющей времени: дата содержит часы, минуты и секунды, а сравнивается с датой без времени. Приведите значения к началу дня функцией НачалоДня() или используйте КонецДня() для верхней границы периода.