В процессе разработки на платформе 1С:Предприятие программисты часто сталкиваются с задачей определения возраста или срока хранения ТМЦ на складе. Например, для вывода списка именинников часто используется внешняя обработка Дни рождения сотрудников. Стандартная функция РАЗНОСТЬДАТ в языке запросов имеет специфическую особенность: она считает количество пересечений границ указанного периода (года, месяца или дня). Это приводит к тому, что разница между 31 декабря 2024 года и 1 января 2025 года в годах будет равна 1, хотя фактически прошел всего один день. В данной статье мы подробно разберем, как получить корректное количество полных лет, учитывая комплексную работу с датами и периодами в 1С: запросы, БСП и СКД.
Проанализируем ситуацию, описанную пользователем, и выявим основные подводные камни функции РАЗНОСТЬДАТ в языке запросов. Чтобы лучше ориентироваться в подобных нюансах синтаксиса, вам может пригодиться Шпаргалка по языку запросов. При использовании конструкции РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, ГОД) система возвращает разницу календарных лет. Если &ДатаНачала — это 29.10.2024, а &ДатаОкончания — 01.09.2025, функция вернет 1. Однако с точки зрения бизнес-логики (например, для расчета износа или срока нахождения товара на складе) полный год еще не прошел, и результат должен быть равен 0.
Рассмотрим, почему простые арифметические операции не всегда эффективны:
РАЗНОСТЬДАТ для месяцев также считает границы месяцев. Разница между 31 января и 1 февраля составит 1 месяц, что приведет к неверным расчетам.Разберем, как рассчитать количество полных лет (возраст) в запросе 1С, используя наиболее надежный способ реализации этой логики непосредственно в коде запроса. Основная идея заключается в том, чтобы вычислить разницу в годах и проверить, наступила ли уже «годовщина» даты начала в году даты окончания. Для этого мы используем функцию ДОБАВИТЬКДАТЕ.
Проанализируем следующий пример кода запроса:
ВЫБРАТЬ
ВЫБОР
КОГДА &ДатаОкончания >= ДОБАВИТЬКДАТЕ(&ДатаНачала, ГОД, РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, ГОД))
ТОГДА РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, ГОД)
ИНАЧЕ РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, ГОД) - 1
КОНЕЦ КАК ПолныхЛет
Рассмотрим по шагам, как работает эта конструкция:
РАЗНОСТЬДАТ.ДОБАВИТЬКДАТЕ мы прибавляем это количество лет к исходной дате.Если ваша конфигурация построена на базе БСП, мы рекомендуем использование функций БСП для расчета временных интервалов. Изучить доступный инструментарий поможет Справочник по методам БСП (с примерами использования), чтобы не «изобретать велосипед», а воспользоваться готовыми программными методами. Это гарантирует правильную обработку всех краевых случаев, включая високосные года. В общих модулях уже реализованы необходимые механизмы.
Наиболее подходящая функция находится в модуле РаботаСДатами. Рассмотрим пример её вызова:
// Возвращает количество полных лет между двумя датами
ПолныхЛет = РаботаСДатами.КоличествоПолныхЛет(ДатаНачала, ДатаОкончания);
Для задач, связанных с кадровым учетом (например, расчет возраста сотрудника), можно использовать функцию из модуля ОбщегоНазначения:
// Часто используется для вычисления возраста на определенную дату
Возраст = ОбщегоНазначения.Возраст(ДатаРождения, ДатаОтсчета);
Важный нюанс: функции БСП работают в программном коде на сервере. Если вам нужно вывести результат в отчете СКД, вы можете вызвать эти функции в «Вычисляемых полях», если у общего модуля установлен флаг «Вызов сервера».
Проанализируем специфическую ситуацию: что произойдет, если дата начала приходится на 29 февраля високосного года? Рассмотрим, как платформа 1С интерпретирует прибавление года к этой дате. Платформа 1С в функции ДОБАВИТЬКДАТЕ при добавлении одного года к 29.02.2024 вернет 28.02.2025. В большинстве случаев бизнес-логики это считается правильным поведением.
Если же ваша задача требует исключительной точности и вы хотите изучить различные алгоритмы расчета стажа и возраста: от простого к сложному, рассмотрим проверку года на «високосность» прямо в запросе:
ВЫБРАТЬ
ВЫБОР
КОГДА РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(&Дата, ГОД), КОНЕЦПЕРИОДА(&Дата, ГОД), ДЕНЬ) = 365
ТОГДА "Високосный"
ИНАЧЕ "Не високосный"
КОНЕЦ КАК ЭтоВисокосныйГод
Обратите внимание: в обычном году 364 дня разницы между началом и концом года (так как РАЗНОСТЬДАТ в днях считает именно разницу, а не количество дней в периоде), а в високосном — 365.
При работе с большими объемами данных в запросах использование ДОБАВИТЬКДАТЕ внутри ВЫБОР является стандартом. Сравнение месяцев и дней напрямую может работать быстрее на некоторых СУБД, так как не требует сложных календарных вычислений от движка базы данных.
Логика сравнения компонентов выглядит так:
ГОД(Дата2) - ГОД(Дата1).МЕСЯЦ(Дата2) < МЕСЯЦ(Дата1), вычитаем 1.ДЕНЬ(Дата2) < ДЕНЬ(Дата1), вычитаем 1.Этот подход сложнее в написании, но позволяет избежать функций манипуляции датами, которые в некоторых случаях блокируют использование индексов СУБД.
Мы рассмотрели несколько способов решения задачи. Подведем итоги и выберем оптимальный путь:
ВЫБОР с функцией ДОБАВИТЬКДАТЕ (как показано в примере выше).РаботаСДатами.КоличествоПолныхЛет.Помните, что точность расчетов в бизнес-приложениях крайне важна, и стандартная функция РАЗНОСТЬДАТ требует осторожного обращения при работе с крупными периодами (месяцами и годами).