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

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

Как из даты вычесть месяцы в 1С

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

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

Главная тонкость — арифметика календаря. Вычитание месяца из 31 марта должно дать 28 (или 29) февраля, а не несуществующее «31 февраля». Функция ДобавитьМесяц решает это автоматически: если исходный день не существует в целевом месяце, результатом становится последний день этого месяца. Именно поэтому ручные вычисления через количество дней (30 или 31) почти всегда дают ошибку.

В статье разобран синтаксис функции, примеры кода для тонкого и управляемого клиента, вычитание месяцев в запросах, особенности работы с концом месяца и типичные ошибки, которые приводят к неверным датам в отчётах и документах.

Синтаксис функции ДобавитьМесяц

Функция доступна во встроенном языке 1С:Предприятие 8 во всех клиентских и серверных контекстах. Её объявление выглядит так:

1c
Результат = ДобавитьМесяц(ИсходнаяДата, КоличествоМесяцев);
// ИсходнаяДата — значение типа Дата
// КоличествоМесяцев — целое число, может быть отрицательным

Первый параметр — исходная дата (тип Дата). Второй — целое число месяцев для сдвига. Положительное значение сдвигает дату вперёд, отрицательное — назад. Чтобы вычесть, например, 3 месяца, передайте -3.

Функция возвращает новое значение типа Дата, исходная переменная не изменяется — результат нужно присвоить. Время дня (часы, минуты, секунды) при сдвиге сохраняется: если исходная дата была 15.03.2026 14:30:00, то после вычитания месяца получится 15.02.2026 14:30:00.

Базовые примеры вычитания месяцев

Простейший сценарий — вычесть фиксированное число месяцев из текущей даты или из реквизита документа:

1c
ДатаОтчета = ДобавитьМесяц(ТекущаяДатаСеанса(), -6); // полгода назад
ДатаНачалаКвартала = ДобавитьМесяц(НачалоКвартала(ТекущаяДатаСеанса()), -3); // начало прошлого квартала
ДатаОтгрузки = ДобавитьМесяц(Документ.Дата, -1); // месяц до даты документа

Переход через границу года обрабатывается автоматически. Если вычесть 2 месяца из 15 января, получится 15 ноября предыдущего года — дополнительный код для смены года писать не требуется.

Для вычитания произвольного количества, заданного пользователем (например, параметр периода в отчёте), достаточно взять значение со знаком минус:

1c
Процедура РассчитатьДатуНачала(ПериодМесяцев)
	ДатаНачала = ДобавитьМесяц(КонецДня(ТекущаяДатаСеанса()), -ПериодМесяцев);
КонецПроцедуры

Особенность: конец месяца и несуществующие дни

Ключевое правило функции: если день исходной даты отсутствует в целевом месяце, результатом будет последний день этого месяца. Вычитание одного месяца из 31 марта даст 28 или 29 февраля (в зависимости от високосности), а из 31 мая — 30 апреля.

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

Если бизнес-логика требует всегда получать конец месяца, надёжнее явно обернуть результат в КонецМесяца:

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

Вычитание месяцев в запросах

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

1c
ВЫБРАТЬ
	ДОБАВИТЬКДАТЕ(&ТекущаяДата, МЕСЯЦ, -3) КАК ДатаТриМесяцаНазад,
	Продажи.Период КАК Период
ИЗ
	РегистрНакопления.Продажи КАК Продажи
ГДЕ
	Продажи.Период >= ДОБАВИТЬКДАТЕ(&ТекущаяДата, МЕСЯЦ, -12)

Типичное применение — отбор данных за последние N месяцев без вычисления дат на стороне кода. Это удобно, когда граница периода должна зависеть от параметра запроса, а не от заранее рассчитанной переменной.

Обратите внимание: в запросе нельзя передать отрицательное число через параметр напрямую в третий аргумент в некоторых конструкциях построителя — надёжнее передавать уже вычисленное отрицательное значение или использовать выражение -&КоличествоМесяцев, если оно поддерживается в вашем контексте. Проще всего вычислить дату в коде через ДобавитьМесяц и передать в запрос готовым параметром.

Где вычитать месяцы

ДобавитьМесяц в коде

Подходит для расчётов перед запросом, в проведении документов, веб-сервисах. Результат легко проверить в отладчике.

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

Подходит для отборов и вычисляемых полей прямо в запросе, когда дата зависит от полей выборки. Менее наглядно при отладке.

Схема СКД с выражениями

Подходит для отчётов, где пользователь сам задаёт период. Сложнее поддерживать при нестандартной логике.

