Как в 1С получить разность дат в виде лет, месяцев и дней?

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

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

Проблема стандартной функции РАЗНОСТЬДАТ в запросах

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


Функция РазницаМеждуДатами(НачалоПериода, КонецПериода) Экспорт
    Структура = Новый Структура("ГОД,МЕСЯЦ,ДЕНЬ");
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ
    | РАЗНОСТЬДАТ(&НачалоПериода, &КонецПериода, ГОД) КАК ГОД,
    | РАЗНОСТЬДАТ(&НачалоПериода, &КонецПериода, МЕСЯЦ) КАК МЕСЯЦ,
    | РАЗНОСТЬДАТ(&НачалоПериода, &КонецПериода, ДЕНЬ) КАК ДЕНЬ";
    Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
    Запрос.УстановитьПараметр("КонецПериода", КонецПериода);
    
    // ... обработка результата
КонецФункции

Выясним причину, по которой этот метод считается неточным. Функция РАЗНОСТЬДАТ в языке запросов 1С работает по принципу подсчета границ периодов. Например, если разница между 31 января и 1 февраля составит «1 месяц» для запроса, то фактически прошел всего один день. Для вычисления стажа такой подход неприемлем, так как он не учитывает количество дней в конкретных месяцах и високосные годы.

Решение 1: Использование функций из ЗУП или ERP

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

Рассмотрим применение метода РазностьДатВГодахМесяцахИДнях. Он учитывает все нюансы календаря:


// Пример использования в конфигурациях с кадровым блоком
ДатаНачала = '19910805';
ДатаОкончания = ТекущаяДата();

Результат = КадровыйУчет.РазностьДатВГодахМесяцахИДнях(ДатаНачала, ДатаОкончания);

// На выходе получаем структуру:
// Результат.Годы
// Результат.Месяцы
// Результат.Дни

Этот метод является эталонным, так как он используется для расчета трудового стажа, где ошибки в один день могут иметь юридические последствия.

Решение 2: Универсальный алгоритм для «чистой» БСП

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

Рассмотрим программную реализацию:


Функция ПолучитьРазностьДат(ДатаНачала, ДатаКонца) Экспорт
    
    Результат = Новый Структура("Лет, Месяцев, Дней", 0, 0, 0);
    
    Если ДатаНачала > ДатаКонца Тогда
        Возврат Результат;
    КонецЕсли;
    
    // 1. Считаем полные годы
    ВременнаяДата = ДатаНачала;
    Пока ДобавитьМесяц(ВременнаяДата, 12) <= ДатаКонца Цикл
        Результат.Лет = Результат.Лет + 1;
        ВременнаяДата = ДобавитьМесяц(ВременнаяДата, 12);
    КонецЦикла;
    
    // 2. Считаем полные месяцы
    Пока ДобавитьМесяц(ВременнаяДата, 1) <= ДатаКонца Цикл
        Результат.Месяцев = Результат.Месяцев + 1;
        ВременнаяДата = ДобавитьМесяц(ВременнаяДата, 1);
    КонецЦикла;
    
    // 3. Остаток - это дни
    Результат.Дней = (НачалоДня(ДатаКонца) - НачалоДня(ВременнаяДата)) / 86400;
    
    Возврат Результат;
    
КонецФункции

Важный момент: при расчете дней мы делим разницу в секундах на 86400 (количество секунд в сутках). Использование НачалоДня позволяет избежать ошибок, связанных с разным временем в исходных датах.

Формирование текстового представления (склонение)

После получения цифр (например, 3 года, 2 месяца, 11 дней) необходимо вывести их пользователю в красивом виде. В БСП для этого используются механизмы форматных строк. Рассмотрим, как это сделать с помощью СтрШаблон или модуля СтроковыеФункцииКлиентСервер.

Для корректного склонения слов «год/года/лет» рекомендуется использовать форматную строку НП=Ложь. Посмотрим на пример кода, который преобразует числовые значения в строку:


Функция ПредставлениеПериода(СтруктураДаты)
    
    ТекстЛет = ПредставлениеЧислаССуществительным(СтруктураДаты.Лет, "год", "года", "лет");
    ТекстМесяцев = ПредставлениеЧислаССуществительным(СтруктураДаты.Месяцев, "месяц", "месяца", "месяцев");
    ТекстДней = ПредставлениеЧислаССуществительным(СтруктураДаты.Дней, "день", "дня", "дней");
    
    Возврат СтрШаблон("%1 %2 %3", ТекстЛет, ТекстМесяцев, ТекстДней);
    
КонецФункции

// Вспомогательная функция для формирования строки
Функция ПредставлениеЧислаССуществительным(Число, Род1, Род2, Род5)
    Если Число = 0 Тогда Возврат ""; КонецЕсли;
    
    // Используем встроенный механизм форматных строк 1С
    ФорматнаяСтрока = СтрШаблон("L=ru_RU; ND=15; NFD=0; NTS= ; ПредставлениеЧисла = '%1, %2, %3'", Род1, Род2, Род5);
    Возврат ЧислоПрописью(Число, ФорматнаяСтрока, "");
КонецФункции

Подведем итоги

Проанализировав различные подходы, мы можем сделать следующие выводы:

  1. Не используйте РАЗНОСТЬДАТ в запросах для вычисления стажа или возраста, если вам нужна точность до дня. Этот метод хорош только для примерных расчетов.
  2. Если в вашей конфигурации есть модуль КадровыйУчет, всегда используйте стандартную функцию РазностьДатВГодахМесяцахИДнях. Это сэкономит время и гарантирует корректность.
  3. В самописных решениях применяйте цикл с функцией ДобавитьМесяц — это единственный способ правильно учесть переменную длительность месяцев (28, 29, 30 и 31 день).
  4. Для вывода результата пользователю используйте функции склонения, чтобы интерфейс выглядел профессионально (например, «1 год», а не «1 лет»).

Таким образом, задача вычисления разницы дат требует внимания к деталям календаря, но легко решается при использовании правильных инструментов платформы 1С.

← На главную