К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как рассчитать возраст в 1С: запросы, встроенный язык и отчёты

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

Задача вычислить возраст сотрудника, клиента или контрагента возникает в 1С постоянно: при формировании кадровых отчётов, в печатных формах, при проверке условий в программном коде. Возраст — это не хранимый реквизит, а вычисляемое значение, потому что он меняется с каждым днём. Хранить его в базе бессмысленно: данные устареют уже на следующий день, поэтому возраст всегда рассчитывают «на лету» от даты рождения и текущей (или заданной) даты.

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

Как устроен расчёт возраста в 1С: базовые принципы

Дата в 1С — это значение типа «Дата», содержащее день, месяц, год и время. Возраст в полных годах — это количество полных лет, прошедших с даты рождения до заданной даты. Ключевой момент: простое вычитание годов даёт ошибку, если день рождения в текущем году ещё не наступил. Например, для человека, родившегося 15.10.1990, на дату 01.03. текущего года разность годов покажет лишний год, хотя полных лет ещё меньше.

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

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

Расчёт возраста в запросе функцией РАЗНОСТЬДАТ

В языке запросов 1С для работы с датами предусмотрена функция РАЗНОСТЬДАТ(<Дата1>, <Дата2>, <Единица>). Она возвращает разность между двумя датами в указанных единицах: ГОД, КВАРТАЛ, МЕСЯЦ, ДЕНЬ, ЧАС, МИНУТА, СЕКУНДА. Для возраста используется единица ГОД.

Типичный запрос по справочнику сотрудников выглядит так:

ВЫБРАТЬ

Сотрудники.Наименование КАК Сотрудник,

Сотрудники.ДатаРождения КАК ДатаРождения,

РАЗНОСТЬДАТ(Сотрудники.ДатаРождения, &ТекущаяДата, ГОД) КАК Возраст

ИЗ

Справочник.Сотрудники КАК Сотрудники

Важная тонкость: РАЗНОСТЬДАТ с единицей ГОД считает именно количество полных лет между датами, то есть уже учитывает месяц и день. Для дат 15.10.1990 и 01.03. текущего года функция вернёт корректное число полных лет, а не простую разность годов. Это отличает её от ручного вычитания ГОД(Дата2) - ГОД(Дата1), которое даёт ошибку на один год.

Текущую дату в запрос передают параметром, а не вычисляют внутри текста запроса. Перед выполнением установите параметр: Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДатаСеанса());. Так запрос можно переиспользовать для расчёта возраста на любую дату.

Учёт дня рождения: когда РАЗНОСТЬДАТ недостаточно

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

Пример запроса, который выводит возраст в формате «лет и месяцев»:

ВЫБРАТЬ

Сотрудники.Наименование КАК Сотрудник,

РАЗНОСТЬДАТ(Сотрудники.ДатаРождения, &ТекущаяДата, ГОД) КАК Лет,

РАЗНОСТЬДАТ(Сотрудники.ДатаРождения, &ТекущаяДата, МЕСЯЦ)

- РАЗНОСТЬДАТ(Сотрудники.ДатаРождения, &ТекущаяДата, ГОД) * 12 КАК Месяцев

ИЗ

Справочник.Сотрудники КАК Сотрудники

Если дата рождения может быть пустой, добавьте проверку через ВЫБОР КОГОГДА: иначе РАЗНОСТЬДАТ от пустой даты (01.01.0001) вернёт огромное число, которое попадёт в отчёт и исказит итоги. Корректная обработка: ВЫБОР КОГДА Сотрудники.ДатаРождения = ДАТАВРЕМЯ(1,1,1) ТОГДА NULL ИНАЧЕ РАЗНОСТЬДАТ(...) КОНЕЦ.

Расчёт возраста на встроенном языке: готовая функция

Когда возраст нужен в коде модуля — например, при проверке условий перед записью документа или в печатной форме — используют функцию на встроенном языке. Универсальный вариант, который принимает дату рождения и дату расчёта:

Функция РассчитатьВозраст(ДатаРождения, НаДату) Экспорт

Если Не ЗначениеЗаполнено(ДатаРождения) Тогда

Возврат Неопределено;

КонецЕсли;

Возраст = Год(НаДату) - Год(ДатаРождения);

Если Месяц(НаДату) < Месяц(ДатаРождения)

Или (Месяц(НаДату) = Месяц(ДатаРождения)

И День(НаДату) < День(ДатаРождения)) Тогда

Возраст = Возраст - 1;

КонецЕсли;

Возврат Возраст;

КонецФункции

Логика поправки проста: если месяц текущей даты меньше месяца рождения — день рождения ещё не наступил. Если месяцы совпадают, сравниваются дни. В обоих случаях из разности годов вычитается единица. Функцию удобно разместить в общем модуле, чтобы вызывать её из любых объектов конфигурации.

Обратите внимание на обработку пустой даты: функция возвращает Неопределено, а не ноль. Это позволяет отличить «возраст неизвестен» от «возраст 0 лет», что важно в кадровых отчётах и при выгрузке данных.

