Разработка и Конфигурация · 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), функция вернёт пустую дату. Это удобно: не требуется отдельная проверка перед вызовом, но при дальнейшем использовании результата пустоту всё равно стоит контролировать.
ПрошлыйМесяц = ДобавитьМесяц(ТекущаяДатаСеанса(), -1);Особенность конца месяца: из 31 марта в февраль
Главный нюанс при вычитании месяца — ситуация, когда в целевом месяце нет дня с таким номером. Платформа в этом случае возвращает последний день целевого месяца. Например, ДобавитьМесяц(Дата(2026, 3, 31), -1) даст 29.02.2026 в високосном году и 28.02.2023 в обычном.
Это поведение не всегда очевидно при серии операций. Если отнять месяц от 31 марта (получится 28/29 февраля), а затем прибавить месяц обратно, результатом будет 28/29 марта, а не исходное 31 марта. Обратная операция не гарантирует возврата к исходной дате — это важно учитывать в алгоритмах, где даты проходят цепочку пересчётов.
Если бизнес-логика требует сохранить «крайний день месяца», определяйте это условие явно: сравнивайте исходную дату с КонецМесяца(ИсходнаяДата) и в этом случае принудительно берите конец целевого месяца.
Как отнять месяц в запросе
В языке запросов 1С функция ДобавитьМесяц недоступна. Вместо неё используется конструкция ДОБАВИТЬКДАТЕ(Дата, ТипУвеличения, Количество), где тип увеличения — МЕСЯЦ, а количество может быть отрицательным.
ВЫБРАТЬ
ДОБАВИТЬКДАТЕ(&ДатаОтчета, МЕСЯЦ, -1) КАК ДатаМесяцНазад
Типичный сценарий — отбор документов за предыдущий месяц относительно переданной даты. Для этого вычисляют границы периода через параметры и накладывают условие на дату документа.
- 1Передайте в запрос параметр с опорной датой
- 2Вычислите начало периода: НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&Дата, МЕСЯЦ, -1), МЕСЯЦ)
- 3Вычислите конец периода: КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&Дата, МЕСЯЦ, -1), МЕСЯЦ)
- 4Наложите условие: Документ.Дата МЕЖДУ &НачалоПериода И &КонецПериода
- 5Выполните запрос и проверьте попадание граничных дат в результат
Помните, что в запросах параметры дат без времени трактуются как начало дня (00:00:00). Если документ проведён в последний день месяца в 14:30, условие «меньше или равно концу дня без времени» его не захватит — используйте КОНЕЦПЕРИОДА или сравнение «меньше начала следующего периода».
Почему нельзя просто вычесть 30 дней
В 1С даты можно вычитать и складывать с числом секунд: Дата - 30 24 60 * 60. Такой приём иногда встречается в старом коде, но для месяцев он некорректен. Февраль содержит 28–29 дней, а часть месяцев — 31. При вычитании фиксированных 30 дней результат будет «плавать» на 1–3 дня в зависимости от исходной даты.
Для отчётных периодов такая погрешность критична: документы граничных дат попадут не в тот период, итоги по оборотам разойдутся с предыдущими закрытыми месяцами, а сверка с контрагентами покажет расхождения. Поэтому для календарных смещений всегда применяйте ДобавитьМесяц, а арифметику с секундами оставьте для точных интервалов (часы, минуты, конкретное число дней).
Получение начала и конца предыдущего месяца
На практике чаще нужна не просто дата месяц назад, а весь предыдущий календарный месяц как период. Для этого функцию вычитания комбинируют с НачалоМесяца() и КонецМесяца().
ДатаМесяцНазад = ДобавитьМесяц(ТекущаяДатаСеанса(), -1);
НачалоПрошлогоМесяца = НачалоМесяца(ДатаМесяцНазад);
КонецПрошлогоМесяца = КонецМесяца(ДатаМесяцНазад);
Такая пара границ корректна для любой исходной даты, включая январь (переход на декабрь прошлого года) и даты с 29 по 31 число. Именно этот вариант рекомендуется для формирования отчётов за прошлый месяц и для регламентных заданий, запускаемых первого числа.
Как проверить результат
Получено 15.02
Получено 13.02 или 14.02 — признак вычитания 30 дней
Получено 28/29.02 — последний день февраля
Ошибка выполнения или дата в марте
Получено 10.12 прошлого года
Год не изменился — смещение выполнено вручную с ошибкой
Альтернативные подходы и когда они уместны
В типовых конфигурациях на БСП (библиотека стандартных подсистем) доступны общие модули для работы с датами, например функции получения периодов. Они удобны, когда нужен не одиночный сдвиг, а стандартный период: «прошлый месяц», «прошлый квартал». Если конфигурация уже использует БСП, предпочтительнее вызывать её механизмы для единообразия кода.
Ещё один вариант — хранить смещение в настройках и вычислять дату на лету, что удобно для регламентных заданий с параметризуемой глубиной выборки. Но внутри любого из этих подходов физическое вычитание месяца всё равно выполняется через ДобавитьМесяц или ДОБАВИТЬКДАТЕ — другого корректного механизма в платформе нет.
Сравнение вариантов
Стандартный способ в коде. Корректные переходы через год и короткие месяцы. Не работает в запросах.
Единственный корректный способ в языке запросов. Требует аккуратности с границами периода и временем.
Просто, но даёт погрешность 1–3 дня. Допустимо только для грубых прикидок, не для учётных данных.
Что важно запомнить
Месяц от даты в 1С отнимают функцией ДобавитьМесяц(Дата, -1) в коде и ДОБАВИТЬКДАТЕ(Дата, МЕСЯЦ, -1) в запросах. При переходе в короткий месяц возвращается его последний день. Вычитание фиксированных 30 дней для учётных задач недопустимо.
Частые вопросы
Что вернёт ДобавитьМесяц, если отнять месяц от пустой даты?
Функция вернёт пустую дату (01.01.0001), ошибки не возникнет. Однако дальнейшее использование такого значения в отборах и сравнениях может дать неожиданные результаты, поэтому пустоту результата стоит проверять функцией ЗначениеЗаполнено перед использованием.
Как отнять месяц от даты, введённой пользователем на форме?
Получите значение реквизита формы в переменную, примените ДобавитьМесяц(Значение, -1) и присвойте результат обратно реквизиту или в новое поле. Реквизит должен иметь тип Дата, иначе потребуется преобразование из строки функцией Дата().
Можно ли отнять месяц в СКД (системе компоновки данных)?
Да. В тексте запроса набора данных используйте ДОБАВИТЬКДАТЕ с отрицательным смещением. Если дата приходит как параметр компоновки, вычисление выполняется прямо в запросе, дополнительный код не нужен.
Как получить дату ровно год назад?
Вызовите ДобавитьМесяц(Дата, -12) — это корректнее, чем вычитание 365 дней, поскольку учитывает високосные годы. Из 29 февраля результатом будет 28 февраля невисокосного года.
Почему после вычитания месяца дата сравнивается неправильно в условии?
Чаще всего причина в составляющей времени: дата содержит часы, минуты и секунды, а сравнивается с датой без времени. Приведите значения к началу дня функцией НачалоДня() или используйте КонецДня() для верхней границы периода.