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