Как в запросе 1С убрать год из даты и сгруппировать данные по месяцам рождения и возрасту

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

При разработке отчетов по сотрудникам (например, списков именинников или анализа возрастного состава) программисты часто сталкиваются с проблемой: стандартная группировка по дате рождения учитывает год. Из-за этого сотрудники, родившиеся в один и тот же день, но в разные годы, попадают в разные строки. Нам же требуется собрать их по месяцам или дням, игнорируя год рождения. Рассмотрим, как решить эту задачу эффективно, используя язык запросов и Систему компоновки данных (СКД).

Проблема группировки дат в запросах

В системе 1С:Предприятие тип Дата всегда содержит год, месяц, день, часы, минуты и секунды. Если мы просто выберем поле ДатаРождения в запросе и попробуем сгруппировать по нему данные в СКД, система создаст отдельную группу для каждой уникальной даты. Например, 15.10.1980 и 15.10.1990 — это разные значения.

Проанализируем ситуацию: нам нужно «обнулить» год, приведя все даты к одному базовому значению, чтобы группировка сработала корректно, но при этом сохранить возможность выводить название месяца ("Октябрь") и сортировать данные хронологически.

Способ 1. Нормализация даты через прибавление разницы лет

Самый надежный способ «убрать» год в запросе — это вычислить разницу между текущим (или базовым) годом и годом рождения, а затем добавить эту разницу к дате рождения. Рассмотрим пример кода, который приводит все даты к 1-му году нашей эры (0001 год):


ВЫБРАТЬ
    ДОБАВИТЬКДАТЕ(Сотрудники.ДатаРождения, ГОД, 1 - ГОД(Сотрудники.ДатаРождения)) КАК ПериодМесяц,
    Сотрудники.Ссылка КАК Сотрудник
ИЗ
    Справочник.Сотрудники КАК Сотрудники

Разберем, что происходит в этом выражении: функция ГОД(Сотрудники.ДатаРождения) возвращает число (например, 1985). Мы вычитаем его из единицы (1 - 1985 = -1984) и добавляем полученное количество лет к исходной дате. В результате получаем дату вида 15.10.0001. Теперь все сотрудники, родившиеся 15 октября любого года, будут иметь идентичное значение в поле ПериодМесяц.

Важный нюанс: Проблема 29 февраля (викосные годы)

При использовании 0001 года как базового можно столкнуться с ошибкой, если сотрудник родился 29 февраля. Так как 0001 год не является високосным, система может выдать пустую дату или ошибку при попытке преобразования. Чтобы избежать этого, рекомендуется использовать в качестве базового любой високосный год, например, 2000-й.

ДОБАВИТЬКДАТЕ(Сотрудники.ДатаРождения, ГОД, 2000 - ГОД(Сотрудники.ДатаРождения))

Это гарантирует, что дата 29.02.1988 превратится в 29.02.2000, а не исчезнет из отчета.

Способ 2. Использование функции МЕСЯЦ в запросе

Если нам нужно сгруппировать данные строго по месяцам, мы можем использовать функцию МЕСЯЦ(). Она возвращает число от 1 до 12.


ВЫБРАТЬ
    МЕСЯЦ(Сотрудники.ДатаРождения) КАК НомерМесяца,
    КОЛИЧЕСТВО(Сотрудники.Ссылка) КАК КоличествоСотрудников
ИЗ
    Справочник.Сотрудники КАК Сотрудники
СГРУППИРОВАТЬ ПО
    МЕСЯЦ(Сотрудники.ДатаРождения)

Однако у этого метода есть недостаток: в отчете мы увидим цифры (1, 2, 3...) вместо красивых названий ("Январь", "Февраль"). Чтобы это исправить, в СКД придется либо писать сложное выражение ВЫБОР КОГДА..., либо настраивать форматирование через выражения представления.

Расчет точного возраста и возрастных диапазонов

Для отчета по возрастным диапазонам нам сначала нужно вычислить точный возраст. Простое вычитание лет ГОД(ТекущаяДата) - ГОД(ДатаРождения) не совсем корректно, так как оно не учитывает, наступил ли день рождения в этом году. Выясним правильную формулу для запроса:


ВЫБОР
    КОГДА МЕСЯЦ(Сотрудники.ДатаРождения) < МЕСЯЦ(&ТекущаяДата)
        ИЛИ (МЕСЯЦ(Сотрудники.ДатаРождения) = МЕСЯЦ(&ТекущаяДата) И ДЕНЬ(Сотрудники.ДатаРождения) <= ДЕНЬ(&ТекущаяДата))
    ТОГДА РАЗНОСТЬДАТ(Сотрудники.ДатаРождения, &ТекущаяДата, ГОД)
    ИНАЧЕ РАЗНОСТЬДАТ(Сотрудники.ДатаРождения, &ТекущаяДата, ГОД) - 1
КОНЕЦ КАК Возраст

После вычисления возраста мы можем распределить сотрудников по диапазонам, используя конструкцию ВЫБОР прямо в запросе или в вычисляемом поле СКД:


ВЫБОР
    КОГДА Возраст < 20 ТОГДА "До 20 лет"
    КОГДА Возраст МЕЖДУ 20 И 30 ТОГДА "20-30 лет"
    КОГДА Возраст МЕЖДУ 31 И 45 ТОГДА "31-45 лет"
    ИНАЧЕ "Старше 45 лет"
КОНЕЦ КАК ВозрастнойДиапазон

Настройка отображения в СКД

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

  1. Перейдем на вкладку Наборы данных.
  2. Для поля ПериодМесяц установим тип значения Дата.
  3. В колонке Оформление зададим форматную строку: ДФ=ММММ. Это заставит систему выводить только полное название месяца.
  4. Если мы группируем по колонкам в таблице СКД, то в качестве поля группировки выберем наш ПериодМесяц.

Преимущество такого подхода: так как в поле по-прежнему хранится дата (пусть и с измененным годом), СКД автоматически отсортирует колонки в хронологическом порядке: Январь, Февраль, Март и так далее. Если бы мы использовали просто названия месяцев как строки, они бы отсортировались по алфавиту (Август, Апрель, Декабрь...).

Итоги

Мы рассмотрели, как при помощи функции ДОБАВИТЬКДАТЕ привести дни рождения к одному году, чтобы обеспечить корректную группировку. Посмотрим еще раз на финальную структуру запроса, которая объединяет все приемы:


ВЫБРАТЬ
    Сотрудники.Ссылка КАК Сотрудник,
    НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(Сотрудники.ДатаРождения, ГОД, 2000 - ГОД(Сотрудники.ДатаРождения)), МЕСЯЦ) КАК МесяцДляГруппировки,
    ВЫБОР
        КОГДА РАЗНОСТЬДАТ(Сотрудники.ДатаРождения, &ТекущаяДата, ГОД) < 25 ТОГДА "Молодежь"
        ИНАЧЕ "Основной состав"
    КОНЕЦ КАК Категория
ИЗ
    Справочник.Сотрудники КАК Сотрудники

Использование функции НАЧАЛОПЕРИОДА дополнительно гарантирует, что все даты месяца будут приведены к его первому числу, что окончательно исключает "размножение" строк в группировках отчета.

← На главную