Разработка и Конфигурация · 10 мин
Как посчитать количество месяцев между датами в 1С
Способы посчитать количество месяцев между датами в 1С: функции РазностьДат, ДобавитьМесяц, запросы и типовые ошибки при расчёте периодов.
Посчитать количество месяцев между двумя датами — типовая задача при разработке в 1С: она встречается в расчёте стажа, сроков действия договоров, амортизации, отсрочек платежа и периодов обслуживания. При этом встроенного оператора вычитания дат, который сразу вернул бы месяцы, в языке 1С нет — вычитание дат даёт только разность в секундах.
Поэтому используются несколько подходов: функция РазностьДат() в запросах, комбинация ДобавитьМесяц() с циклом в коде, ручной расчёт через год и месяц даты, а также типовые механизмы БСП (Библиотека стандартных подсистем). У каждого способа есть свои ограничения: например, «месяц» в запросе — это календарное понятие, а не 30 дней, и результаты при граничных датах могут отличаться от ожиданий.
Ниже разобраны рабочие варианты с примерами кода, условиями выбора и проверкой результата. Примеры применимы к платформе 8.3 и типовым конфигурациям.
Как 1С хранит даты и почему нет прямого вычитания месяцев
Тип «Дата» в 1С хранится с точностью до секунды. Операция Дата2 - Дата1 возвращает число — разность в секундах. Чтобы получить дни, результат делят на 86400, но с месяцами такой приём не работает: месяцы имеют разную длину (28–31 день), поэтому «средний месяц» из секунд даст погрешность.
Из-за этого платформа предлагает отдельные инструменты: функции Месяц(), Год(), ДобавитьМесяц() в языке и РазностьДат() в языке запросов. Каждая решает задачу по-своему, и выбор зависит от того, нужен ли календарный результат или количество полностью прошедших месяцев.
Способ 1: РазностьДат в запросе
Самый короткий путь — запрос с функцией РАЗНОСТЬДАТ(ДатаНачала, ДатаОкончания, МЕСЯЦ). Третий параметр задаёт единицу измерения: можно получить ДЕНЬ, МЕСЯЦ, КВАРТАЛ, ГОД, СЕКУНДА и другие.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, МЕСЯЦ) КАК КоличествоМесяцев";
Запрос.УстановитьПараметр("ДатаНачала", Дата(2026, 1, 15));
Запрос.УстановитьПараметр("ДатаОкончания", Дата(2026, 3, 10));
Результат = Запрос.Выполнить().Выгрузить();
КоличествоМесяцев = Результат[0].КоличествоМесяцев;
Важная особенность: РазностьДат считает количество границ месяцев между датами, а не полных прожитых месяцев. Например, между 31 января и 1 февраля разность в месяцах равна 1, хотя прошли сутки. А между 15 января и 14 февраля — тоже 1. Поэтому для расчёта стажа или сроков с точностью до дня этот способ нужно дополнять проверкой дня месяца.
Способ 2: расчёт через Год и Месяц в коде
Если запрос не нужен, количество календарных месяцев между датами легко получить формулой через годы и месяцы:
КоличествоМесяцев = (Год(ДатаОкончания) - Год(ДатаНачала)) * 12
+ (Месяц(ДатаОкончания) - Месяц(ДатаНачала));
Этот вариант даёт тот же результат, что и РазностьДат(..., МЕСЯЦ): разность номеров месяцев без учёта дней. Он удобен в модуле объекта или формы, где даты уже есть в реквизитах и формировать запрос ради одного числа избыточно.
Чтобы получить количество полных месяцев, добавьте корректировку по дню:
КоличествоМесяцев = (Год(ДатаОкончания) - Год(ДатаНачала)) * 12
+ (Месяц(ДатаОкончания) - Месяц(ДатаНачала));
Если День(ДатаОкончания) < День(ДатаНачала) Тогда
КоличествоМесяцев = КоличествоМесяцев - 1;
КонецЕсли;
Такой расчёт соответствует бытовому пониманию «полных месяцев»: с 10 января по 9 февраля — 0 полных месяцев, с 10 января по 10 февраля — 1.
Способ 3: цикл с ДобавитьМесяц
Функция ДобавитьМесяц(Дата, ЧислоМесяцев) сдвигает дату на заданное число месяцев, корректно обрабатывая конец месяца: ДобавитьМесяц(Дата(2026,1,31), 1) вернёт 29.02.2026 (в високосный год), а не несуществующее 31 февраля. На этом строится итеративный подсчёт:
КоличествоМесяцев = 0;
ТекДата = ДатаНачала;
Пока ДобавитьМесяц(ТекДата, 1) <= ДатаОкончания Цикл
ТекДата = ДобавитьМесяц(ТекДата, 1);
КоличествоМесяцев = КоличествоМесяцев + 1;
КонецЦикла;
Способ нагляден и безопасен для коротких периодов (месяцы, годы), но для интервалов в десятки лет цикл выполнит сотни итераций — в этом случае быстрее формула из предыдущего раздела. Цикл оправдан, когда на каждом шаге нужно не только посчитать, но и что-то сделать: сформировать строку таблицы по месяцам, рассчитать амортизацию за месяц и т.п.
ДобавитьМесяц корректно обрабатывает 29–31 числа: при сдвиге с конца длинного месяца дата «приземляется» на последний день короткого. Поэтому цепочка сдвигов с 31 января пойдёт через 29/28 февраля, а дальше день месяца уже не восстановится до 31 — учитывайте это в графиках платежей.
Количество месяцев в периоде документа или справочника
Частая прикладная задача — посчитать, сколько месяцев действует договор, или вывести месяцы периода в табличную часть. Здесь удобно сочетать запрос и обход:
ТекМесяц = НачалоМесяца(ДатаНачала);
Пока ТекМесяц <= ДатаОкончания Цикл
НоваяСтрока = ТаблицаМесяцев.Добавить();
НоваяСтрока.Месяц = ТекМесяц;
ТекМесяц = ДобавитьМесяц(ТекМесяц, 1);
КонецЦикла;
Количество строк в итоговой таблице и будет количеством месяцев, которых касается период (включая неполные первый и последний). Этот подход используется в графиках начислений, плановых платежах и отчётах по периодам.
В типовых конфигурациях на БСП есть готовые процедуры работы с датами (модуль ОбщегоНазначения и подсистемы дат), а в ЗУП — механизмы расчёта стажа, где подсчёт месяцев и дней уже реализован. Перед написанием своего алгоритма проверьте, нет ли типовой функции: это снизит риск расхождений с отчётностью.
- 1Определите, что считать: календарные месяцы (смена номера) или полные месяцы с учётом дней
- 2Для запроса используйте РазностьДат(Дата1, Дата2, МЕСЯЦ)
- 3Для кода без запроса примените формулу (Год2-Год1)*12 + (Месяц2-Месяц1)
- 4Если нужны полные месяцы — добавьте корректировку по дню месяца
- 5Проверьте результат на граничных датах: 31.01–01.02, 15.01–14.02, високосный февраль
Проверка результата и типичные ошибки
Главный источник ошибок — разные ожидания от слова «месяц». Бухгалтер под «3 месяца отсрочки» понимает полные месяцы, а РазностьДат вернёт 3 даже для периода с 28 февраля по 1 марта при определённых границах. Всегда согласовывайте методику расчёта с постановкой задачи и фиксируйте её в комментарии к коду.
Вторая группа ошибок — пустые и незаполненные даты. Если реквизит даты не заполнен, функции Год(), Месяц() вернут значения от даты 01.01.0001, и результат будет огромным числом. Перед расчётом проверяйте даты на заполненность и на корректный порядок (начало раньше окончания).
Для контроля используйте простой набор тестовых пар дат с известным ответом: ровно год (12 месяцев), ровно месяц (1), граничные случаи вроде 31.01–28.02 и 15.01–14.02. Если алгоритм проходит эти точки, он надёжен и на произвольных данных.
Как проверить результат
Полных месяцев: 1; календарных: 1
0 или 2 — ошибка в корректировке по дню
РазностьДат даёт 1, полных месяцев — 0
Ожидание «0» от РазностьДат без учёта её логики
Расчёт не выполняется, выводится предупреждение
Огромное число месяцев от даты 01.01.0001
Что выбрать в разных ситуациях
Единственного «правильного» способа нет — выбор зависит от контекста. В отчётах и СКД логичнее РазностьДат на уровне запроса: это быстрее и не требует обхода выборки. В модуле документа с парой дат достаточно формулы через Год() и Месяц(). Для построения помесячных графиков незаменим цикл с ДобавитьМесяц().
Сравнение способов
Подходит для отчётов и СКД; быстро, но считает только календарные месяцы без учёта дней
Удобна в коде без запроса; легко дополняется корректировкой на полные месяцы
Нужен для помесячного обхода периода; на длинных интервалах медленнее формулы
Предпочтительны в типовых конфигурациях: согласованы с отчётностью, но требуют изучения API
При сомнениях ориентируйтесь на постановку задачи: если в ней сказано «срок действия в месяцах» — считайте полные месяцы с корректировкой по дню; если «количество месяцев периода» для отчёта — подойдёт календарная разность.
Что важно запомнить
Прямого вычитания месяцев в 1С нет: используйте РазностьДат(..., МЕСЯЦ) в запросах, формулу (Год2-Год1)*12+(Месяц2-Месяц1) в коде и ДобавитьМесяц для помесячного обхода. Различайте календарные и полные месяцы и проверяйте даты на заполненность.
Частые вопросы
Как посчитать количество месяцев между датами в запросе 1С?
Используйте функцию РАЗНОСТЬДАТ(ДатаНачала, ДатаОкончания, МЕСЯЦ). Она вернёт целое число — количество границ месяцев между датами. Даты можно передать параметрами или взять из полей таблицы.
Как получить только полные месяцы между датами?
Посчитайте разность через (Год2-Год1)*12 + (Месяц2-Месяц1), затем сравните день конечной и начальной даты: если день окончания меньше дня начала, вычтите 1. Так с 10.01 по 09.02 получится 0 полных месяцев, а с 10.01 по 10.02 — один.
Что вернёт ДобавитьМесяц для даты 31 января?
Функция вернёт последний день февраля (28 или 29 число в високосный год), так как 31 февраля не существует. Это корректное поведение платформы, но при цепочке сдвигов исходный день месяца не восстановится.
Можно ли посчитать месяцы через разность дат в секундах?
Технически можно поделить секунды на усреднённую длину месяца, но результат будет дробным и с погрешностью, которая растёт на длинных периодах. Для прикладных расчётов такой способ не рекомендуется — используйте календарные функции.
Почему расчёт даёт огромное число месяцев?
Скорее всего, одна из дат не заполнена: пустая дата равна 01.01.0001, и разность с реальной датой составит тысячи месяцев. Добавьте проверку ЗначениеЗаполнено(Дата) перед расчётом и контроль порядка дат.
Есть ли готовые функции расчёта месяцев в типовых конфигурациях?
Да. В конфигурациях на БСП есть общие модули работы с датами, а в 1С:ЗУП реализован расчёт стажа с разложением на годы, месяцы и дни. Использование типовых механизмов снижает риск расхождений с регламентированной отчётностью.