Разработка и Конфигурация · 10 мин
Как из даты вычесть месяцы в 1С
Как вычесть месяцы из даты в 1С с помощью ДобавитьМесяц: синтаксис, примеры кода, работа с концом месяца, запросы и типичные ошибки разработчиков.
Вычитание месяцев из даты — типовая задача при разработке отчётов, расчёте периодов хранения, определении дат начала квартала или срока действия договора. Во встроенном языке 1С нет отдельной функции «ВычестьМесяц», но она и не нужна: стандартная функция ДобавитьМесяц принимает отрицательные значения и корректно сдвигает дату назад.
Главная тонкость — арифметика календаря. Вычитание месяца из 31 марта должно дать 28 (или 29) февраля, а не несуществующее «31 февраля». Функция ДобавитьМесяц решает это автоматически: если исходный день не существует в целевом месяце, результатом становится последний день этого месяца. Именно поэтому ручные вычисления через количество дней (30 или 31) почти всегда дают ошибку.
В статье разобран синтаксис функции, примеры кода для тонкого и управляемого клиента, вычитание месяцев в запросах, особенности работы с концом месяца и типичные ошибки, которые приводят к неверным датам в отчётах и документах.
Синтаксис функции ДобавитьМесяц
Функция доступна во встроенном языке 1С:Предприятие 8 во всех клиентских и серверных контекстах. Её объявление выглядит так:
Результат = ДобавитьМесяц(ИсходнаяДата, КоличествоМесяцев);
// ИсходнаяДата — значение типа Дата
// КоличествоМесяцев — целое число, может быть отрицательнымПервый параметр — исходная дата (тип Дата). Второй — целое число месяцев для сдвига. Положительное значение сдвигает дату вперёд, отрицательное — назад. Чтобы вычесть, например, 3 месяца, передайте -3.
Функция возвращает новое значение типа Дата, исходная переменная не изменяется — результат нужно присвоить. Время дня (часы, минуты, секунды) при сдвиге сохраняется: если исходная дата была 15.03.2026 14:30:00, то после вычитания месяца получится 15.02.2026 14:30:00.
Базовые примеры вычитания месяцев
Простейший сценарий — вычесть фиксированное число месяцев из текущей даты или из реквизита документа:
ДатаОтчета = ДобавитьМесяц(ТекущаяДатаСеанса(), -6); // полгода назад
ДатаНачалаКвартала = ДобавитьМесяц(НачалоКвартала(ТекущаяДатаСеанса()), -3); // начало прошлого квартала
ДатаОтгрузки = ДобавитьМесяц(Документ.Дата, -1); // месяц до даты документаПереход через границу года обрабатывается автоматически. Если вычесть 2 месяца из 15 января, получится 15 ноября предыдущего года — дополнительный код для смены года писать не требуется.
Для вычитания произвольного количества, заданного пользователем (например, параметр периода в отчёте), достаточно взять значение со знаком минус:
Процедура РассчитатьДатуНачала(ПериодМесяцев)
ДатаНачала = ДобавитьМесяц(КонецДня(ТекущаяДатаСеанса()), -ПериодМесяцев);
КонецПроцедурыОсобенность: конец месяца и несуществующие дни
Ключевое правило функции: если день исходной даты отсутствует в целевом месяце, результатом будет последний день этого месяца. Вычитание одного месяца из 31 марта даст 28 или 29 февраля (в зависимости от високосности), а из 31 мая — 30 апреля.
Это поведение удобно для расчётов «месяц назад», но может давать неожиданный эффект при цепочках операций. Если из 31 марта вычесть месяц (получим 28 февраля), а затем прибавить месяц обратно, результатом будет 28 марта, а не исходное 31 марта. Операция необратима — учитывайте это при итеративных расчётах графиков платежей.
Если бизнес-логика требует всегда получать конец месяца, надёжнее явно обернуть результат в КонецМесяца:
КонецПрошлогоМесяца = КонецМесяца(ДобавитьМесяц(ТекущаяДатаСеанса(), -1));Вычитание месяцев в запросах
В языке запросов 1С функция называется ДОБАВИТЬКДАТЕ и принимает четыре параметра: дату, тип периода, количество. Для вычитания количество указывается отрицательным:
ВЫБРАТЬ
ДОБАВИТЬКДАТЕ(&ТекущаяДата, МЕСЯЦ, -3) КАК ДатаТриМесяцаНазад,
Продажи.Период КАК Период
ИЗ
РегистрНакопления.Продажи КАК Продажи
ГДЕ
Продажи.Период >= ДОБАВИТЬКДАТЕ(&ТекущаяДата, МЕСЯЦ, -12)Типичное применение — отбор данных за последние N месяцев без вычисления дат на стороне кода. Это удобно, когда граница периода должна зависеть от параметра запроса, а не от заранее рассчитанной переменной.
Обратите внимание: в запросе нельзя передать отрицательное число через параметр напрямую в третий аргумент в некоторых конструкциях построителя — надёжнее передавать уже вычисленное отрицательное значение или использовать выражение -&КоличествоМесяцев, если оно поддерживается в вашем контексте. Проще всего вычислить дату в коде через ДобавитьМесяц и передать в запрос готовым параметром.
Где вычитать месяцы
Подходит для расчётов перед запросом, в проведении документов, веб-сервисах. Результат легко проверить в отладчике.
Подходит для отборов и вычисляемых полей прямо в запросе, когда дата зависит от полей выборки. Менее наглядно при отладке.
Подходит для отчётов, где пользователь сам задаёт период. Сложнее поддерживать при нестандартной логике.
Расчёт периодов: начало и конец диапазона
На практике вычитание месяцев почти всегда связано с построением периода отчёта: «последние 6 месяцев», «прошлый квартал», «аналогичный месяц прошлого года». Здесь функция комбинируется с НачалоМесяца, КонецМесяца, НачалоДня.
- 1Определите опорную дату, обычно ТекущаяДатаСеанса() или дата отчёта
- 2Вычислите начало: НачалоМесяца(ДобавитьМесяц(ОпорнаяДата, -N + 1))
- 3Вычислите конец: КонецМесяца(ОпорнаяДата) или КонецДня(ОпорнаяДата)
- 4Передайте обе границы параметрами в запрос или СКД
- 5Проверьте результат на граничных датах: 1 января, 31 марта, 29 февраля високосного года
Пример для аналогичного периода прошлого года — вычитаем 12 месяцев от обеих границ текущего периода:
НачалоПрошлогоГодаПериод = ДобавитьМесяц(НачалоТекущегоПериода, -12);
КонецПрошлогоГодаПериод = ДобавитьМесяц(КонецТекущегоПериода, -12);Такой подход сохраняет длину периода и сдвигает его ровно на год назад, что корректно для сравнительных отчётов «год к году».
Типичные ошибки и как их избежать
Отдельная группа ошибок — работа с пустой датой. Если исходная дата не заполнена ('00010101'), вычитание месяцев вернёт дату до начала отсчёта календаря, что в запросах может привести к неожиданным отборам. Перед расчётом проверяйте заполненность:
Если ЗначениеЗаполнено(ИсходнаяДата) Тогда
НоваяДата = ДобавитьМесяц(ИсходнаяДата, -КоличествоМесяцев);
Иначе
НоваяДата = Неопределено;
КонецЕсли;Проверка корректности результата
После внедрения расчёта проверьте его на граничных случаях. Минимальный набор контрольных точек: 31 марта (переход на февраль), 1 января (переход через год), 29 февраля високосного года, 31 мая (месяц из 30 дней).
Как проверить результат
28 или 29 февраля в зависимости от високосности
31 февраля, 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-х чисел. Никогда не заменяйте её арифметикой дней и проверяйте результат на граничных датах.