Часто в практике разработки на платформе 1С возникает необходимость узнать, сколько месяцев прошло между двумя произвольными датами. Если мы просто попытаемся вычесть одну дату из другой, система вернет нам разницу в секундах. Проанализируем ситуацию: прямой перевод полученных секунд в месяцы обычным делением невозможен. Причина заключается в том, что разные месяцы содержат разное количество дней (от 28 до 31), а также существуют високосные года. Разберем по шагам, как правильно решить эту задачу.
Посмотрим на простой и эффективный подход. Главное правило, которое стоит запомнить: переводим данные в месяцы и только потом вычитаем. Математическая формула для расчета выглядит следующим образом:
Разница = Год(КонДата) * 12 - Год(НачДата) * 12 + Месяц(КонДата) - Месяц(НачДата);
Рассмотрим подробнее готовую экспортную функцию на встроенном языке 1С, которая реализует этот алгоритм и дополнительно проверяет, какая из дат больше, чтобы всегда возвращать положительный результат:
Функция РазницаДатВМесяцах(Дата1, Дата2) Экспорт
ДатаНач = ?(Дата1 < Дата2, Дата1, Дата2);
ДатаКон = ?(Дата1 < Дата2, Дата2, Дата1);
Годы = Год(ДатаКон) - Год(ДатаНач);
Месяцы = Месяц(ДатаКон) - Месяц(ДатаНач);
Разность = Месяцы + Годы * 12;
Возврат Разность;
КонецФункции
Проанализируем возможные подводные камни предложенного решения. Приведенная выше математическая формула считает лишь пересеченные границы календарных месяцев и полностью игнорирует дни. Разберем на примере: если переменная ДатаНач равна 31 января, а ДатаКон равна 1 февраля, формула выдаст разницу ровно в 1 месяц. Фактически же прошел всего 1 день. Это критично, если вам требуется рассчитать точный стаж сотрудника или количество дней компенсации за неиспользованный отпуск.
Если перед нами стоит задача посчитать количество именно полных (фактических) месяцев между датами, простой математической разницы будет недостаточно. Выясним причину: нам требуется анализировать, в какую половину месяца попадает первая и вторая дата.
Рассмотрим, как это обычно реализуется в программном коде:
День().День() у даты окончания меньше, чем у даты начала, то из полученного математического количества месяцев вычитается единица (так как полный месяц еще не истек).КонецМесяца() и ДобавитьМесяц().Посмотрим на альтернативный вариант решения задачи, когда расчет требуется выполнить не в программном модуле, а непосредственно при выборке данных из базы. В языке запросов 1С существует встроенная функция РАЗНОСТЬДАТ().
Для получения разницы в месяцах в тексте запроса синтаксис будет следующим:
РАЗНОСТЬДАТ(ДатаНачала, ДатаОкончания, МЕСЯЦ)
Однако проанализируем важный нюанс: эта встроенная функция имеет то же самое платформенное ограничение, что и математический расчет. Она возвращает разницу в календарных месяцах без учета дней (округление происходит строго по границам месяцев). Чтобы в запросе получить точное количество полных месяцев, разработчикам приходится конструировать более сложные условия, используя функции НАЧАЛОПЕРИОДА, КОНЕЦПЕРИОДА и ДОБАВИТЬКДАТЕ.
Рассмотрим ситуацию, когда разработка или доработка ведется в рамках современных типовых решений от фирмы "1С" (например, 1С:ЗУП, 1С:Бухгалтерия или 1С:ERP). В этом случае писать собственные алгоритмы и изобретать сложные функции для точного вычисления периодов не требуется.
В системе уже присутствуют специализированные общие модули, предназначенные для кадрового или финансового учета. В них реализованы готовые экспортные процедуры и функции. Они автоматически, с учетом всех тонкостей законодательства и особенностей производственного календаря, вычисляют точное количество лет, месяцев и дней между двумя заданными датами. Перед написанием собственного сложного кода всегда проверяйте наличие таких общих модулей в вашей конфигурации.