Расчет количества месяцев между двумя датами в 1С:Предприятие — задача, с которой регулярно сталкиваются бухгалтеры, кадровики и разработчики. Казалось бы, что может быть проще: взять разницу в днях и разделить на 30? Но такой подход даст погрешность, которая критична для начисления зарплаты, амортизации или финансовой отчетности. В этой статье разберем 5 точных методов — от стандартных функций платформы до авторских алгоритмов на встроенном языке.
Особенность работы с периодами в 1С заключается в учете календарных месяцев, а не просто 30-дневных интервалов. Например, между 01.01.2026 и 31.01.2026 ровно 1 месяц, хотя разница в днях — 30. А между 15.01.2026 и 15.02.2026 тоже 1 месяц, хотя дней прошло 31. Стандартные математические операции здесь не работают — нужны специализированные инструменты.
Метод 1: Встроенная функция МесяцевМежду()
Самый простой способ — использовать функцию МесяцевМежду(), которая появилась в платформе 1С:Предприятие 8.3.10. Она автоматически учитывает календарные месяцы и корректно обрабатывает граничные случаи, например, когда начальная дата — конец месяца.
Синтаксис функции:
КоличествоМесяцев = МесяцевМежду(ДатаНачала, ДатаОкончания);
Примеры работы:
- 📅
МесяцевМежду(Дата(2026,1,31), Дата(2026,2,28))→ вернет 1 (несмотря на разницу в 28 дней) - 📅
МесяцевМежду(Дата(2026,1,15), Дата(2026,3,15))→ вернет 2 - 📅
МесяцевМежду(Дата(2026,2,29), Дата(2026,3,31))→ вернет 1 (учитывает високосный год)
Функция имеет необязательный третий параметр Точность, который определяет округление результата:
- 🔢
Точность.Месяц— округление до целых месяцев (значение по умолчанию) - 🔢
Точность.День— результат в месяцах с дробной частью (например, 1.5 месяца)
Если вам нужно получить количество полных месяцев (без округления в большую сторону), используйте параметр Точность.Месяц и функцию Цел():
ПолныхМесяцев = Цел(МесяцевМежду(Дата1, Дата2, Точность.Месяц));Метод 2: Использование функции РазностьДат()
Для версий 1С ниже 8.3.10 или когда требуется более гибкий контроль над расчетами, подойдет комбинация функций РазностьДат() и ручной обработки. Этот метод требует дополнительной логики, но работает во всех конфигурациях.
Алгоритм:
- Получите разницу в днях между датами.
- Преобразуйте дни в месяцы с учетом количества дней в каждом месяце.
- Скорректируйте результат для граничных дат (например, 31 января → 28 февраля).
Пример кода:
Процедура РассчитатьМесяцы(ДатаНачала, ДатаОкончания)
РазницаДней = РазностьДат(ДатаОкончания, ДатаНачала, День);
ТекущаяДата = ДатаНачала;
КоличествоМесяцев = 0;
Пока ТекущаяДата < ДатаОкончания Цикл
СледующийМесяц = НачалоМесяца(ТекущаяДата) + Месяц;
Если СледующийМесяц > ДатаОкончания Тогда
Прервать;
КонецЕсли;
КоличествоМесяцев = КоличествоМесяцев + 1;
ТекущаяДата = СледующийМесяц;
КонецЦикла;
Возврат КоличествоМесяцев;
КонецПроцедуры
Этот метод точнее простого деления дней на 30, но требует учета високосных годов и разной длины месяцев. Например, при расчете между 31.01.2026 и 28.02.2026 результат будет 0 месяцев, хотя фактически прошел 1 месяц. Для корректной работы добавьте проверку:
Если День(ДатаНачала) > День(ДатаОкончания) И КонецМесяца(ДатаОкончания) = ДатаОкончания Тогда
КоличествоМесяцев = КоличествоМесяцев + 1;
КонецЕсли;
Метод 3: Расчет через начало и конец месяцев
Еще один надежный способ — сравнивать начала месяцев. Этот подход гарантированно учитывает календарные месяцы, но может давать неожиданные результаты для дат внутри одного месяца (например, 01.01.2026 и 15.01.2026 вернут 0).
Алгоритм:
- Приведите обе даты к началу месяца с помощью
НачалоМесяца(). - Посчитайте разницу в месяцах между полученными датами.
- Скорректируйте результат, если день окончания меньше дня начала.
Пример реализации:
Функция МесяцевВПериоде(ДатаНачала, ДатаОкончания)
НачалоПериода = НачалоМесяца(ДатаНачала);
КонецПериода = НачалоМесяца(ДатаОкончания);
Месяцев = (Год(КонецПериода) - Год(НачалоПериода)) * 12 + (Месяц(КонецПериода) - Месяц(НачалоПериода));
Если День(ДатаНачала) > День(ДатаОкончания) Тогда
Месяцев = Месяцев - 1;
КонецЕсли;
Возврат Месяцев;
КонецФункции
Особенности метода:
- ✅ Точно учитывает календарные месяцы.
- ⚠️ Требует дополнительной проверки для дат внутри одного месяца (см. корректировку с
День()). - 🔄 Работает во всех версиях 1С:Предприятие 8.
Почему нельзя просто разделить дни на 30?
Если разделить разницу в днях на 30, для периода с 31.01.2026 по 28.02.2026 получится ~0.93 месяца, хотя фактически прошел 1 полный месяц. А для периода 01.01.2026–31.01.2026 результат будет 1 месяц, что верно. Такой подход дает погрешность до 10% в зависимости от выбранных дат.
Метод 4: Использование объекта Период
В некоторых конфигурациях (например, 1С:Бухгалтерия или 1С:Зарплата и Управление Персоналом) удобно работать с объектом Период, который предоставляет методы для анализа временных интервалов.
Пример использования:
ПериодРаботы = Новый Период(ДатаНачала, ДатаОкончания);
КоличествоМесяцев = ПериодРаботы.КоличествоМесяцев();
Преимущества метода:
- 📊 Встроенная поддержка в типовых конфигурациях.
- 🔧 Учитывает специфику расчетов (например, для начисления зарплаты или амортизации).
- ⚡ Быстрее самописных алгоритмов за счет оптимизации платформы.
Ограничения:
- ❌ Доступен не во всех конфигурациях (например, в 1С:Управление Торговлей может отсутствовать).
- ❌ Логика расчета может отличаться в разных версиях конфигураций.
Убедитесь, что объект Период доступен в вашей конфигурации|Проверьте документацию — метод КоличествоМесяцев() может иметь особенности|Сравните результаты с другими методами для критичных расчетов|Учтите, что в некоторых конфигурациях периоды считаются включительно/исключительно-->
Метод 5: Программный расчет с учетом високосных годов
Для максимальной точности (например, в финансовых расчетах) можно реализовать полноценный алгоритм, учитывающий:
- 📅 Количество дней в каждом месяце.
- 🔄 Високосные годы.
- 📆 Начало и конец месяцев.
Пример кода:
Функция ТочныеМесяцыМежду(ДатаНачала, ДатаОкончания)
Если ДатаНачала > ДатаОкончания Тогда
Возврат 0;
КонецЕсли;
Месяцев = 0;
ТекущаяДата = НачалоМесяца(ДатаНачала);
Пока ТекущаяДата <= ДатаОкончания Цикл
СледующийМесяц = ТекущаяДата + Месяц;
Если СледующийМесяц > ДатаОкончания Тогда
Прервать;
КонецЕсли;
// Проверяем, что текущий месяц полностью входит в период
КонецТекущегоМесяца = КонецМесяца(ТекущаяДата);
Если КонецТекущегоМесяца <= ДатаОкончания Тогда
Месяцев = Месяцев + 1;
Иначе
// Частичный месяц
Если ДатаОкончания >= ТекущаяДата Тогда
Месяцев = Месяцев + (День(ДатаОкончания) / ДнейВМесяце(ТекущаяДата));
КонецЕсли;
Прервать;
КонецЕсли;
ТекущаяДата = СледующийМесяц;
КонецЦикла;
Возврат Месяцев;
КонецФункции
Функция ДнейВМесяце(Дата)
Месяц = Месяц(Дата);
Год = Год(Дата);
Если Месяц = 2 Тогда
Если (Год % 4 = 0 И Год % 100 <> 0) Или (Год % 400 = 0) Тогда
Возврат 29; // Високосный год
Иначе
Возврат 28;
КонецЕсли;
ИначеЕсли Месяц В [4,6,9,11] Тогда
Возврат 30;
Иначе
Возврат 31;
КонецЕсли;
КонецФункции
Этот алгоритм:
- ✔️ Учитывает частичные месяцы (например, с
15.01.2026по10.02.2026вернет ~1.5 месяца). - ✔️ Корректно обрабатывает високосные годы.
- ✔️ Подходит для финансовых расчетов с дробной точностью.
Для бухгалтерских расчетов (амортизация, резервы) используйте методы с дробной точностью (например, 1.5 месяца вместо округления до 2). Это соответствует требованиям ПБУ и НК РФ.
Сравнение методов: какой выбрать?
Выбор метода зависит от задачи, версии 1С и требуемой точности. Ниже таблица сравнения:
| Метод | Точность | Сложность реализации | Поддержка старых версий | Применимость |
|---|---|---|---|---|
МесяцевМежду() |
⭐⭐⭐⭐⭐ | ⭐ | Только 8.3.10+ | Универсальный |
РазностьДат() + ручная обработка |
⭐⭐⭐⭐ | ⭐⭐⭐ | Все версии | Простые расчеты |
| Сравнение начал месяцев | ⭐⭐⭐ | ⭐⭐ | Все версии | Отчетность |
Объект Период |
⭐⭐⭐⭐ | ⭐ | Зависит от конфигурации | Типовые конфигурации |
| Полный программный расчет | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | Все версии | Финансовые расчеты |
Рекомендации по выбору:
- 🔹 Для бухгалтерских отчетов (например, расчет среднесписочной численности) подойдет
МесяцевМежду()или объектПериод. - 🔹 Для зарплатных расчетов (например, компенсация за неиспользованный отпуск) используйте метод с дробной точностью.
- 🔹 В устаревших конфигурациях (до 8.3.10) реализуйте алгоритм через
РазностьДат().
Если вам нужно посчитать количество месяцев между датами включительно (например, для расчета стажа), добавьте 1 к результату:
МесяцевВключительно = МесяцевМежду(ДатаНачала, ДатаОкончания) + 1;Типичные ошибки и как их избежать
Даже опытные разработчики допускают ошибки при расчете месяцев в 1С. Рассмотрим самые распространенные:
⚠️ Внимание: Если в расчете участвуют даты с 31 числом (например, 31.01.2026–28.02.2026), большинство методов вернут 0 месяцев вместо 1. Всегда проверяйте граничные случаи!
Ошибка 1: Игнорирование високосных лет
Если в периоде попадает 29 февраля, простые алгоритмы могут дать сбой. Например, разница между 28.02.2026 и 28.02.2026 — 1 год (12 месяцев), но если 2026 год високосный, а даты — 29.02.2026 и 28.02.2026, разница составит 11 месяцев и 28 дней.
Ошибка 2: Округление в большую сторону
Функция МесяцевМежду() с параметром Точность.Месяц округляет результат до целого числа. Например, для периода 15.01.2026–15.02.2026 она вернет 1, а для 15.01.2026–14.02.2026 — 0. Если вам нужны полные месяцы, используйте:
ПолныхМесяцев = Цел(МесяцевМежду(Дата1, Дата2, Точность.День));
Ошибка 3: Неучет временных зон
Если даты хранятся с учетом времени (например, 20260131235959), приведение к дате без времени может дать неверный результат. Всегда используйте:
ДатаБезВремени = НачалоДня(ДатаСВременем);
⚠️ Внимание: В конфигурациях с поддержкой международных стандартов (например, 1С:ERP) формат дат может отличаться. Перед расчетами приведите даты к локальному формату с помощью Формат(Дата, "ДЛФ=DT").
FAQ: Ответы на частые вопросы
Как посчитать количество месяцев между датами в отчете 1С?
В отчетах используйте выражение с функцией МесяцевМежду(). Например, для поля "Стаж" в отчете по сотрудникам:
Вычислить("МесяцевМежду(ДатаПриема, ТекущаяДата())")
Если функция недоступна, создайте вычисляемое поле с формулой:
(Год(ТекущаяДата()) - Год(ДатаПриема)) * 12 + (Месяц(ТекущаяДата()) - Месяц(ДатаПриема))
Почему МесяцевМежду() возвращает нецелое число?
Функция с параметром Точность.День возвращает дробное значение (например, 1.5 месяца). Чтобы получить целые месяцы:
- Используйте
Точность.Месяц(округление по правилам математики). - Примените
Цел()для отбрасывания дробной части. - Используйте
Окр()для округления до ближайшего целого.
Пример:
ЦелыхМесяцев = Цел(МесяцевМежду(Дата1, Дата2, Точность.День));
Как посчитать месяцы в периоде с учетом рабочих дней?
Для расчета рабочих месяцев (например, для начисления премии за отработанное время):
- Посчитайте общее количество месяцев (любым методом из статьи).
- Вычтите месяцы, в которых сотрудник был в отпуске или на больничном.
Пример кода:
РабочихМесяцев = МесяцевМежду(ДатаНачала, ДатаОкончания);
Для Каждого Отпуск Из ОтпускаСотрудника Цикл
Если Отпуск.ДатаНачала >= ДатаНачала И Отпуск.ДатаОкончания <= ДатаОкончания Тогда
РабочихМесяцев = РабочихМесяцев - МесяцевМежду(Отпуск.ДатаНачала, Отпуск.ДатаОкончания);
КонецЕсли;
КонецЦикла;
Можно ли использовать эти методы для расчета амортизации?
Да, но с оговорками:
- Для линейного метода амортизации подойдет любой метод с целыми месяцами.
- Для нелинейных методов (уменьшаемого остатка) используйте дробную точность.
- Учтите, что согласно ПБУ 6/01, амортизация начисляется с 1-го числа месяца, следующего за месяцем ввода объекта в эксплуатацию.
Пример для амортизации:
ДатаНачалаАмортизации = НачалоМесяца(ДатаВвода) + Месяц;
КоличествоМесяцев = МесяцевМежду(ДатаНачалаАмортизации, ТекущаяДата());
Как посчитать месяцы в периоде с учетом выходных?
Для расчета календарных месяцев за вычетом выходных (актуально для срочных договоров):
- Посчитайте общее количество дней в периоде.
- Вычтите количество суббот и воскресений.
- Преобразуйте оставшиеся дни в месяцы (условно 21 рабочий день = 1 месяц).
Пример кода:
ДнейВПериоде = РазностьДат(ДатаОкончания, ДатаНачала, День);
Выходных = 0;
ТекущаяДата = ДатаНачала;
Пока ТекущаяДата <= ДатаОкончания Цикл
Если ДеньНедели(ТекущаяДата) В [6,7] Тогда // 6 - суббота, 7 - воскресенье
Выходных = Выходных + 1;
КонецЕсли;
ТекущаяДата = ТекущаяДата + День;
КонецЦикла;
РабочихДней = ДнейВПериоде - Выходных;
РабочихМесяцев = РабочихДней / 21; // Условно 21 рабочий день в месяце