Расчёт периодов: начало и конец диапазона

На практике вычитание месяцев почти всегда связано с построением периода отчёта: «последние 6 месяцев», «прошлый квартал», «аналогичный месяц прошлого года». Здесь функция комбинируется с НачалоМесяца, КонецМесяца, НачалоДня.

Период «последние N месяцев»
  1. 1
    Определите опорную дату, обычно ТекущаяДатаСеанса() или дата отчёта
  2. 2
    Вычислите начало: НачалоМесяца(ДобавитьМесяц(ОпорнаяДата, -N + 1))
  3. 3
    Вычислите конец: КонецМесяца(ОпорнаяДата) или КонецДня(ОпорнаяДата)
  4. 4
    Передайте обе границы параметрами в запрос или СКД
  5. 5
    Проверьте результат на граничных датах: 1 января, 31 марта, 29 февраля високосного года

Пример для аналогичного периода прошлого года — вычитаем 12 месяцев от обеих границ текущего периода:

1c
НачалоПрошлогоГодаПериод = ДобавитьМесяц(НачалоТекущегоПериода, -12);
КонецПрошлогоГодаПериод  = ДобавитьМесяц(КонецТекущегоПериода, -12);

Такой подход сохраняет длину периода и сдвигает его ровно на год назад, что корректно для сравнительных отчётов «год к году».

Типичные ошибки и как их избежать

Типичные ошибки
01
Вычитание через секунды: Дата - 30*86400 сдвигает на 30 дней, а не на месяц — в феврале и при переходе через год результат неверен
02
Ожидание обратимости: ДобавитьМесяц(ДобавитьМесяц(31.03, -1), 1) даёт 28.03, а не 31.03 — не используйте цепочки для возврата к исходной дате
03
Передача дробного числа месяцев: функция работает с целыми значениями, дробная часть отбрасывается — сдвиг на 1,5 месяца придётся реализовывать отдельно
04
Потеря времени дня при оборачивании в НачалоМесяца/КонецМесяца там, где время было значимым, например в графиках с точностью до часа
05
Использование ТекущаяДата() в серверных процедурах многочасовых конфигураций — граница месяца может «уехать» на соседний день

Отдельная группа ошибок — работа с пустой датой. Если исходная дата не заполнена ('00010101'), вычитание месяцев вернёт дату до начала отсчёта календаря, что в запросах может привести к неожиданным отборам. Перед расчётом проверяйте заполненность:

1c
Если ЗначениеЗаполнено(ИсходнаяДата) Тогда
	НоваяДата = ДобавитьМесяц(ИсходнаяДата, -КоличествоМесяцев);
Иначе
	НоваяДата = Неопределено;
КонецЕсли;

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

После внедрения расчёта проверьте его на граничных случаях. Минимальный набор контрольных точек: 31 марта (переход на февраль), 1 января (переход через год), 29 февраля високосного года, 31 мая (месяц из 30 дней).

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

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

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

28 или 29 февраля в зависимости от високосности

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

31 февраля, 2 марта или ошибка преобразования даты

ДобавитьМесяц(15.01, -2)
Норма

15 ноября предыдущего года

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

15 ноября того же года

Время дня после сдвига
Норма

Часы, минуты и секунды совпадают с исходной датой

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

Время сброшено в 00:00:00 без явного вызова НачалоДня

Повторное прибавление того же числа месяцев
Норма

Дата совпадает с исходной, если день существует в целевом месяце

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

Ожидание точного совпадения для 31 числа — это нормальное поведение, а не дефект

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

Если в модуле уже есть типовые процедуры работы с датами (например, из БСП — общий модуль ОбщегоНазначения или РаботаСДатами), проверьте их перед написанием собственных обёрток: часто нужный расчёт периода уже реализован и протестирован.
ПЗ
Практическое замечание

FAQ

Как вычесть один месяц из текущей даты?

Используйте ДобавитьМесяц(ТекущаяДатаСеанса(), -1). Функция вернёт ту же календарную дату месяцем ранее; если такого дня нет (например, 31 число), результатом будет последний день предыдущего месяца.

Чем вычитание месяцев отличается от вычитания 30 дней?

Месяц — календарная единица переменной длины (28–31 день). Вычитание фиксированных 30 дней через арифметику секунд даёт сдвиг на 30 суток, который почти никогда не совпадает с календарным месяцем. Для месяцев корректен только ДобавитьМесяц.

Как вычесть месяцы в запросе 1С?

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

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

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

Сохраняется ли время при вычитании месяцев?

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

Что вернёт функция, если исходная дата пустая?

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

Итог

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

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