При разработке отчетов в системе 1С:Предприятие 8 программисты часто сталкиваются с необходимостью вывести интервал времени между двумя событиями. Казалось бы, простая задача — вычесть одну дату из другой. Однако на уровне языка запросов 1С мы получаем разницу в секундах (число), которое пользователю читать неудобно. Нам же требуется привычный формат ЧЧ:мм:сс или ЧЧ ч. ММ мин..
Сложность заключается в том, что язык запросов 1С не поддерживает прямое преобразование типов (число в строку) и не имеет встроенной функции остатка от деления (modulo). В этой статье мы подробно разберем несколько эффективных способов решения этой задачи, начиная от простых «хитростей» в запросе и заканчивая профессиональной настройкой в системе компоновки данных (СКД).
Проанализируем изящный способ, который подходит для случаев, когда разность дат гарантированно не превышает 24 часа. Идея заключается в том, чтобы добавить полученное количество секунд разности к базовой «нулевой» дате ДАТАВРЕМЯ(1, 1, 1).
Рассмотрим пример кода в запросе:
ВЫБРАТЬ
ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0), СЕКУНДА, РАЗНОСТЬДАТ(ВремяПрихода, ВремяНачала, СЕКУНДА)) КАК ИнтервалВременем
ИЗ
Документ.Приемка КАК Приемка
Что мы получаем в результате? Поле ИнтервалВременем будет иметь тип Дата. Несмотря на то, что это дата, визуально она будет содержать время, равное разности. Чтобы пользователь увидел «красиво», нам достаточно в настройках отчета (или в оформлении поля) установить формат:
ДФ=ЧЧ:мм:сс
Важное ограничение: если разница между датами составит, например, 25 часов, то ДОБАВИТЬКДАТЕ вернет дату 02.01.0001 01:00:00. Если в формате указано только время, пользователь увидит 01:00:00 вместо 25:00:00. Поэтому данный метод идеален только для внутридневных интервалов.
Если нам нужно программно выделить часы, минуты и секунды внутри запроса (например, для сложной конкатенации или условий), мы столкнемся с отсутствием функции % (остаток от деления). Однако мы можем вычислить его математически. Разберем формулу: Остаток = Число - (ЦелаяЧасть(Число / Делитель) * Делитель).
В языке запросов 1С для получения целой части используется функция ВЫРАЗИТЬ. Но внимание: ВЫРАЗИТЬ(Число КАК ЧИСЛО(15, 0)) работает по правилам математического округления. Чтобы «отсечь» дробную часть и получить аналог Floor, нужно вычитать 0.5. Выясним, как это выглядит на практике для получения минут:
ВЫБРАТЬ
РАЗНОСТЬДАТ(ДатаНачала, ДатаКонца, СЕКУНДА) КАК ВсегоСекунд,
// Вычисляем целые часы
ВЫРАЗИТЬ(РАЗНОСТЬДАТ(ДатаНачала, ДатаКонца, СЕКУНДА) / 3600 - 0.5 КАК ЧИСЛО(15, 0)) КАК ЦелыхЧасов,
// Вычисляем остаток секунд после вычета полных часов
РАЗНОСТЬДАТ(ДатаНачала, ДатаКонца, СЕКУНДА) - ВЫРАЗИТЬ(РАЗНОСТЬДАТ(ДатаНачала, ДатаКонца, СЕКУНДА) / 3600 - 0.5 КАК ЧИСЛО(15, 0)) * 3600 КАК ОстатокСекунд
ИЗ
ВТ_Данные
Подобным образом можно выделить минуты и «чистые» секунды. Этот метод громоздкий, но он позволяет производить дальнейшие расчеты без использования СКД.
Если запрос используется в Системе компоновки данных (или в Универсальном отчете), задача решается гораздо проще. Рассмотрим по шагам, как это сделать правильно:
Строка(ЦелоеЧисло(Секунды/3600)) + " ч : " + Строка(ЦелоеЧисло((Секунды % 3600)/60)) + " мин".СерверныеИнструменты.СформироватьВремяСтр(Секунды)), вы можете вызвать её прямо в поле СКД.Пример выражения для вычисляемого поля в СКД:
МойОбщийМодуль.ПредставитьДлительность(РАЗНОСТЬДАТ(ДатаНачала, ДатаОкончания, "СЕКУНДА"))
Это позволит вам выводить интервалы любой длительности (хоть тысячи часов) в любом удобном формате, сохраняя читаемость запроса.
Рассмотрим экзотический, но рабочий способ для тех случаев, когда нельзя использовать СКД, а нужно именно текстовое поле в результате запроса. Поскольку ВЫРАЗИТЬ не умеет превращать число в строку, мы можем использовать функцию ПОДСТРОКА и заранее заготовленную строку цифр.
Проанализируем логику: если мы знаем, что число (например, единицы минут) — это цифра от 0 до 9, мы можем найти её положение в эталонной строке:
ПОДСТРОКА("0123456789", (Минуты - ВЫРАЗИТЬ(Минуты / 10 - 0.5 КАК ЧИСЛО(10, 0)) * 10) + 1, 1)
Соединяя такие «подстроки» для десятков и единиц часов, минут и секунд, можно собрать полноценную строку ЧЧ:ММ:СС. Однако стоит помнить, что такой запрос крайне тяжело поддерживать, и к нему стоит прибегать только в самых крайних ситуациях (например, при жестких требованиях к SQL-выборке).
Подводя итоги, выберем оптимальный путь решения задачи:
ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1,1,1), ...) и настройте формат поля в настройках оформления.Помните, что представление данных — это задача уровня интерфейса, поэтому старайтесь переносить форматирование в настройки отчетов или программный код обработки результата, оставляя запросы максимально простыми и производительными.