При формировании отчетов или выводе информации о длительности выполнения задач часто возникает необходимость преобразовать временную разницу, выраженную в минутах (или секундах), в более понятный и удобочитаемый формат, например, "1 день, 10 часов, 15 минут". Такая конвертация требует особого подхода, поскольку стандартные средства форматирования даты и времени в 1С не всегда напрямую поддерживают формат длительности, отличный от даты или времени суток. Мы рассмотрим несколько эффективных способов решения этой задачи, применимых как в коде, так и в запросах 1С и Системе Компоновки Данных (СКД).
Давайте разберем основные подходы, которые позволят нам добиться желаемого результата, от гибкого программного пересчета до использования встроенных механизмов платформы.
Один из самых гибких и универсальных способов — это прямой программный пересчет общего количества минут в дни, часы и минуты с использованием математических операторов деления и остатка от деления. Этот подход позволяет нам самостоятельно контролировать логику формирования строки и применять его в любом месте, где доступен код 1С.
Для начала нам потребуется общее количество минут. Предположим, оно хранится в переменной КоличествоМинут. Мы знаем, что в одном часе 60 минут, а в одном дне — 24 часа, то есть 1440 минут (24 * 60).
Рассмотрим по шагам, как мы можем произвести этот пересчет:
Посмотрим на пример кода, который реализует эту логику:
Функция ПреобразоватьДлительностьВСтроку(ОбщееКоличествоМинут)
Если ОбщееКоличествоМинут < 0 Тогда
Возврат "Длительность не может быть отрицательной";
КонецЕсли;
ПеременнаяДней = Цел(ОбщееКоличествоМинут / (24 * 60));
ОставшиесяМинутыПослеДней = ОбщееКоличествоМинут % (24 * 60);
ПеременнаяЧасов = Цел(ОставшиесяМинутыПослеДней / 60);
ПеременнаяМинут = ОставшиесяМинутыПослеДней % 60;
РезультатСтрокой = "";
Если ПеременнаяДней > 0 Тогда
РезультатСтрокой = РезультатСтрокой + ПеременнаяДней + " дн. ";
КонецЕсли;
Если ПеременнаяЧасов > 0 Или ПеременнаяДней > 0 Тогда // Часы выводим, если есть дни или сами часы
РезультатСтрокой = РезультатСтрокой + ПеременнаяЧасов + " ч. ";
КонецЕсли;
РезультатСтрокой = РезультатСтрокой + ПеременнаяМинут + " мин.";
Возврат СокрЛП(РезультатСтрокой);
КонецФункции
// Пример использования:
лкМинуты = 1575; // 1 день, 2 часа, 15 минут
Сообщить(ПреобразоватьДлительностьВСтроку(лкМинуты)); // Выведет: "1 дн. 2 ч. 15 мин."
лкМинуты = 75; // 1 час, 15 минут
Сообщить(ПреобразоватьДлительностьВСтроку(лкМинуты)); // Выведет: "1 ч. 15 мин."
лкМинуты = 15; // 15 минут
Сообщить(ПреобразоватьДлительностьВСтроку(лкМинуты)); // Выведет: "15 мин."
Этот подход также был предложен в форуме в следующем виде:
лкИнтервал = "" + Цел(лкМинуты /(24*60)) + " день, " + Цел(лкМинуты % (24*60) / 60 ) + "час. " + лкМинуты % 60 + " мин."
Обратите внимание, что здесь используется конкатенация строк с числами. В коде 1С это допустимо, так как числа автоматически преобразуются в строки. Для более гибкого вывода мы можем добавить условия, чтобы не выводить "0 дней" или "0 часов", если их нет, как показано в первом расширенном примере.
В некоторых конфигурациях 1С существуют уже готовые функции в общих модулях, предназначенные для работы с длительностью. Одна из таких функций, упомянутая в теме форума, это ДлительностьСтрокой(Длительность). Если вы работаете с Системой Компоновки Данных (СКД) или пишете код, проверьте наличие подобных функций в вашей конфигурации. Использование таких готовых решений предпочтительнее, так как они, как правило, уже протестированы и обеспечивают единообразие вывода.
Платформа 1С также содержит специальный тип Длительность, который имеет метод Представление(). Этот метод позволяет форматировать значения типа Длительность в заданный формат. Однако, сам тип Длительность не является встроенным типом данных для хранения интервалов напрямую (он скорее используется для внутренних расчетов). Вместо этого, для работы с длительностью часто используются обычные числа (секунды, минуты) или временные интервалы, полученные как разность двух значений типа Дата. Тем не менее, концепция форматирования длительности через похожие механизмы существует.
Для примера, функция Формат() в 1С позволяет форматировать значения. Хотя она в основном работает с числами и датами, мы можем использовать ее для форматирования частей длительности, если предварительно рассчитаем их. Например, если у нас есть объект типа Дата, представляющий длительность (как мы увидим в следующем решении), мы можем форматировать его так:
// Предположим, у нас есть ДатаВремя, где день = 1, месяц = 1, год = 1, а часы и минуты отражают длительность.
ДлительностьДата = ДатаВремя(1, 1, 1, 10, 15, 0); // Представляет 10 часов 15 минут
ФорматированнаяДлительность = Формат(ДлительностьДата, "ЧН=0; ДФ=ЧЧ:мм");
Сообщить(ФорматированнаяДлительность); // Выведет "10:15"
Однако, это не решает проблему вывода дней. Для комплексного вывода "дни, часы, минуты" с использованием Формат() или аналогичных функций, нам все равно придется сначала выделить дни, часы и минуты отдельно, а затем собрать строку, возможно, с использованием функции Формат() для каждой числовой части для добавления ведущих нулей (например, 05 часов вместо 5 часов).
Если в вашей конфигурации есть общий модуль с функцией типа ДлительностьСтрокой(ДлительностьВСекундах) или ДлительностьСтрокой(ДлительностьВМинутах), мы рекомендуем использовать ее. Обычно такие функции принимают длительность в секундах или минутах и возвращают отформатированную строку. Вы можете найти ее, используя глобальный поиск в конфигураторе по названию "ДлительностьСтрокой" или подобным.
В запросах 1С можно использовать некоторую хитрость, чтобы временно преобразовать количество минут в значение типа Дата, из которого потом можно будет извлечь часы и минуты. Этот метод был предложен в форуме и выглядит так:
ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), МИНУТА, КоличествоМинут)
Функция ДАТАВРЕМЯ(1, 1, 1) создает базовую дату 01.01.0001 00:00:00. Затем функция ДОБАВИТЬКДАТЕ() прибавляет к этой дате указанное количество минут. Например, если КоличествоМинут равно 75, результатом будет 01.01.0001 01:15:00. Если КоличествоМинут равно 1575 (1 день 2 часа 15 минут), то результатом будет 02.01.0001 02:15:00.
Что мы можем делать с этим значением дальше?
Вот как это можно сделать в запросе:
ВЫБРАТЬ
ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), МИНУТА, ВТ_Задачи.Длительность) КАК ДатаДлительности,
ДЕНЬ(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), МИНУТА, ВТ_Задачи.Длительность)) - 1 КАК Дни,
ЧАС(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), МИНУТА, ВТ_Задачи.Длительность)) КАК Часы,
МИНУТА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), МИНУТА, ВТ_Задачи.Длительность)) КАК Минуты
ИЗ
ВТ_Задачи
Важное ограничение: Этот подход имеет существенный недостаток. Он корректно работает только для длительностей, не превышающих количество минут в 31 дне, так как ДЕНЬ() возвращает номер дня месяца, а не общее количество прошедших дней. Если длительность превысит 31 день, то при переходе на следующий месяц функция ДЕНЬ() сбросится. Например, 01.02.0001 00:00:00 покажет 1 день, хотя с начала отсчета прошло гораздо больше.
Поэтому этот метод подходит только для коротких длительностей (менее месяца) и не является универсальным решением для произвольных интервалов.
При попытке напрямую сформировать строку длительности в запросе, как это было сделано в одном из сообщений форума:
ВТ_Задачи.Длительность = "" + ЕСТЬNULL(ВТ_Задачи.Длительность, 0) /(24*60) + " день, " + ЕСТЬNULL(ВТ_Задачи.Длительность, 0) * (24*60) / 60 + "час. " + ЕСТЬNULL(ВТ_Задачи.Длительность, 0) * 60 + " мин."
мы сталкиваемся с ошибкой. Причина в том, что в запросах 1С нельзя напрямую складывать строки и числа. Функция конкатенации строк (оператор +) ожидает операнды строкового типа. Числа должны быть предварительно преобразованы в строки с помощью функции СТРОКА().
Кроме того, в приведенном примере была допущена логическая ошибка в расчетах часов и минут. Корректные формулы для запроса должны использовать операторы деления (/) и остатка от деления (%), как мы видели в программном пересчете. Вот как можно было бы получить отдельные компоненты длительности в запросе:
ВЫБРАТЬ
ВТ_Задачи.Длительность,
ЦЕЛ(ВТ_Задачи.Длительность / (24 * 60)) КАК ДниДлительности,
ЦЕЛ((ВТ_Задачи.Длительность % (24 * 60)) / 60) КАК ЧасыДлительности,
(ВТ_Задачи.Длительность % 60) КАК МинутыДлительности
ИЗ
ВТ_Задачи КАК ВТ_Задачи
После получения отдельных числовых значений (ДниДлительности, ЧасыДлительности, МинутыДлительности) в СКД или в коде, мы можем сформировать итоговую строку, используя функцию Формат() для добавления ведущих нулей при необходимости (например, "05 часов") и объединяя все части в одну строку.
Важно понимать, что формирование сложной текстовой строки с условиями ("1 день" или "1 час" вместо "0 дней" или "0 часов") напрямую в запросе СКД или встроенном языке запросов 1С является затруднительным и не рекомендуется. Лучше всего это делать в вычисляемых полях СКД или уже в процедурном коде, получив предварительно рассчитанные числовые значения из запроса.
Для Системы Компоновки Данных (СКД) мы можем:
ДниДлительности, ЧасыДлительности, МинутыДлительности как отдельные поля.ФорматированнаяДлительность, и использовать для него выражение, которое собирает строку из этих отдельных полей, применяя условия и форматирование.
// Пример выражения для вычисляемого поля в СКД
ВЫБОР
КОГДА ДниДлительности > 0 ТОГДА
СТРОКА(ДниДлительности) + " дн. " + СТРОКА(ЧасыДлительности) + " ч. " + СТРОКА(МинутыДлительности) + " мин."
КОГДА ЧасыДлительности > 0 ТОГДА
СТРОКА(ЧасыДлительности) + " ч. " + СТРОКА(МинутыДлительности) + " мин."
ИНАЧЕ
СТРОКА(МинутыДлительности) + " мин."
КОНЕЦ
Такой подход обеспечивает максимальную гибкость и правильное формирование строки длительности без ошибок типов в запросе.
Мы рассмотрели несколько подходов к преобразованию разницы временных значений, выраженных в минутах, в удобочитаемый формат "дни, часы, минуты" в 1С:
ДлительностьСтрокой()), если они есть в вашей конфигурации, является предпочтительным из-за стандартизации и надежности.ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), МИНУТА, КоличествоМинут)) – это быстрый, но ограниченный по длительности способ, который не рекомендуется для интервалов более 31 дня.СТРОКА()).Выбор конкретного метода зависит от ваших требований, места реализации (код, запрос, СКД) и наличия готовых функций в конфигурации. Наиболее надежным и гибким является программный пересчет, а для СКД – вычисление компонентов в запросе и сборка строки в вычисляемом поле.