При разработке конфигураций на платформе 1С:Предприятие часто возникает задача вычисления точного интервала между двумя датами. Это может быть возраст сотрудника, стаж работы или срок действия договора. Обычное вычитание дат дает результат в секундах, а использование стандартной функции запроса РАЗНОСТЬДАТ не всегда обеспечивает нужную точность для кадрового или юридического учета. Рассмотрим подробнее, как решить эту задачу правильно, используя возможности Библиотеки стандартных подсистем (БСП) и опыт типовых решений.
Прежде всего, проанализируем ситуацию с использованием стандартного механизма 1С. Многие разработчики пытаются решить задачу через запрос, как было предложено в обсуждении. Давайте посмотрим на этот пример, который часто используется:
Функция РазницаМеждуДатами(НачалоПериода, КонецПериода) Экспорт
Структура = Новый Структура("ГОД,МЕСЯЦ,ДЕНЬ");
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| РАЗНОСТЬДАТ(&НачалоПериода, &КонецПериода, ГОД) КАК ГОД,
| РАЗНОСТЬДАТ(&НачалоПериода, &КонецПериода, МЕСЯЦ) КАК МЕСЯЦ,
| РАЗНОСТЬДАТ(&НачалоПериода, &КонецПериода, ДЕНЬ) КАК ДЕНЬ";
Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
Запрос.УстановитьПараметр("КонецПериода", КонецПериода);
// ... обработка результата
КонецФункции
Выясним причину, по которой этот метод считается неточным. Функция РАЗНОСТЬДАТ в языке запросов 1С работает по принципу подсчета границ периодов. Например, если разница между 31 января и 1 февраля составит «1 месяц» для запроса, то фактически прошел всего один день. Для вычисления стажа такой подход неприемлем, так как он не учитывает количество дней в конкретных месяцах и високосные годы.
Если ваша конфигурация построена на базе БСП и включает в себя блоки кадрового учета (как в 1С:Зарплата и управление персоналом или 1С:ERP), вам не нужно изобретать велосипед. Проанализируем возможности общего модуля КадровыйУчет. В нем существует готовая функция, которая возвращает точную структуру данных.
Рассмотрим применение метода РазностьДатВГодахМесяцахИДнях. Он учитывает все нюансы календаря:
// Пример использования в конфигурациях с кадровым блоком
ДатаНачала = '19910805';
ДатаОкончания = ТекущаяДата();
Результат = КадровыйУчет.РазностьДатВГодахМесяцахИДнях(ДатаНачала, ДатаОкончания);
// На выходе получаем структуру:
// Результат.Годы
// Результат.Месяцы
// Результат.Дни
Этот метод является эталонным, так как он используется для расчета трудового стажа, где ошибки в один день могут иметь юридические последствия.
Если же вы работаете в минималистичной конфигурации, где нет модуля КадровыйУчет, разберем по шагам правильный алгоритм вычисления. Основная хитрость заключается в использовании функции ДобавитьМесяц, которая в 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);
Возврат ЧислоПрописью(Число, ФорматнаяСтрока, "");
КонецФункции
Проанализировав различные подходы, мы можем сделать следующие выводы:
КадровыйУчет, всегда используйте стандартную функцию РазностьДатВГодахМесяцахИДнях. Это сэкономит время и гарантирует корректность.ДобавитьМесяц — это единственный способ правильно учесть переменную длительность месяцев (28, 29, 30 и 31 день).Таким образом, задача вычисления разницы дат требует внимания к деталям календаря, но легко решается при использовании правильных инструментов платформы 1С.