Расчет стажа — одна из классических задач в 1С, которая на первый взгляд кажется простой, но скрывает в себе множество подводных камней. Нам необходимо учитывать не только количество прошедших дней, но и календарные особенности: разную длительность месяцев, високосные годы и правила включения граничных дат. Разберем подробно несколько проверенных способов решения этой задачи, начиная от простых запросов и заканчивая сложными алгоритмами кадрового учета.
Самый быстрый способ получить разницу между датами — воспользоваться встроенной функцией языка запросов РАЗНОСТЬДАТ. Рассмотрим ситуацию, когда нам нужно получить результат непосредственно в теле запроса. Важно понимать особенность этой функции: она считает количество границ периодов. Если мы укажем периодичность ГОД, то для дат "31.12.2023" и "01.01.2024" функция вернет 1, хотя фактически прошел всего один день.
Чтобы избежать этой ошибки и получить количество полных лет, проанализируем следующий подход. Мы можем передать даты в запрос и выполнить вычисление там. Посмотрим на пример кода, который можно оформить в виде функции:
Функция ПолучитьРазностьДатВЗапросе(ДатаНачала, ДатаОкончания, Периодичность = "ГОД")
Запрос = Новый Запрос;
// Используем замену текста для динамической установки периодичности
ТекстЗапроса =
"ВЫБРАТЬ
| РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, " + Периодичность + ") КАК Разность";
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
Запрос.УстановитьПараметр("ДатаОкончания", ДатаОкончания);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Разность;
КонецЕсли;
Возврат 0;
КонецФункции
Внимание: Если вам нужна исключительная точность для расчета полных лет (как в "день рождения"), в запросе следует добавить проверку: если день и месяц окончания меньше дня и месяца начала, то из полученного результата РАЗНОСТЬДАТ нужно вычесть единицу.
Если вы работаете в современной конфигурации (например, 1С:Управление торговлей 11, ERP или Бухгалтерия предприятия 3.0), нет смысла "изобретать велосипед". В составе Библиотеки стандартных подсистем (БСП) уже есть готовые инструменты. Проанализируем вызов функции из общего модуля ОбщегоНазначенияУТ (или аналогичных модулей БСП):
ОбщегоНазначенияУТ.РазностьДат(ДатаНачала, ДатаОкончания, Периодичность)
Преимущество этого метода в том, что он уже отлажен разработчиками 1С и учитывает большинство стандартных ситуаций. Рассмотрим, как это применить на практике для получения стажа в днях или годах, просто передав нужный параметр периодичности.
Часто в кадровом учете недостаточно просто знать количество лет. Нужно вывести стаж в формате "5 лет, 3 месяца, 10 дней". Для этого разберем более сложный алгоритм, который программно "прокручивает" даты. Выясним причину, почему это лучше делать через ДобавитьМесяц: эта функция корректно обрабатывает високосные года и разную длину месяцев (28, 30, 31 день).
Рассмотрим реализацию процедуры, которая принимает две даты и возвращает разложенный стаж:
Процедура РазобратьРазностьДат(Дата1, Дата2, Лет = 0, Месяцев = 0, Дней = 0) Экспорт
Лет = 0; Месяцев = 0; Дней = 0;
Если Дата1 > Дата2 Тогда
// Для удобства расчетов всегда вычитаем из большей даты меньшую
ВременнаяДата = Дата1;
// Сначала считаем разницу в днях, если текущий день месяца меньше дня начала
Если День(ВременнаяДата) < День(Дата2) Тогда
Дней = (ВременнаяДата - ДобавитьМесяц(ВременнаяДата, -1)) / 86400;
ВременнаяДата = ДобавитьМесяц(ВременнаяДата, -1);
КонецЕсли;
// Считаем разницу в месяцах
Если Месяц(ВременнаяДата) < Месяц(Дата2) Тогда
ВременнаяДата = ДобавитьМесяц(ВременнаяДата, -12);
Месяцев = 12;
КонецЕсли;
Лет = Макс(Год(ВременнаяДата) - Год(Дата2), 0);
Месяцев = Макс(Месяцев + Месяц(ВременнаяДата) - Месяц(Дата2), 0);
Дней = Макс(Дней + День(ВременнаяДата) - День(Дата2), 0);
// Корректировка для случаев с разным количеством дней в месяцах
Если Дата2 <> (ДобавитьМесяц(Дата1, -Лет * 12 - Месяцев) - Дней * 86400) Тогда
Дней = Дней + ((ДобавитьМесяц(Дата1, -Лет * 12 - Месяцев) - Дней * 86400) - Дата2) / 86400;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
В этом коде мы используем деление на 86400 — это количество секунд в сутках. Поскольку в 1С разность двух дат дает результат в секундах, это стандартный способ перевода интервала в дни.
При реализации любого из перечисленных методов, нам необходимо учитывать специфику кадрового учета:
ДобавитьМесяц(Дата, 12) для даты 29.02.2024, система вернет 28.02.2025. Это корректное поведение для большинства юридических расчетов.Подведем итог: если вам нужно быстрое значение в запросе — используйте РАЗНОСТЬДАТ с коррекцией. Если вы пишете код в модуле и у вас есть БСП — используйте типовые функции. Для детального кадрового отчета лучше всего подойдет алгоритм с последовательным вычитанием периодов через ДобавитьМесяц.