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