В практике разработки на платформе 1С:Предприятие часто возникает задача определения временного интервала между двумя датами, выраженного в месяцах. Это может потребоваться для расчета стажа, начисления амортизации, определения срока действия договора или формирования периодической отчетности. Несмотря на кажущуюся простоту, задача имеет несколько вариантов решения в зависимости от того, где выполняется расчет (в запросе или в коде) и насколько точно нужно учитывать дни месяца.
В данной статье мы подробно разберем все доступные методы, проанализируем их особенности и выясним, какой подход лучше применять в конкретных ситуациях.
Если вам необходимо получить разницу дат непосредственно при выборке данных из базы, самым эффективным способом будет использование встроенной функции языка запросов. Рассмотрим пример синтаксиса:
ВЫБРАТЬ
РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, МЕСЯЦ) КАК КоличествоМесяцев
Важный нюанс: Функция РАЗНОСТЬДАТ в запросах работает по принципу подсчета границ периодов. Это означает, что если разница между датами составляет даже один день, но этот день является переходом месяца (например, с 31 января на 1 февраля), функция вернет 1. Если же даты находятся внутри одного календарного месяца (например, 1 января и 30 января), результат будет 0. Этот метод идеально подходит для статистических отчетов, но может быть неточен для расчета фактического времени владения или работы.
Если расчет необходимо выполнить в модуле (на клиенте или сервере) без обращения к запросу, самым быстрым и распространенным способом является вычисление разницы лет и месяцев. Разберем логику этого метода:
// Предположим, Дата1 — это дата начала, Дата2 — дата окончания
КоличествоМесяцев = (Год(Дата2) - Год(Дата1)) * 12 + (Месяц(Дата2) - Месяц(Дата1));
Проанализируем ситуацию: эта формула возвращает количество полных календарных месяцев, прошедших между двумя датами, не обращая внимания на число месяца. Она эквивалентна работе функции в запросе. Например, для дат 01.10.2006 и 06.03.2020 результат составит 161 месяц.
Совет: Всегда проверяйте корректность передаваемых параметров. Если вы получаете странные значения (например, десятки тысяч), убедитесь, что данные правильно считываются из реквизитов формы или объектов базы данных.
Современные конфигурации (такие как БП 3.0, УТ 11, ERP, ЗУП 3.1) содержат готовые механизмы в составе БСП. Проанализируем наиболее «чистый» программный способ, который избавляет разработчика от написания собственных формул:
Для решения задачи можно вызвать функцию общего модуля:
ОбщегоНазначенияКлиентСервер.РазностьДатВМесяцах(ДатаНачала, ДатаОкончания)
Эта функция уже учитывает разницу лет и месяцев, оптимизирована и протестирована на различных сценариях. Использование стандартных процедур — признак хорошего тона в профессиональной разработке.
Иногда требуется более точный расчет. Например, если человек отработал с 15 января по 10 февраля, прошел ли полный месяц? Формула из второго способа скажет, что прошел 1 месяц, но фактически это не так. Разберем алгоритм проверки завершенности месяца по дням:
Функция ПолучитьКоличествоПолныхМесяцев(ДатаНачала, ДатаОкончания)
// Получаем предварительную разницу по календарным месяцам
Результат = (Год(ДатаОкончания) - Год(ДатаНачала)) * 12 + (Месяц(ДатаОкончания) - Месяц(ДатаНачала));
// Проверяем, наступило ли число месяца даты начала в месяце даты окончания
Если День(ДатаОкончания) < День(ДатаНачала) Тогда
// Если день окончания меньше дня начала, значит последний месяц еще не завершен
Результат = Результат - 1;
КонецЕсли;
Возврат Макс(Результат, 0);
КонецФункции
Этот подход критически важен для кадрового учета или расчета процентов по кредитам, где важна фактическая длительность периода.
Один из самых надежных (хотя и чуть более медленных) способов — использование цикла и встроенной функции ДобавитьМесяц(). Посмотрим на пример реализации:
Функция ТочнаяРазницаВМесяцах(ДатаН, ДатаК)
КолМесяцев = 0;
ВременнаяДата = ДатаН;
Пока ДобавитьМесяц(ВременнаяДата, 1) <= ДатаК Цикл
КолМесяцев = КолМесяцев + 1;
ВременнаяДата = ДобавитьМесяц(ВременнаяДата, 1);
КонецЦикла;
Возврат КолМесяцев;
КонецФункции
Данный метод хорош тем, что платформа 1С самостоятельно обрабатывает сложные случаи: високосные годы и разное количество дней в месяцах (28, 30, 31). Функция ДобавитьМесяц() корректно «прыгает» на последнее число следующего месяца, если исходное число отсутствовало (например, с 31 января на 28/29 февраля).
В некоторых экономических расчетах требуется получить результат вида «2.5 месяца». В 1С нет встроенного механизма для этого, поэтому выясним, как это реализовать математически. Обычно за основу берется среднее количество дней в месяце — 30.4375 (365.25 дней в году / 12 месяцев).
РазницаВСекундах = ДатаОкончания - ДатаНачала;
КоличествоДней = РазницаВСекундах / (24 * 60 * 60);
КоличествоМесяцев = КоличествоДней / 30.4375;
Этот метод дает усредненный результат, который часто применяется в управленческом учете для оценки длительности процессов.
Подведем итоги нашего анализа:
РАЗНОСТЬДАТ(..., МЕСЯЦ).(Год2-Год1)*12 + (Мес2-Мес1).ОбщегоНазначенияКлиентСервер.РазностьДатВМесяцах().День(Дата) или цикл с ДобавитьМесяц().Выбор конкретного метода зависит от требований к точности и контекста выполнения кода. Надеемся, что рассмотренные примеры помогут вам эффективно решать задачи по работе с периодами в 1С.