Как правильно рассчитать стаж работы в годах между двумя датами в 1С?

Программист 1С v8.3 (Управляемые формы)
← На главную

Расчет стажа — одна из классических задач в 1С, которая на первый взгляд кажется простой, но скрывает в себе множество подводных камней. Нам необходимо учитывать не только количество прошедших дней, но и календарные особенности: разную длительность месяцев, високосные годы и правила включения граничных дат. Разберем подробно несколько проверенных способов решения этой задачи, начиная от простых запросов и заканчивая сложными алгоритмами кадрового учета.

Способ 1: Использование функции РАЗНОСТЬДАТ в запросах

Самый быстрый способ получить разницу между датами — воспользоваться встроенной функцией языка запросов РАЗНОСТЬДАТ. Рассмотрим ситуацию, когда нам нужно получить результат непосредственно в теле запроса. Важно понимать особенность этой функции: она считает количество границ периодов. Если мы укажем периодичность ГОД, то для дат "31.12.2023" и "01.01.2024" функция вернет 1, хотя фактически прошел всего один день.

Чтобы избежать этой ошибки и получить количество полных лет, проанализируем следующий подход. Мы можем передать даты в запрос и выполнить вычисление там. Посмотрим на пример кода, который можно оформить в виде функции:


Функция ПолучитьРазностьДатВЗапросе(ДатаНачала, ДатаОкончания, Периодичность = "ГОД")
    Запрос = Новый Запрос;
    // Используем замену текста для динамической установки периодичности
    ТекстЗапроса = 
    "ВЫБРАТЬ
    |    РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, " + Периодичность + ") КАК Разность";
    
    Запрос.Текст = ТекстЗапроса;
    Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
    Запрос.УстановитьПараметр("ДатаОкончания", ДатаОкончания);
    
    Выборка = Запрос.Выполнить().Выбрать();
    Если Выборка.Следующий() Тогда
        Возврат Выборка.Разность;
    КонецЕсли;
    Возврат 0;
КонецФункции

Внимание: Если вам нужна исключительная точность для расчета полных лет (как в "день рождения"), в запросе следует добавить проверку: если день и месяц окончания меньше дня и месяца начала, то из полученного результата РАЗНОСТЬДАТ нужно вычесть единицу.

Способ 2: Использование типовых функций (БСП и УТ/ERP)

Если вы работаете в современной конфигурации (например, 1С:Управление торговлей 11, ERP или Бухгалтерия предприятия 3.0), нет смысла "изобретать велосипед". В составе Библиотеки стандартных подсистем (БСП) уже есть готовые инструменты. Проанализируем вызов функции из общего модуля ОбщегоНазначенияУТ (или аналогичных модулей БСП):

ОбщегоНазначенияУТ.РазностьДат(ДатаНачала, ДатаОкончания, Периодичность)

Преимущество этого метода в том, что он уже отлажен разработчиками 1С и учитывает большинство стандартных ситуаций. Рассмотрим, как это применить на практике для получения стажа в днях или годах, просто передав нужный параметр периодичности.

Способ 3: Детальный расчет (Годы, Месяцы, Дни)

Часто в кадровом учете недостаточно просто знать количество лет. Нужно вывести стаж в формате "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С разность двух дат дает результат в секундах, это стандартный способ перевода интервала в дни.

Важные нюансы при расчете стажа

При реализации любого из перечисленных методов, нам необходимо учитывать специфику кадрового учета:

  1. Включение дня увольнения: Обычно стаж считается включительно. Это значит, что к разнице дат нужно прибавлять 1 день. Например, если сотрудник принят 01.01 и уволен 01.01 того же года, он отработал 1 день.
  2. Проблема 29 февраля: При использовании функции ДобавитьМесяц(Дата, 12) для даты 29.02.2024, система вернет 28.02.2025. Это корректное поведение для большинства юридических расчетов.
  3. Суммирование периодов: Если у сотрудника было несколько периодов работы, нельзя просто сложить "года" и "месяцы" каждого периода. Правильно будет сначала сложить общую разность в днях (или секундах), а уже затем переводить итоговую сумму в годы и месяцы.

Подведем итог: если вам нужно быстрое значение в запросе — используйте РАЗНОСТЬДАТ с коррекцией. Если вы пишете код в модуле и у вас есть БСП — используйте типовые функции. Для детального кадрового отчета лучше всего подойдет алгоритм с последовательным вычитанием периодов через ДобавитьМесяц.

← На главную