Разработка и Конфигурация · 10 мин
Как посчитать количество лет в 1С
Как посчитать количество лет между датами в 1С: функции РазностьДат, ДобавитьКДате, запросы, вычисление возраста и стажа с примерами кода и типичными ошибками.
Задача вычислить количество лет между двумя датами встречается в 1С постоянно: возраст сотрудника в кадровом учёте, стаж работы, срок службы оборудования, возраст дебиторской задолженности, длительность договора. При этом встроенной функции «КоличествоЛет» в языке платформы нет, и разработчики решают задачу несколькими способами — от простого деления разности дат на 365 до точных алгоритмов с корректировкой на месяц и день.
Выбор способа зависит от того, где выполняется расчёт: в модуле на встроенном языке, в запросе или в выражении СКД. Также важна требуемая точность: для аналитического отчёта достаточно приближения, а для кадровых документов, где возраст влияет на льготы и удержания, нужен точный подсчёт полных лет с учётом месяца и дня.
Ниже разобраны рабочие варианты кода для встроенного языка и языка запросов, условия выбора между ними, типичные ошибки и способы проверить результат перед тем, как использовать расчёт в прикладной логике.
Как вычислить полные годы на встроенном языке 1С
Самый надёжный способ на встроенном языке — сравнить годы, месяцы и дни двух дат. Идея простая: разность годов уменьшается на единицу, если в конечной дате «годовщина» начальной даты ещё не наступила. Так работает подсчёт возраста человека: полных лет становится больше только в день рождения.
Функция ПолныхЛет(ДатаНачала, ДатаОкончания) Экспорт
Лет = Год(ДатаОкончания) - Год(ДатаНачала);
Если Месяц(ДатаОкончания) < Месяц(ДатаНачала)
Или (Месяц(ДатаОкончания) = Месяц(ДатаНачала)
И День(ДатаОкончания) < День(ДатаНачала)) Тогда
Лет = Лет - 1;
КонецЕсли;
Возврат Макс(Лет, 0);
КонецФункции
Функция корректно обрабатывает ситуацию, когда день окончания меньше дня начала в пределах одного месяца, и защищается от отрицательного результата, если даты случайно перепутаны местами. Обёртка Макс(Лет, 0) — простая страховка: вместо отрицательного числа вернётся ноль, что безопаснее для дальнейших расчётов.
Обратите внимание на граничный случай 29 февраля. Если дата начала — 29.02.2020, а дата окончания — 28.02.2023, формально полных трёх лет ещё нет, и функция вернёт 2. В кадровом учёте такие ситуации обычно регулируются методикой конкретного расчёта, поэтому для юридически значимых величин сверяйтесь с требованиями прикладной конфигурации.
Лет = Год(ДатаОкончания) - Год(ДатаНачала);
Если Месяц(ДатаОкончания) < Месяц(ДатаНачала)
Или (Месяц(ДатаОкончания) = Месяц(ДатаНачала) И День(ДатаОкончания) < День(ДатаНачала)) Тогда
Лет = Лет - 1;
КонецЕсли;Как посчитать годы через запрос: РАЗНОСТЬДАТ и её ограничения
В языке запросов есть встроенная функция РАЗНОСТЬДАТ(Дата1, Дата2, Тип), которая возвращает разность в заданных единицах: СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, МЕСЯЦ, ГОД. Для подсчёта лет используют тип ГОД:
ВЫБРАТЬ
Сотрудники.Ссылка КАК Сотрудник,
РАЗНОСТЬДАТ(Сотрудники.ДатаРождения, &ТекущаяДата, ГОД) КАК ВозрастЛет
ИЗ
Справочник.Сотрудники КАК Сотрудники
Важно понимать, как РАЗНОСТЬДАТ считает годы: она возвращает количество полных периодов указанного типа между датами. Однако поведение функции на границах периодов в разных версиях платформы и СУБД может отличаться, поэтому для юридически значимых расчётов (возраст для льгот, стаж для надбавок) запрос с РАЗНОСТЬДАТ стоит тестировать на граничных датах: день рождения сегодня, завтра, вчера, 29 февраля.
Если требуется гарантированно точный подсчёт полных лет в запросе, надёжнее скомбинировать функции ГОД, МЕСЯЦ и ДЕНЬ через ВЫБОР — по той же логике, что и во встроенном языке:
ВЫБОР
КОГДА МЕСЯЦ(&ДатаОтчета) < МЕСЯЦ(Сотрудники.ДатаРождения)
ИЛИ (МЕСЯЦ(&ДатаОтчета) = МЕСЯЦ(Сотрудники.ДатаРождения)
И ДЕНЬ(&ДатаОтчета) < ДЕНЬ(Сотрудники.ДатаРождения))
ТОГДА ГОД(&ДатаОтчета) - ГОД(Сотрудники.ДатаРождения) - 1
ИНАЧЕ ГОД(&ДатаОтчета) - ГОД(Сотрудники.ДатаРождения)
КОНЕЦ КАК ПолныхЛет
Когда достаточно приближённого расчёта
Не каждой задаче нужны точные полные годы. Для аналитики — например, среднего возраста основных средств или примерного срока хранения документов — допустимо приближение: разность дат в днях, делённая на 365 или 365,25. Встроенный оператор вычитания дат в 1С возвращает разность в секундах, поэтому расчёт выглядит так:
РазностьВДнях = (ДатаОкончания - ДатаНачала) / 86400;
ПриблизительноЛет = Окр(РазностьВДнях / 365.25, 1);
Здесь 86400 — количество секунд в сутках. Деление на 365,25 учитывает високосные годы в среднем. Результат подходит для диаграмм, пороговых значений с запасом, черновых оценок. Но использовать его нельзя там, где важна точность до дня: ошибка накапливается до нескольких дней на длинных интервалах.
Признак того, что приближение допустимо: результат не влияет на денежные начисления, права доступа, налоги или юридические статусы, а пользователю достаточно оценки «около N лет». Во всех остальных случаях применяйте точный алгоритм с корректировкой на месяц и день.
Как выбрать способ расчёта
Готовые механизмы в типовых конфигурациях
Прежде чем писать собственный расчёт, проверьте стандартные средства. В конфигурациях на базе БСП и в типовых решениях есть готовые функции работы с датами. Например, в общих модулях встречаются функции вида РазностьДат, расчёта возраста и стажа, а в ЗУП кадровый стаж и возраст сотрудников вычисляются штатными механизмами с учётом требований учётной политики.
Использование типовых функций предпочтительнее собственного кода по двум причинам. Во-первых, они уже учитывают методические требования конфигурации — например, правила подсчёта стажа для надбавок. Во-вторых, при обновлении конфигурации поведение типовых функций сопровождается вендором, а самописный код придётся проверять самостоятельно.
Чтобы найти подходящую функцию, откройте в конфигураторе глобальный поиск по словам «Возраст», «Стаж», «РазностьДат», «Лет» по общим модулям. Если функция найдена, посмотрите её описание и примеры вызова в типовом коде — обычно рядом есть процедуры, которые её используют.
В доработках удобно вынести расчёт полных лет в общий серверный модуль своей подсистемы и вызывать его отовсюду: тогда исправление логики потребуется только в одном месте, а не в каждом отчёте и документе.
Как вычислить возраст сотрудника на дату отчёта
Частый прикладной сценарий — отчёт, показывающий возраст сотрудников не на текущую дату, а на произвольную дату, заданную пользователем. Здесь важно не «зашить» ТекущаяДатаСеанса() в расчёт, а передавать дату параметром. Это позволяет строить отчёт «на конец прошлого года» или «на дату приказа» без переписывания кода.
В СКД задачу решают вычисляемым полем с выражением на языке запросов (через ВЫБОР с ГОД/МЕСЯЦ/ДЕНЬ) либо вычислением в коде при формировании. Параметр даты отчёта передаётся в запрос как &ДатаОтчета, и все сравнения выполняются относительно него.
Отдельно учтите пустые даты рождения. Если в справочнике сотрудников поле не заполнено, функции ГОД и МЕСЯЦ вернут значения от пустой даты, и результат будет бессмысленно большим. Добавьте в запрос проверку: ВЫБОР КОГДА ДатаРождения = ДАТАВРЕМЯ(1,1,1) ТОГДА NULL ... — и выводите в отчёте прочерк или пометку «не указано».
Как проверить результат
Количество лет увеличивается ровно на 1 в этот день
Годы увеличиваются на день раньше или позже
Возвращается NULL, 0 или явная пометка об отсутствии данных
Получается огромное число лет
Возвращается 0 или контролируемая ошибка
Отрицательное значение уходит в дальнейшие расчёты
Результат совпадает с ручным подсчётом
Расхождение на день и более
Типичные ошибки при подсчёте лет
Самая распространённая ошибка — считать годы простым вычитанием Год(Дата2) - Год(Дата1) без корректировки. Такой код завышает результат на единицу для всех, у кого «годовщина» начальной даты в текущем году ещё не наступила. В кадровом учёте это означает неверный возраст у значительной части сотрудников.
Вторая ошибка — забыть, что вычитание дат в 1С даёт секунды, а не дни. Код вида (Дата2 - Дата1) / 365 возвращает число, во много раз большее ожидаемого, и если его округлить и записать в реквизит, ошибка может долго оставаться незамеченной.
Третья группа проблем — игнорирование пустых дат и перепутанного порядка аргументов. Пустая дата в 1С — это 01.01.0001, и расчёт от неё даст возраст в тысячи лет. Защищайте функцию проверками на входе: ЗначениеЗаполнено(ДатаНачала) и ДатаОкончания >= ДатаНачала.
Вопросы и ответы
Чем отличается РАЗНОСТЬДАТ с типом ГОД от вычитания годов?
РАЗНОСТЬДАТ считает полные периоды между датами, а не просто разность номеров лет. Однако её поведение на границах периодов стоит проверить в конкретной версии платформы и СУБД, поэтому для критичных расчётов надёжнее явное сравнение года, месяца и дня через ВЫБОР.
Как посчитать возраст с дробной частью, например 25,5 лет?
Вычислите разность дат в днях (разность в секундах, делённая на 86400) и разделите на 365,25, округлив до нужной точности. Такое значение подходит для статистики, но не для кадровых документов, где используются только полные годы.
Как учесть 29 февраля при расчёте возраста?
Стандартный алгоритм сравнения месяца и дня считает, что в невисокосном году годовщина 29 февраля ещё не наступила 28 февраля. Если методика вашего учёта требует иного (например, считать годовщиной 28 февраля), добавьте отдельную ветку условия для этого случая.
Можно ли посчитать годы в СКД без написания кода?
Да. Добавьте вычисляемое поле или используйте выражение ВЫБОР с функциями ГОД, МЕСЯЦ, ДЕНЬ прямо в тексте запроса набора данных. Дату отчёта передайте параметром, чтобы отчёт работал на любую дату.
Что вернёт расчёт, если дата начала больше даты окончания?
Без защиты — отрицательное число или искажённый результат. Рекомендуется в начале функции проверять порядок дат и возвращать 0 или вызывать исключение с понятным сообщением, чтобы ошибка данных была видна сразу.
Есть ли в типовых конфигурациях готовый расчёт стажа и возраста?
Да, в решениях на базе БСП и в конфигурациях вроде ЗУП есть штатные функции и механизмы расчёта возраста и стажа. Перед написанием собственного кода найдите их глобальным поиском по общим модулям и используйте типовой вариант.
Что важно запомнить
Полные годы в 1С считают через разность годов с корректировкой на месяц и день; в запросах применяют РАЗНОСТЬДАТ или ВЫБОР с ГОД/МЕСЯЦ/ДЕНЬ. Приближение через деление дней на 365,25 годится только для аналитики. Всегда проверяйте пустые даты, порядок аргументов и поведение на граничных датах, а в типовых конфигурациях сначала ищите готовые функции.