Как правильно проверить возраст и дату совершеннолетия сотрудника в запросе 1С

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

При разработке кадровых отчетов или проверок в системе 1С программисты часто сталкиваются с необходимостью вычислить точный возраст физического лица или проверить факт наступления совершеннолетия (18 лет). Кажется, что для этого идеально подходит встроенная функция языка запросов РАЗНОСТЬДАТ, однако на практике её использование для этих целей является одной из самых распространенных логических ошибок. Разберем подробно, почему стандартный подход может подвести и как реализовать проверку возраста максимально точно.

Анализ проблемы: почему РАЗНОСТЬДАТ(..., ГОД) работает неверно

Рассмотрим типичную ситуацию. Программист пытается определить возраст, вычитая год рождения из текущего года. На первый взгляд код выглядит логично:


ВЫБОР
    КОГДА РАЗНОСТЬДАТ(ФизЛицо.ДатаРождения, &ТекущаяДата, ГОД) < 18
    ТОГДА "Несовершеннолетний"
    ИНАЧЕ "Взрослый"
КОНЕЦ

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

Правильный метод: использование функции ДОБАВИТЬКДАТЕ

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

Рассмотрим по шагам реализацию этого метода в языке запросов:

  1. Берем поле ДатаРождения из информационной базы.
  2. Используем функцию ДОБАВИТЬКДАТЕ, передавая в неё тип периода ГОД и количество 18.
  3. Сравниваем результат с параметром &ТекущаяДата.

Пример готового кода для запроса:


ВЫБОР
    КОГДА ДОБАВИТЬКДАТЕ(КадроваяИстория.Сотрудник.ФизическоеЛицо.ДатаРождения, ГОД, 18) > &ТекущаяДата
    ТОГДА "Сотрудник еще не достиг совершеннолетия"
    ИНАЧЕ "Сотрудник совершеннолетний"
КОНЕЦ

В данном случае условие > &ТекущаяДата означает, что день 18-летия еще не наступил. Этот метод считается эталонным для платформы "1С:Предприятие", так как он учитывает и месяцы, и дни рождения автоматически.

Проблема точности времени и использование НАЧАЛОПЕРИОДА

Проанализируем еще один важный нюанс — точность до секунд. В базе данных 1С дата рождения физического лица обычно хранится без времени (точнее, со временем 00:00:00). Если в параметр &ТекущаяДата мы передадим значение ТекущаяДата(), которое включает часы, минуты и секунды, то в сам день рождения система может посчитать человека несовершеннолетним до наступления времени его рождения (которое в базе всегда полночь).

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


ГДЕ
    ДОБАВИТЬКДАТЕ(ФизическиеЛица.ДатаРождения, ГОД, 18) <= НАЧАЛОПЕРИОДА(&ТекущаяДата, ДЕНЬ)

Использование НАЧАЛОПЕРИОДА гарантирует, что в 00:00:00 дня своего восемнадцатилетия сотрудник официально будет признан системой совершеннолетним.

Особенности високосных лет (29 февраля)

Многие разработчики опасаются, что прибавление лет к дате 29 февраля может вызвать программную ошибку или неверный результат. Выясним, как ведет себя платформа. Если человек родился 29 февраля, то через 18 лет (год будет невисокосным) функция ДОБАВИТЬКДАТЕ вернет 28 февраля.

С точки зрения гражданского законодательства (например, ГК РФ), срок, исчисляемый годами, истекает в соответствующие месяц и число последнего года срока. Таким образом, логика 1С полностью соответствует правовым нормам: день рождения "високосного" именинника в обычный год юридически наступает 28 февраля.

Оптимизация производительности запроса

Важно помнить, что использование функций над полями таблиц в секции ГДЕ может существенно замедлить выполнение запроса на больших объемах данных. Это происходит потому, что СУБД не может эффективно использовать индексы по полю ДатаРождения, так как оно обернуто в функцию ДОБАВИТЬКДАТЕ.

Если в вашей базе сотни тысяч сотрудников, разберем более производительный подход. Мы можем заранее рассчитать "граничную дату рождения" на стороне встроенного языка 1С и передать её в запрос как готовый параметр.

Пример кода на встроенном языке:


// Вычисляем дату, позже которой рожденные люди считаются несовершеннолетними
ДатаГраница = ДобавитьМесяц(НачалоДня(ТекущаяДата()), -18 * 12);

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Сотрудники.Ссылка КАК Сотрудник
    |ИЗ
    |	Справочник.Сотрудники КАК Сотрудники
    |ГДЕ
    |	Сотрудники.ФизическоеЛицо.ДатаРождения > &ДатаГраница";

Запрос.УстановитьПараметр("ДатаГраница", ДатаГраница);

Этот метод работает быстрее, так как в условии запроса происходит простое сравнение поля с константой, что позволяет системе использовать индексы базы данных.

Использование функций БСП

Если вы работаете в современной конфигурации (например, ЗУП 3.1, ERP 2.5), проанализируем возможность использования Библиотеки стандартных подсистем (БСП). В составе БСП есть общие модули, такие как ФизическиеЛицаКлиентСервер, которые содержат готовые функции для расчета возраста.

Например, функция РассчитатьВозраст(ДатаРождения, ДатаРасчета) вернет вам точное количество лет. Однако помните, что такие функции нельзя использовать внутри текста запроса — они предназначены для обработки данных уже после их выборки из базы или при работе с формами.

Резюме

Подводя итог, можно выделить основные правила проверки возраста в 1С:

← На главную