При разработке прикладных решений нередко возникает задача учета длительности или отработанного времени, значение которого превышает 24 часа (например, 150 часов 30 минут). Разработчики часто пытаются настроить стандартное поле ввода с типом Дата, рассчитывая обойтись параметрами форматной строки. Рассмотрим, почему этот подход не работает на уровне платформы и какими способами можно правильно решить данную задачу.
В платформе «1С:Предприятие 8» отсутствует отдельный примитивный тип данных для хранения временных интервалов или продолжительности (Duration/Interval). Примитивный тип Дата предназначен исключительно для фиксации конкретной календарной точки во времени в диапазоне от 0001-01-01 00:00:00 до 3999-12-31 23:59:59.
Даже если в метаданных или свойствах элемента формы установить свойство «Состав даты = Время», реквизит физически продолжает оставаться полной датой. При этом параметры форматной строки Ч или ЧЧ жестко привязаны к суточному циклу: платформа воспринимает часы строго в диапазоне от 0 до 23 (или от 1 до 12 при 12-часовом формате). Попытка вывести или ввести значение вида 150:00:00 через форматную строку даты принципиально невозможна. Поэтому для реализации длительности свыше 24 часов необходимо изменить модель хранения и ввода данных.
Проанализируем наиболее универсальный подход для хранения длительности. Для хранения значения в базе данных лучше всего использовать реквизит с типом Число(10, 0) (общее количество секунд) или Число(10, 2) (дробное количество часов). Это позволяет в дальнейшем без проблем суммировать показатели в запросах, регистрах и отчетах.
Для организации удобного пользовательского ввода на управляемой форме создадим строковый реквизит формы (например, ДлительностьСтрокой) и свяжем его с полем ввода. Разберем по шагам, как настроить преобразование:
ЧЧЧ:ММ:СС.ПриИзменении выполняем обратный разбор строки, валидацию введенных данных и пересчет в секунды.Посмотрим на пример серверных и клиентских процедур для обработки такой строки:
&НаКлиенте
Процедура ДлительностьСтрокойПриИзменении(Элемент)
ЧастиВремени = СтрРазделить(ДлительностьСтрокой, ":");
КоличествоЧастей = ЧастиВремени.Количество();
Если КоличествоЧастей = 0 Тогда
Объект.ДлительностьВСекундах = 0;
ДлительностьСтрокой = "00:00:00";
Возврат;
КонецЕсли;
Попытка
Часы = Число(ЧастиВремени[0]);
Минуты = ?(КоличествоЧастей > 1, Число(ЧастиВремени[1]), 0);
Секунды = ?(КоличествоЧастей > 2, Число(ЧастиВремени[2]), 0);
Исключение
ВызватьИсключение "Некорректный формат времени. Используйте шаблон ЧЧЧ:ММ:СС";
КонецПопытки;
Если Минуты >= 60 Или Секунды >= 60 Или Часы < 0 Или Минуты < 0 Или Секунды < 0 Тогда
ВызватьИсключение "Минуты и секунды должны быть в диапазоне от 0 до 59";
КонецЕсли;
Объект.ДлительностьВСекундах = Часы * 3600 + Минуты * 60 + Секунды;
ДлительностьСтрокой = СтрШаблон("%1:%2:%3",
Формат(Часы, "ЧЦ=10; ЧВН=; ЧГ="),
Формат(Минуты, "ЧЦ=2; ЧВН=; ЧГ="),
Формат(Секунды, "ЧЦ=2; ЧВН=; ЧГ="));
КонецПроцедуры
Рассмотрим вариант, который исключает ручной разбор текста и полностью защищает от ошибок формата. Для этого реквизиты разбиваются на три составляющие:
ИнтервалЧасы (тип Число(6, 0)), ИнтервалМинуты (тип Число(2, 0)) и при необходимости ИнтервалСекунды (тип Число(2, 0)).ПриИзменении числовых полей рассчитываем результирующее значение для реквизита объекта.Посмотрим на пример обработчика:
&НаКлиенте
Процедура ПересчитатьИнтервалВСекунды()
Если ИнтервалМинуты > 59 Тогда
ИнтервалМинуты = 59;
КонецЕсли;
Если ИнтервалСекунды > 59 Тогда
ИнтервалСекунды = 59;
КонецЕсли;
Объект.ДлительностьВСекундах = ИнтервалЧасы * 3600 + ИнтервалМинуты * 60 + ИнтервалСекунды;
КонецПроцедуры
В качестве быстрого решения можно применить маску ввода для строкового поля формы. Для этого в свойствах элемента управления задается свойство Маска, например: 999:99:99.
Однако при использовании маски важно учитывать существенные ограничения:
999:99:99 жестко ограничивает ввод тремя знаками часов. Ввести 1000 часов без программной смены маски пользователь не сможет.150:99:99, что потребует обязательной программной проверки в событии ПриИзменении.Резюме: для работы со временем свыше 24 часов стандартный тип Дата не подходит. Оптимальным решением является хранение общего количества секунд в числовом реквизите объекта с организацией пользовательского ввода через парсинг строки или раздельные горизонтальные числовые поля.