Разработка и Конфигурация · 11 мин
Как посчитать количество месяцев между датами в 1С
Как в 1С вычислить количество месяцев между датами: функции РазностьДат, ДобавитьМесяц, запросы РАЗНОСТЬДАТ, примеры кода, подводные камни и проверка результата.
Задача вычислить количество месяцев между двумя датами возникает в 1С постоянно: расчёт трудового стажа, сроков действия договоров, периодов амортизации, длительности подписок и отсрочек платежа. При этом во встроенном языке 1С нет одной готовой функции «МесяцевМежду», поэтому разработчики используют несколько подходов — и каждый даёт разный результат на граничных датах.
Главная сложность в том, что «месяц» — не фиксированная величина. Между 15 января и 14 февраля формально ещё не прошёл полный месяц, а между 31 января и 28 февраля — уже прошёл, хотя разница в днях почти одинаковая. Прежде чем писать код, нужно определиться, что именно считать месяцем: полные календарные месяцы, количество затронутых месяцев или дробное значение.
Ниже разобраны рабочие способы для встроенного языка и языка запросов, примеры кода, типичные ошибки и способы проверить результат на граничных датах.
Что считать месяцем: три разных результата
Прежде чем выбирать инструмент, определите требуемую логику. Одна и та же пара дат — с 10 января по 5 марта — даст разные ответы в зависимости от постановки задачи:
- Полные месяцы — сколько целых месяцев уместилось в интервале. С 10 января по 5 марта полных месяцев один (с 10 января по 10 февраля), остаток отбрасывается. Так считают стаж и сроки в кадровом учёте.
- Затронутые месяцы — сколько календарных месяцев задевает период. Интервал с 10 января по 5 марта затрагивает три месяца: январь, февраль, март. Так считают количество строк в помесячных отчётах.
- Дробное значение — разница в днях, делённая на условную длину месяца (обычно 30 или 30,44). Используется в финансовых расчётах, где точность до дня не нужна.
Уточните требование у постановщика задачи до написания кода. Самая частая причина переделок — разработчик посчитал полные месяцы, а бухгалтер ожидал количество затронутых.
Способ 1. Функция РАЗНОСТЬДАТ в запросе
Самый короткий и надёжный способ — вычислить месяцы на стороне запроса. Функция РАЗНОСТЬДАТ принимает две даты и единицу измерения:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, МЕСЯЦ) КАК Месяцев";
Запрос.УстановитьПараметр("ДатаНачала", '20260115');
Запрос.УстановитьПараметр("ДатаОкончания", '20260610');
Результат = Запрос.Выполнить().Выгрузить();
// Месяцев = 5
РАЗНОСТЬДАТ с единицей МЕСЯЦ возвращает количество полных месяцев: она сравнивает номера месяцев с поправкой на день. Если день конечной даты меньше дня начальной, последний месяц не засчитывается. С 15 января по 10 июня получится 4 месяца, а с 15 января по 15 июня — ровно 5.
Допустимые единицы измерения: СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, МЕСЯЦ, КВАРТАЛ, ГОД. Если дата начала больше даты окончания, результат будет отрицательным — учитывайте это при проверках.
Способ 2. Расчёт во встроенном языке без запроса
Если запрос не нужен, количество полных месяцев вычисляют формулой через год и месяц с поправкой на день:
Функция МесяцевМеждуДатами(ДатаНачала, ДатаОкончания)
Месяцев = (Год(ДатаОкончания) - Год(ДатаНачала)) * 12
+ Месяц(ДатаОкончания) - Месяц(ДатаНачала);
Если День(ДатаОкончания) < День(ДатаНачала) Тогда
Месяцев = Месяцев - 1;
КонецЕсли;
Возврат Месяцев;
КонецФункции
Логика поправки: месяц считается завершённым только когда день конечной даты достиг или превысил день начальной. С 20 марта по 10 мая формула без поправки даст 2, с поправкой — 1, что соответствует одному полному месяцу.
Альтернативный вариант — цикл с функцией ДобавитьМесяц. Он чуть медленнее на больших интервалах, но нагляднее и удобен, когда нужно не только число, но и сами границы месяцев:
Месяцев = 0;
ТекущаяДата = ДатаНачала;
Пока ДобавитьМесяц(ТекущаяДата, 1) <= ДатаОкончания Цикл
ТекущаяДата = ДобавитьМесяц(ТекущаяДата, 1);
Месяцев = Месяцев + 1;
КонецЦикла;
Для количества затронутых календарных месяцев поправка на день не нужна — просто прибавьте единицу к разности номеров месяцев: (Год2 − Год1) × 12 + Месяц2 − Месяц1 + 1.
Месяцев = (Год(Дата2) - Год(Дата1)) * 12 + Месяц(Дата2) - Месяц(Дата1);
Если День(Дата2) < День(Дата1) Тогда
Месяцев = Месяцев - 1;
КонецЕсли;Способ 3. Подсчёт через дни и условную длину месяца
Когда требуется дробное значение — например, 2,5 месяца для финансового коэффициента, — считают разницу в днях и делят на условную длину месяца:
Дней = (НачалоДня(ДатаОкончания) - НачалоДня(ДатаНачала)) / 86400;
Месяцев = Окр(Дней / 30, 2);
Разность двух дат во встроенном языке даёт секунды, поэтому делим на 86400 (60 × 60 × 24). В качестве делителя используют 30, 30,44 (средняя длина месяца в году) или 365/12 — выбор зависит от методики расчёта, принятой в организации.
Этот способ не подходит для кадрового и юридически значимого учёта: «условный месяц» не совпадает с календарным, и на длинных интервалах ошибка накапливается. Используйте его только там, где методика явно предписывает усреднение.
Сравнение способов
Полные месяцы, одна строка кода. Подходит для отчётов и выборок, но только внутри запроса.
Полные месяцы в любом коде. Универсально, но требует аккуратной обработки граничных дат.
Полные месяцы плюс границы периодов. Наглядно, удобно для помесячных начислений.
Дробное значение для финансовых коэффициентов. Не годится для стажа и юридических сроков.
Граничные случаи: конец месяца и переход через год
Функция ДобавитьМесяц корректно обрабатывает переход через год и разную длину месяцев: ДобавитьМесяц('20260131', 1) вернёт 29 февраля високосного года, а не 31-е и не ошибку. Это стандартное поведение платформы — дата прижимается к последнему дню месяца, если исходного числа в нём нет.
Из-за этого возникает тонкий эффект: последовательное добавление месяцев к 31 января даст 29 февраля, затем 29 марта — «потерянные» дни не восстанавливаются. Если для задачи важно сохранять исходный день (например, ежемесячное начисление 31-го числа, а в коротких месяцах — в последний день), храните исходную дату и считайте смещение от неё, а не от предыдущего результата.
При переходе через год формула (Год2 − Год1) × 12 работает без дополнительных условий — именно для этого в ней умножение на 12. Ошибка возникает только если разработчик забыл про год и сравнивает номера месяцев напрямую: декабрь и январь следующего года дадут −11 вместо 1.
Как проверить результат
Проверяйте функцию на заранее известных парах дат, включая граничные. Минимальный набор контрольных примеров:
- Ровный интервал: 01.01 — 01.07 должно дать 6 месяцев.
- Неполный последний месяц: 15.01 — 10.06 даёт 4 полных месяца, хотя разница в номерах месяцев равна 5.
- Переход через год: 15.11 — 15.02 следующего года даёт 3.
- Конец месяца: 31.01 — 28.02 даёт 1 полный месяц (февраль закрыл интервал полностью).
- Один день: 10.03 — 11.03 даёт 0 полных месяцев и 1 затронутый месяц.
Полезно сверить программный результат с ручным подсчётом по календарю на 3–4 реальных примерах из учётных данных. Если разработанная функция используется в регламентных расчётах (стаж, амортизация), зафиксируйте контрольные примеры в комментарии к коду — это упростит проверку после обновлений.
Как проверить результат
Функция возвращает ровно N
N-1 или N+1 — ошибка в поправке на день
Последний месяц не засчитан
Месяц засчитан — поправка на день отсутствует
Разница в 1 месяц считается как 1
Отрицательное число или 11 — не учтён год
Один полный месяц, без ошибки платформы
Ошибка выполнения или 0 месяцев
Где применять: типовые сценарии в конфигурациях
В кадровом учёте количество месяцев стажа считается по полным месяцам с поправкой на день, а остаток дней выводится отдельно (формат «лет/месяцев/дней»). Для этого после подсчёта полных месяцев остаток вычисляют как разницу в днях между конечной датой и датой начала, сдвинутой на найденное число месяцев через ДобавитьМесяц.
В торговом учёте для договоров с помесячной оплатой удобнее цикл с ДобавитьМесяц: он сразу даёт границы расчётных периодов для формирования счетов. Количество итераций и есть число месяцев.
В отчётах на СКД предпочтителен вариант с РАЗНОСТЬДАТ в запросе набора данных — вычисление выполняется на сервере СУБД и не требует обхода выборки в коде. Для помесячной группировки строк используйте функции НАЧАЛОПЕРИОДА(Дата, МЕСЯЦ) и КОНЕЦПЕРИОДА(Дата, МЕСЯЦ).
Как выбрать способ
Часто задаваемые вопросы
Есть ли в 1С готовая функция «месяцев между датами»?
Отдельной функции во встроенном языке нет. В языке запросов есть РАЗНОСТЬДАТ с единицей МЕСЯЦ, а в коде расчёт выполняют формулой через год и месяц либо циклом с ДобавитьМесяц. В типовых конфигурациях также встречаются готовые процедуры в общих модулях работы с датами — проверьте их наличие в своей конфигурации.
Почему РАЗНОСТЬДАТ возвращает на единицу меньше, чем я ожидаю?
Функция считает только полные месяцы. Если день конечной даты меньше дня начальной, последний месяц не завершён и не засчитывается. Например, с 20 января по 10 марта результат равен 1, а не 2. Если нужны затронутые месяцы, добавьте единицу к разности номеров месяцев без учёта дня.
Как получить результат в формате «лет, месяцев, дней»?
Сначала вычислите полные годы с поправкой на месяц и день, затем сдвиньте дату начала на найденные годы через ДобавитьМесяц(Дата, Лет*12) и посчитайте полные месяцы остатка. Оставшиеся дни — разница в днях между конечной датой и датой, сдвинутой на годы и месяцы. Такой пошаговый сдвиг исключает ошибки на коротких месяцах.
Что будет, если дата начала позже даты окончания?
РАЗНОСТЬДАТ вернёт отрицательное значение, формула с поправкой на день — тоже отрицательное число, а цикл с ДобавитьМесяц не выполнится ни разу и вернёт 0. Если перевернутые даты возможны в данных, добавьте явную проверку и либо меняйте даты местами, либо выводите предупреждение.
Как посчитать месяцы между датами в СКД без изменения запроса?
Если даты доступны как поля набора данных, добавьте вычисляемое поле на закладке «Вычисляемые поля» с выражением на языке выражений СКД, где доступны функции Год(), Месяц() и День(). Формула с поправкой на день записывается через конструкцию Выбор. Для сложной логики надёжнее вынести расчёт в запрос набора данных.
Влияет ли время в датах на расчёт месяцев?
Функции Год, Месяц и День отсекают время, поэтому на расчёт полных месяцев время не влияет. Но при сравнении дат операторами < и > время учитывается: 15.03.2026 23:59 больше, чем 15.03.2026 00:00. Перед сравнениями приводите даты к началу дня функцией НачалоДня(), если время несущественно.
Что важно запомнить
Готовой функции «месяцев между датами» во встроенном языке 1С нет: в запросах используйте РАЗНОСТЬДАТ с единицей МЕСЯЦ, в коде — формулу (Год2−Год1)×12 + Месяц2 − Месяц1 с поправкой на день или цикл с ДобавитьМесяц. Заранее определите, что считать месяцем — полные месяцы, затронутые или дробное значение, — и проверяйте функцию на граничных датах: конец месяца, переход через год, неполный последний месяц.