При разработке кадровых отчетов или доработке документов в конфигурации 1С:Зарплата и Управление Персоналом 2.5 (а также в УПП 1.3 или КА 1.1) программисты часто сталкиваются с необходимостью вычислить стаж сотрудника. Задача кажется простой лишь на первый взгляд. Если мы просто вычтем одну дату из другой, то получим разницу в секундах. Однако для кадрового учета требуется результат в формате: «количество лет, месяцев и дней». Разберем по шагам, как решить эту задачу правильно, используя как типовые механизмы, так и собственные алгоритмы.
Рассмотрим стандартный механизм платформы 1С. Когда мы пишем Разность = Дата1 - Дата2, система возвращает число. Это число — количество секунд, прошедших между двумя моментами времени. Чтобы перевести их в дни, нам придется делить результат на 86400 (количество секунд в сутках). Но как перевести дни в месяцы или годы? Количество дней в месяцах варьируется (28, 29, 30 или 31), а в году может быть 365 или 366 дней. Простое деление на «среднее количество дней» даст погрешность, которая недопустима в кадровом учете. Выясним, какие инструменты предлагает нам сама конфигурация.
В конфигурациях на базе «Зарплата и Управление Персоналом 2.5» (ЗУП) уже реализованы все необходимые механизмы для расчета стажа. Самый надежный и правильный способ — обратиться к общему модулю ОбщегоНазначенияЗК (ЗК означает «Зарплата и Кадры»).
Проанализируем пример использования типовой функции РазобратьРазностьДат. Эта функция принимает две даты и возвращает результат через параметры, переданные по ссылке. Посмотрим на пример кода:
// Инициализируем переменные для результата
ЛетСтажа = 0;
МесяцевСтажа = 0;
ДнейСтажа = 0;
// Вызываем типовую функцию
// ДатаСобытия - конечная дата, ДатаНачала - начальная дата
ОбщегоНазначенияЗК.РазобратьРазностьДат(ДатаСобытия, ДатаНачала, ЛетСтажа, МесяцевСтажа, ДнейСтажа);
// Теперь переменные ЛетСтажа, МесяцевСтажа и ДнейСтажа содержат нужные значения
Сообщить("Стаж составляет: " + ЛетСтажа + " лет, " + МесяцевСтажа + " месяцев, " + ДнейСтажа + " дней.");
Важный момент: в некоторых версиях конфигураций аналогичная процедура может находиться в модуле ПроцедурыУправленияПерсоналом. Использование этого метода гарантирует, что ваш расчет будет соответствовать логике, заложенной фирмой «1С» для регламентированной отчетности.
Если по какой-то причине вы работаете в конфигурации, где нет вышеуказанных модулей, или создаете внешнюю обработку, которая должна быть максимально независимой, можно реализовать алгоритм самостоятельно. Основная сложность здесь — корректный учет переходов через границы месяцев и високосных лет.
Рассмотрим логику, которую можно применить для точного расчета. Мы будем последовательно уменьшать временную дистанцию, вычитая целые года и месяцы. Проанализируем следующий пример реализации:
Функция ВычислитьСтаж(ДатаНачала, ДатаОкончания)
Лет = 0; Месяцев = 0; Дней = 0;
Если ДатаНачала > ДатаОкончания Тогда
Возврат "Дата начала не может быть больше даты окончания";
КонецЕсли;
// Временная дата для расчетов
ВременнаяДата = ДатаНачала;
// Считаем полные годы
Пока ДобавитьМесяц(ВременнаяДата, 12) <= ДатаОкончания Цикл
ВременнаяДата = ДобавитьМесяц(ВременнаяДата, 12);
Лет = Лет + 1;
КонецЦикла;
// Считаем полные месяцы
Пока ДобавитьМесяц(ВременнаяДата, 1) <= ДатаОкончания Цикл
ВременнаяДата = ДобавитьМесяц(ВременнаяДата, 1);
Месяцев = Месяцев + 1;
КонецЦикла;
// Оставшиеся дни
Дней = (ДатаОкончания - ВременнаяДата) / 86400;
Возврат "Лет: " + Лет + ", месяцев: " + Месяцев + ", дней: " + Цел(Дней);
КонецФункции
В этом примере мы используем встроенную функцию ДобавитьМесяц. Это очень мощный инструмент платформы 1С, который берет на себя всю сложность календарной арифметики: он знает, сколько дней в каждом месяце и учитывает високосные года. Использование циклов Пока позволяет «шагать» по календарю, не опасаясь ошибок округления.
Иногда требуется получить стаж сразу для большого списка сотрудников. В этом случае эффективнее использовать механизм запросов. Однако стоит помнить, что функция РАЗНОСТЬДАТ в языке запросов 1С работает по принципу подсчета границ периодов.
Например, запрос РАЗНОСТЬДАТ(ДАТАВРЕМЯ(2022, 12, 31), ДАТАВРЕМЯ(2023, 01, 01), ГОД) вернет 1, хотя по факту прошел всего один день. Это происходит потому, что даты находятся в разных календарных годах. Чтобы получить точный стаж в годах, месяцах и днях через запрос, придется использовать сложные математические условия.
Посмотрим на пример логики в запросе для получения полных лет:
ВЫБРАТЬ
Сотрудники.Ссылка,
ВЫБОР
КОГДА МЕСЯЦ(Сотрудники.ДатаПриема) < МЕСЯЦ(&ТекущаяДата)
ТОГДА ГОД(&ТекущаяДата) - ГОД(Сотрудники.ДатаПриема)
КОГДА МЕСЯЦ(Сотрудники.ДатаПриема) = МЕСЯЦ(&ТекущаяДата) И ДЕНЬ(Сотрудники.ДатаПриема) <= ДЕНЬ(&ТекущаяДата)
ТОГДА ГОД(&ТекущаяДата) - ГОД(Сотрудники.ДатаПриема)
ИНАЧЕ ГОД(&ТекущаяДата) - ГОД(Сотрудники.ДатаПриема) - 1
КОНЕЦ КАК ПолныхЛет
ИЗ
Справочник.Сотрудники КАК Сотрудники
Этот подход позволяет избежать «ловушки границ», проверяя, наступил ли уже день рождения (или день приема) в текущем году.
При расчете трудового стажа важно учитывать правила, установленные законодательством. Разберем два ключевых момента:
Подведем итоги. Если вы работаете внутри типовой конфигурации ЗУП 2.5, не изобретайте велосипед — используйте ОбщегоНазначенияЗК.РазобратьРазностьДат. Это сэкономит ваше время и обеспечит точность, проверенную тысячами пользователей. Если же вы пишете собственное решение, всегда используйте функцию ДобавитьМесяц для итераций по датам, чтобы платформа сама заботилась о длине месяцев и високосных годах. Помните о необходимости корректного склонения слов (год, года, лет) при выводе результата пользователю — для этого в 1С также существуют механизмы форматных строк.