Разработка и Конфигурация · 9 мин
Как узнать количество месяцев в периоде в 1С
Как посчитать количество месяцев между датами в 1С: функции встроенного языка, запрос РАЗНОСТЬДАТ, готовые примеры кода и разбор типичных ошибок расчёта.
Задача посчитать количество месяцев между двумя датами возникает в 1С постоянно: при расчёте стажа сотрудника, срока действия договора, амортизации, длительности подписки или отпускного периода. Проблема в том, что во встроенном языке 1С нет одной готовой функции вида «КоличествоМесяцев()», и разработчики решают задачу разными способами — не всегда корректными.
Главная ловушка — неоднозначность самого понятия «месяц в периоде». Период с 15 января по 14 февраля — это один месяц или два? А с 31 января по 28 февраля? В зависимости от постановки задачи (полные календарные месяцы, затронутые месяцы, округление) правильный ответ будет разным, и формулу нужно подбирать под конкретный смысл расчёта.
Ниже разобраны рабочие способы: вычисление на встроенном языке через функции работы с датами, оператор РАЗНОСТЬДАТ в запросах, типовые функции общих модулей в конфигурациях 1С:БСП, а также проверка результата и типичные ошибки, из-за которых расчёт «плывёт» на месяц.
Что именно считать: три смысла «количества месяцев»
Прежде чем писать код, определите, какой результат нужен бизнес-логике. На практике встречаются три разные постановки задачи, и каждая требует своей формулы.
Полные месяцы между датами. Считаются только целиком уместившиеся месяцы: с 10.01 по 09.02 — один полный месяц, с 10.01 по 08.02 — ноль. Так считают стаж, сроки договоров, возраст.
Затронутые календарные месяцы. Считаются все месяцы, на которые пришёлся хотя бы один день периода: с 30.01 по 02.02 — два месяца (январь и февраль). Такой подход типичен для отчётов по помесячной разбивке и начислений «за каждый месяц периода».
Округлённая длительность. Разница в днях делится на среднюю длину месяца и округляется. Способ грубый и подходит только для прикидочных оценок, в учётных расчётах его лучше не применять.
Как выбрать способ расчёта
Расчёт в запросе: оператор РАЗНОСТЬДАТ
Самый простой и надёжный способ узнать количество месяцев в периоде — использовать язык запросов 1С. Оператор РАЗНОСТЬДАТ принимает два выражения типа «Дата» и единицу измерения, в том числе МЕСЯЦ:
ВЫБРАТЬ
РАЗНОСТЬДАТ(&НачалоПериода, &КонецПериода, МЕСЯЦ) КАК КоличествоМесяцев
Оператор возвращает количество полных единиц между датами: с 15.01 по 14.02 результат будет 0, с 15.01 по 15.02 — 1. Это соответствует логике «полных месяцев» и хорошо подходит для сроков и стажа. Если нужны затронутые календарные месяцы, добавьте к результату единицу и убедитесь, что границы периода попадают в разные месяцы именно так, как ожидает отчёт.
Важная деталь: РАЗНОСТЬДАТ работает с полными датами, включая время. Если конец периода задан как 28.02.2026 00:00:00, а не конец дня 23:59:59, расчёт может отличаться от ожиданий пользователя. Для границ периодов используйте функцию КонецПериода() или приводите дату к концу дня.
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ РАЗНОСТЬДАТ(&Начало, &Конец, МЕСЯЦ) КАК Месяцев";
Запрос.УстановитьПараметр("Начало", ДатаНачала);
Запрос.УстановитьПараметр("Конец", ДатаОкончания);
Месяцев = Запрос.Выполнить().Выгрузить()[0].Месяцев;Расчёт на встроенном языке без запроса
Если запрос не нужен (например, расчёт идёт в цикле или в форме), количество месяцев вычисляется арифметически через функции Год() и Месяц(). Базовая формула для затронутых месяцев:
МесяцевЗатронуто = (Год(ДатаКонца) - Год(ДатаНачала)) * 12
+ Месяц(ДатаКонца) - Месяц(ДатаНачала) + 1;
Для полных месяцев формула дополняется поправкой на день: если день окончания меньше дня начала, последний месяц неполный и его нужно исключить:
МесяцевПолных = (Год(ДатаКонца) - Год(ДатаНачала)) * 12
+ Месяц(ДатаКонца) - Месяц(ДатаНачала);
Если День(ДатаКонца) < День(ДатаНачала) Тогда
МесяцевПолных = МесяцевПолных - 1;
КонецЕсли;
Такой код работает быстро, не требует обращения к СУБД и легко тестируется. Обратите внимание: функции Год(), Месяц() и День() возвращают числа, поэтому никаких преобразований типов не требуется.
Проверка результата через ДобавитьМесяц()
Функция ДобавитьМесяц(Дата, ЧислоМесяцев) сдвигает дату на заданное число месяцев с корректной обработкой концов месяцев: ДобавитьМесяц к 31.01 даст последний день февраля. Её удобно использовать для проверки расчёта полных месяцев.
Логика проверки: если ДобавитьМесяц(ДатаНачала, МесяцевПолных) не превышает дату окончания, а ДобавитьМесяц(ДатаНачала, МесяцевПолных + 1) уже превышает — расчёт верен. Это простой способ написать юнит-тест или отладочную проверку для своей функции.
Также ДобавитьМесяц применяют для обратной задачи: по известному количеству месяцев получить дату окончания периода. Например, договор на 6 месяцев от 15.03 заканчивается ДобавитьМесяц(Дата(2026,3,15), 6) — 15.09, а день окончания действия обычно берут как предыдущий день.
Готовые функции в типовых конфигурациях
В конфигурациях на базе Библиотеки стандартных подсистем (1С:Бухгалтерия, 1С:ЗУП, 1С:Управление торговлей и другие) уже есть общие модули для работы с датами. Прежде чем писать свою функцию, проверьте модули вида «ОбщегоНазначения», «КалендарныеГрафики», «ЗарплатаКадрыОбщиеНаборыДанных» — во многих из них есть процедуры расчёта разности дат в месяцах и днях.
Использование типовых функций предпочтительнее: они уже учитывают прикладные соглашения конфигурации (например, как считать стаж для кадрового учёта) и не создают дублирующей логики, которую придётся поддерживать при обновлениях.
Если функция расчёта месяцев нужна в нескольких местах, вынесите её в общий серверный модуль с признаком «Вызов сервера» и покройте парой проверок на граничных датах: 31.01–28.02, 01.01–31.12, период внутри одного месяца. Это займёт десять минут и снимет большинство будущих ошибок.
Типичные ошибки и граничные случаи
Больше всего проблем доставляют границы периодов. Первая частая ошибка — перепутанный смысл результата: отчёт показывает «полные месяцы», а пользователь ожидает «затронутые», и суммы начислений не сходятся. Всегда фиксируйте в комментарии к функции, какой именно смысл она возвращает.
Вторая ошибка — игнорирование времени в датах. Дата документа почти всегда содержит время, и сравнение День(ДатаКонца) < День(ДатаНачала) может работать неожиданно, если границы периода заданы с разным временем. Приводите даты к началу дня через НачалоДня() перед сравнениями.
Третья ошибка — периоды внутри одного месяца и нулевая длительность. Период с 05.03 по 20.03 даёт 0 полных месяцев, и если дальше по коду идёт деление на количество месяцев (например, среднемесячное значение), программа упадёт с ошибкой деления на ноль. Добавляйте защитную проверку.
Как проверить результат
Ровно 1 полный месяц
0 или 2 — ошибка в поправке на день
По ДобавитьМесяц — 1 месяц; уточните требуемый смысл
Формула даёт 0 без объяснения
0 полных месяцев, 1 затронутый
Отрицательное число или ошибка
3 полных месяца
Отрицательное значение — не учтён перенос года
FAQ
Как посчитать количество месяцев между датами в запросе 1С?
Используйте оператор РАЗНОСТЬДАТ(ДатаНачала; ДатаОкончания; МЕСЯЦ). Он вернёт число полных месяцев. Для затронутых календарных месяцев добавьте к результату единицу и проверьте граничные даты.
Чем РАЗНОСТЬДАТ с МЕСЯЦ отличается от РАЗНОСТЬДАТ с ДЕНЬ, делённой на 30?
РАЗНОСТЬДАТ с единицей МЕСЯЦ считает именно календарные месяцы с учётом их реальной длины. Деление дней на 30 даёт приближение, которое ошибается на длинных периодах из-за месяцев по 28–31 день и високосных лет.
Как получить дату окончания, если известно количество месяцев?
Примените функцию ДобавитьМесяц(ДатаНачала; КоличествоМесяцев). Она корректно обрабатывает концы месяцев: сдвиг 31 января на один месяц даст последний день февраля, а не несуществующую дату.
Почему расчёт даёт на месяц меньше, чем ожидает пользователь?
Чаще всего причина в разном понимании результата: формула считает полные месяцы, а пользователь ожидает затронутые. Проверьте также, не задан ли конец периода с нулевым временем вместо конца дня.
Как избежать ошибки деления на ноль при расчёте среднемесячных значений?
Перед делением проверяйте, что количество месяцев больше нуля. Для коротких периодов внутри одного месяца либо подставляйте минимальное значение 1, либо обрабатывайте такой случай отдельной веткой алгоритма.
Что важно запомнить
Сначала определите смысл расчёта — полные или затронутые месяцы. В запросе используйте РАЗНОСТЬДАТ с единицей МЕСЯЦ, в коде — формулу через Год() и Месяц() с поправкой на день. Проверяйте результат на граничных датах через ДобавитьМесяц и защищайтесь от нулевого количества месяцев. В типовых конфигурациях ищите готовые функции общих модулей.