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

Разработка и Конфигурация · 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.

bsl
Месяцев = (Год(Дата2) - Год(Дата1)) * 12 + Месяц(Дата2) - Месяц(Дата1);
Если День(Дата2) < День(Дата1) Тогда
    Месяцев = Месяцев - 1;
КонецЕсли;

Способ 3. Подсчёт через дни и условную длину месяца

Когда требуется дробное значение — например, 2,5 месяца для финансового коэффициента, — считают разницу в днях и делят на условную длину месяца:

Дней = (НачалоДня(ДатаОкончания) - НачалоДня(ДатаНачала)) / 86400;

Месяцев = Окр(Дней / 30, 2);

Разность двух дат во встроенном языке даёт секунды, поэтому делим на 86400 (60 × 60 × 24). В качестве делителя используют 30, 30,44 (средняя длина месяца в году) или 365/12 — выбор зависит от методики расчёта, принятой в организации.

Этот способ не подходит для кадрового и юридически значимого учёта: «условный месяц» не совпадает с календарным, и на длинных интервалах ошибка накапливается. Используйте его только там, где методика явно предписывает усреднение.

Сравнение способов

РАЗНОСТЬДАТ в запросе

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

Формула с поправкой на день

Полные месяцы в любом коде. Универсально, но требует аккуратной обработки граничных дат.

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

Полные месяцы плюс границы периодов. Наглядно, удобно для помесячных начислений.

Дни / 30

Дробное значение для финансовых коэффициентов. Не годится для стажа и юридических сроков.

Граничные случаи: конец месяца и переход через год

Функция ДобавитьМесяц корректно обрабатывает переход через год и разную длину месяцев: ДобавитьМесяц('20260131', 1) вернёт 29 февраля високосного года, а не 31-е и не ошибку. Это стандартное поведение платформы — дата прижимается к последнему дню месяца, если исходного числа в нём нет.

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

При переходе через год формула (Год2 − Год1) × 12 работает без дополнительных условий — именно для этого в ней умножение на 12. Ошибка возникает только если разработчик забыл про год и сравнивает номера месяцев напрямую: декабрь и январь следующего года дадут −11 вместо 1.

Типичные ошибки
01
Сравнение только номеров месяцев без учёта года — на переходе через год результат уходит в минус или искажается.
02
Использование РазностьДат с единицей МЕСЯЦ в коде — эта единица поддерживается только в запросной РАЗНОСТЬДАТ, в коде будет ошибка.
03
Отсутствие поправки на день — интервал с 20 января по 10 февраля ошибочно считается полным месяцем.
04
Деление дней на 30 для расчёта стажа — накапливается погрешность, итог не сходится с кадровыми правилами.
05
Накопительное применение ДобавитьМесяц к результату — исходный день месяца «плывёт» на коротких месяцах.

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

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

  • Ровный интервал: 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

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

N-1 или N+1 — ошибка в поправке на день

День окончания меньше дня начала
Норма

Последний месяц не засчитан

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

Месяц засчитан — поправка на день отсутствует

Переход через декабрь–январь
Норма

Разница в 1 месяц считается как 1

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

Отрицательное число или 11 — не учтён год

31 января → конец февраля
Норма

Один полный месяц, без ошибки платформы

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

Ошибка выполнения или 0 месяцев

Где применять: типовые сценарии в конфигурациях

В кадровом учёте количество месяцев стажа считается по полным месяцам с поправкой на день, а остаток дней выводится отдельно (формат «лет/месяцев/дней»). Для этого после подсчёта полных месяцев остаток вычисляют как разницу в днях между конечной датой и датой начала, сдвинутой на найденное число месяцев через ДобавитьМесяц.

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

В отчётах на СКД предпочтителен вариант с РАЗНОСТЬДАТ в запросе набора данных — вычисление выполняется на сервере СУБД и не требует обхода выборки в коде. Для помесячной группировки строк используйте функции НАЧАЛОПЕРИОДА(Дата, МЕСЯЦ) и КОНЕЦПЕРИОДА(Дата, МЕСЯЦ).

Маршрут решения

Как выбрать способ

Нужно число месяцев в отчёте или выборкеИспользуйте РАЗНОСТЬДАТ(Дата1, Дата2, МЕСЯЦ) в тексте запроса
Расчёт в коде модуля без запросаПрименяйте формулу (Год2-Год1)*12 + Месяц2 - Месяц1 с поправкой на день
Нужны границы каждого месяца периодаИспользуйте цикл с ДобавитьМесяц и считайте итерации
Требуется дробное значение для коэффициентаДелите разницу в днях на 30 или 30,44 по принятой методике

Часто задаваемые вопросы

Есть ли в 1С готовая функция «месяцев между датами»?

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

Почему РАЗНОСТЬДАТ возвращает на единицу меньше, чем я ожидаю?

Функция считает только полные месяцы. Если день конечной даты меньше дня начальной, последний месяц не завершён и не засчитывается. Например, с 20 января по 10 марта результат равен 1, а не 2. Если нужны затронутые месяцы, добавьте единицу к разности номеров месяцев без учёта дня.

Как получить результат в формате «лет, месяцев, дней»?

Сначала вычислите полные годы с поправкой на месяц и день, затем сдвиньте дату начала на найденные годы через ДобавитьМесяц(Дата, Лет*12) и посчитайте полные месяцы остатка. Оставшиеся дни — разница в днях между конечной датой и датой, сдвинутой на годы и месяцы. Такой пошаговый сдвиг исключает ошибки на коротких месяцах.

Что будет, если дата начала позже даты окончания?

РАЗНОСТЬДАТ вернёт отрицательное значение, формула с поправкой на день — тоже отрицательное число, а цикл с ДобавитьМесяц не выполнится ни разу и вернёт 0. Если перевернутые даты возможны в данных, добавьте явную проверку и либо меняйте даты местами, либо выводите предупреждение.

Как посчитать месяцы между датами в СКД без изменения запроса?

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

Влияет ли время в датах на расчёт месяцев?

Функции Год, Месяц и День отсекают время, поэтому на расчёт полных месяцев время не влияет. Но при сравнении дат операторами < и > время учитывается: 15.03.2026 23:59 больше, чем 15.03.2026 00:00. Перед сравнениями приводите даты к началу дня функцией НачалоДня(), если время несущественно.

Итог

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

Готовой функции «месяцев между датами» во встроенном языке 1С нет: в запросах используйте РАЗНОСТЬДАТ с единицей МЕСЯЦ, в коде — формулу (Год2−Год1)×12 + Месяц2 − Месяц1 с поправкой на день или цикл с ДобавитьМесяц. Заранее определите, что считать месяцем — полные месяцы, затронутые или дробное значение, — и проверяйте функцию на граничных датах: конец месяца, переход через год, неполный последний месяц.