bsl
Функция ВозрастСтрокой(ДатаРождения, НаДату)
	Лет = РассчитатьВозраст(ДатаРождения, НаДату);
	Если Лет = Неопределено Тогда
		Возврат "";
	КонецЕсли;
	Возврат Строка(Лет) + " " + ?(Лет % 10 = 1 И Лет % 100 <> 11, "год",
		?(Лет % 10 >= 2 И Лет % 10 <= 4 И (Лет % 100 < 10 Или Лет % 100 >= 20), "года", "лет"));
КонецФункции

Возраст в отчётах на СКД и печатных формах

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

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

В типовых конфигурациях (1С:ЗУП, 1С:Бухгалтерия) возраст сотрудников часто уже доступен в готовых отчётах, а для собственных печатных форм значение вычисляют в модуле менеджера объекта при заполнении параметров макета. Передавайте в макет уже готовую строку «35 лет», сформированную функцией склонения, чтобы не усложнять шаблон.

Где считать возраст

РАЗНОСТЬДАТ в запросе

Отчёты, динамические списки, большие выборки. Быстро, учитывает день рождения. Не подходит для сложной логики форматирования.

Функция на встроенном языке

Проверки в коде, печатные формы, склонение «год/года/лет». Гибко, но требует вызова для каждой строки.

Вычисляемое поле СКД

Когда запрос менять нельзя или нужен расчёт от итоговых данных. Медленнее на больших объёмах.

Типичные ошибки при расчёте возраста

Самая распространённая ошибка — вычитание годов без поправки на день рождения: Год(ТекущаяДата) - Год(ДатаРождения). Такой код завышает возраст на единицу для всех, у кого день рождения ещё впереди. В кадровом учёте это приводит к неверным данным о возрастных группах сотрудников.

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

Типичные ошибки
01
Вычитание годов без поправки на день рождения — возраст завышен на год для части людей
02
Расчёт от пустой даты 01.01.0001 без проверки — в отчёт попадает возраст в тысячи лет
03
Хранение возраста в реквизите справочника — данные устаревают ежедневно и требуют пересчёта
04
Жёстко зашитая ТекущаяДатаСеанса() внутри функции — невозможно посчитать возраст на прошедшую дату

Проверка результата и границы применения

Проверить корректность расчёта просто: возьмите дату рождения, у которой день рождения в текущем году ещё не наступил, и дату, у которой уже прошёл. Для первой разность годов должна уменьшаться на единицу, для второй — нет. Также проверьте граничный случай: человек, родившийся сегодня, должен получить возраст 0.

Для запросов удобно выполнить их в консоли запросов с тестовыми параметрами и сверить результат с ручным подсчётом. Если возраст используется в регламентированных отчётах или расчётах, влияющих на выплаты, дополнительно сверьте несколько значений с данными типовой конфигурации.

Контрольные точки

Как проверить результат

День рождения ещё не наступил в текущем году
Норма

Разность годов минус 1

Тревожный признак

Возраст равен простой разности годов

День рождения сегодня
Норма

Возраст увеличился на 1 ровно в этот день

Тревожный признак

Возраст меняется на день раньше или позже

Пустая дата рождения
Норма

Возраст не выводится или равен NULL

Тревожный признак

В отчёте число в тысячи лет

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

Итог

Что важно запомнить

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

Частые вопросы

Учитывает ли РАЗНОСТЬДАТ день рождения при расчёте полных лет?

Да. Функция РАЗНОСТЬДАТ с единицей ГОД возвращает количество полных лет между датами с учётом месяца и дня. Если день рождения на вторую дату ещё не наступил, результат будет на единицу меньше простой разности годов.

Как вывести возраст со словом «год», «года» или «лет»?

Используйте функцию склонения по остатку от деления: если число оканчивается на 1 (кроме 11) — «год», на 2–4 (кроме 12–14) — «года», иначе — «лет». В типовых конфигурациях есть готовые функции склонения в общих модулях работы со строками.

Можно ли хранить возраст в реквизите справочника?

Технически можно, но не нужно: значение устаревает ежедневно, и его придётся пересчитывать регламентным заданием. Правильнее хранить только дату рождения и вычислять возраст в момент обращения — в запросе или коде.

Как посчитать возраст на конкретную дату, а не на сегодня?

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

Что делать, если дата рождения не заполнена?

Проверяйте её перед расчётом: в коде — через ЗначениеЗаполнено(), в запросе — сравнением с ДАТАВРЕМЯ(1,1,1). Возвращайте NULL или Неопределено, чтобы пустые данные не попадали в средние показатели и итоги отчётов.

Как рассчитать возраст в месяцах или днях?

Тем же способом, но с другой единицей измерения: РАЗНОСТЬДАТ(ДатаРождения, &Дата, МЕСЯЦ) для полных месяцев или с единицей ДЕНЬ для дней. Комбинация лет и месяцев получается вычитанием из общего числа месяцев количества полных лет, умноженного на 12.