При разработке отчетов в системе компоновки данных (СКД) часто возникает задача вывести время выполнения операций или хронометраж, хранящийся в виде суммарного количества секунд. Стандартный прием с добавлением секунд к начальной дате через выражение ДобавитьКДате(ДатаВремя(1, 1, 1), "Секунда", Секунды) и применением формата времени ДЛФ=T отлично работает только в пределах одних суток. Как только сумма секунд превышает 86 400 (24 часа), результат сбрасывается на начало нового дня, и мы видим некорректные значения часов.
Выясним причину такого поведения платформы и подробно разберем несколько способов правильного вывода интервалов в формате ЧЧЧ:мм:сс или с выделением дней.
Проанализируем особенности платформы 1С:Предприятие. Тип данных Дата хранит абсолютную дату григорианского календаря и время дня, а не временной интервал (длительность). Когда мы прибавляем, например, 90 000 секунд к дате 0001-01-01 00:00:00, значение превращается в дату 0001-01-02 01:00:00. При применении маски ДЛФ=T или ЧЧ:мм:сс календарная часть отбрасывается, и отчет отображает всего лишь 01:00:00 вместо ожидаемых 25 часов.
В языке запросов также нет встроенной операции вычисления остатка от деления (%) и целочисленного деления. Поэтому попытки рассчитать часы через конструкцию ВЫРАЗИТЬ((Секунды / 3600) - 0.5 КАК ЧИСЛО(15, 0)) подвержены особенностям банковского округления платформы и часто дают расхождение на минуту или секунду на граничных значениях. Однако в СКД есть более точные и гибкие инструменты.
Рассмотрим самый удобный и быстрый способ, не требующий изменения конфигурации или усложнения текста запроса. В отличие от языка запросов 1С, язык выражений СКД поддерживает функцию получения целой части Цел(), оператор получения остатка от деления %, а также функцию Формат().
Перейдем на вкладку «Ресурсы» схемы компоновки данных. Для числового поля с секундами в колонке «Выражение» напишем расчет строкового представления от общей суммы секунд.
Если нам требуется получить непрерывный формат часов ЧЧЧ:мм:сс (где часы могут быть больше 24):
Формат(Цел(Сумма(Секунды) / 3600), "ЧЦ=10; ЧН=0; ЧГ=0")
+ ":" + Формат(Цел((Сумма(Секунды) % 3600) / 60), "ЧЦ=2; ЧВН=; ЧГ=0")
+ ":" + Формат(Сумма(Секунды) % 60, "ЧЦ=2; ЧВН=; ЧГ=0")
Если нам требуется детальный формат с выделением суток вида Дни д. ЧЧ:мм:сс:
Формат(Цел(Сумма(Секунды) / 86400), "ЧГ=0") + " д. "
+ Формат(Цел((Сумма(Секунды) % 86400) / 3600), "ЧЦ=2; ЧВН=; ЧГ=0")
+ ":" + Формат(Цел((Сумма(Секунды) % 3600) / 60), "ЧЦ=2; ЧВН=; ЧГ=0")
+ ":" + Формат(Сумма(Секунды) % 60, "ЧЦ=2; ЧВН=; ЧГ=0")
Разберем параметры форматирования, которые мы применили:
ЧВН= (выводить нули) гарантирует, что для значений минут и секунд меньше 10 будет обязательно добавлен ведущий ноль (например, 04 вместо 4).ЧГ=0 отключает группировку разрядов числа пробелами, исключая появление неразрывных пробелов внутри чисел.Сумма(...) обеспечивает правильный расчет: СКД сначала суммирует исходные секунды по группировке, и только затем выполняет математическое преобразование в строку.Если формулы в ресурсах кажутся громоздкими или форматирование интервалов требуется сразу в нескольких отчетах, разберем вынос логики во встроенный язык. СКД позволяет обращаться к экспортным функциям общих модулей с признаком «Сервер».
Создадим или дополним функцию в общем модуле:
Функция ДлительностьВСтроку(Знач ВсегоСекунд) Экспорт
Если ВсегоСекунд = 0 Или ВсегоСекунд = Неопределено Тогда
Возврат "00:00:00";
КонецЕсли;
КоличествоДней = Цел(ВсегоСекунд / 86400);
ОстатокСекунд = ВсегоСекунд % 86400;
КоличествоЧасов = Цел(ОстатокСекунд / 3600);
ОстатокСекунд = ОстатокСекунд % 3600;
КоличествоМинут = Цел(ОстатокСекунд / 60);
Секунды = ОстатокСекунд % 60;
Результат = "";
Если КоличествоДней > 0 Тогда
Результат = Формат(КоличествоДней, "ЧГ=0") + " д. ";
КонецЕсли;
Результат = Результат
+ Формат(КоличествоЧасов, "ЧЦ=2; ЧВН=; ЧГ=0") + ":"
+ Формат(КоличествоМинут, "ЧЦ=2; ЧВН=; ЧГ=0") + ":"
+ Формат(Секунды, "ЧЦ=2; ЧВН=; ЧГ=0");
Возврат Результат;
КонецФункции
После этого перейдем в СКД на вкладку «Ресурсы» и укажем имя функции в поле выражения:
ИмяОбщегоМодуля.ДлительностьВСтроку(Сумма(Секунды))
Обратите внимание: вызывать функцию необходимо именно от выражения Сумма(Секунды). Если передать просто поле Секунды, СКД не сможет корректно посчитать итоги в группировках отчета.
Проанализируем распространенную проблему: если ресурс СКД возвращает строку, сортировка данных по этой колонке начинает выполняться по алфавитному принципу. В таком случае строка "100:00:00" в отчете окажется раньше строки "20:00:00". Чтобы этого избежать, разделим реальное значение и его визуальное представление.
Выполним следующие шаги:
ИмяОбщегоМодуля.ДлительностьВСтроку(Секунды).Сумма(Секунды).ИмяОбщегоМодуля.ДлительностьВСтроку(Сумма(Секунды)).В результате платформа будет использовать для сортировки, отборов и условного оформления исходное числовое значение в секундах, а пользователю на экран выводить аккуратную строку с часами, минутами и секундами.
Посмотрим на ситуацию, когда отчет строится для последующей выгрузки в Microsoft Excel и пользователям требуется продолжать работать с ячейками как со временем (суммировать, находить среднее). В Excel время измеряется в долях суток, где единица равна 24 часам.
Для корректной интеграции сделаем следующее:
Секунды / 86400.[h]:mm:ss (или [ч]:мм:сс в русскоязычной локализации Excel).Квадратные скобки в формате Excel указывают на то, что счетчик часов не должен сбрасываться по достижении 24, а ячейка остается полноценным числом для дальнейших математических расчетов.