При разработке интерфейсных элементов, таких как таймеры обратного отсчета, счетчики времени сеанса или индикаторы выполнения длительных процессов, часто возникает необходимость перевести общее количество секунд в удобный для пользователя формат: дни, часы, минуты и секунды.
Рассмотрим подробно способы решения этой задачи в платформе 1С:Предприятие, разберем математический алгоритм деления, альтернативный вариант через форматирование дат, а также выясним особенности работы фоновых таймеров.
Самый надежный и универсальный способ — разделение общего количества секунд на составляющие элементы с помощью функций Цел() (целая часть числа) и оператора % (остаток от деления). Этот метод работает с временными интервалами любой длительности и не зависит от ограничений типов данных даты.
Разберем алгоритм по шагам:
Дней * 24), либо берем остаток от деления общего количества часов на 24.% 3600.% 60.Проанализируем пример кода на языке 1С:
// Исходные данные: общее количество секунд до нужного события
ОсталосьВремени = 90615; // Пример: 1 день, 1 час, 10 минут, 15 секунд
// 1. Вычисляем полные дни
Дней = Цел(ОсталосьВремени / (3600 * 24));
// 2. Вычисляем часы в пределах текущих суток
Часов = Цел(ОсталосьВремени / 3600) - (Дней * 24);
// 3. Получаем остаток секунд после вычета полных часов
СекОстМин = ОсталосьВремени % 3600;
// 4. Вычисляем минуты и итоговые секунды
Минут = Цел(СекОстМин / 60);
Секунд = СекОстМин % 60;
// Формируем строковое представление
РезультатТекстом = Строка(Дней) + " д. " + Строка(Часов) + " ч. " + Строка(Минут) + " мин. " + Строка(Секунд) + " сек.";
Существует также более наглядный вариант этого же алгоритма, выполняющий последовательный расчет остатков:
Дней = Цел(ОстатокСекунд / 86400);
ОстатокПослеДней = ОстатокСекунд % 86400;
Часов = Цел(ОстатокПослеДней / 3600);
ОстатокПослеЧасов = ОстатокПослеДней % 3600;
Минут = Цел(ОстатокПослеЧасов / 60);
Секунд = ОстатокПослеЧасов % 60;
Если гарантировано, что отображаемый временной интервал не превышает 31 день, можно применить прибавление разницы секунд к пустой дате '00010101000000' с последующим вызовом функции Формат().
ДатаТаймера = КонецГода(ТекущаяДата());
ТДата = ТекущаяДата();
ОстатокСекунд = ДатаТаймера - ТДата; // Получаем разницу в секундах
// Формируем представление через форматную строку
ОсталосьВремени = Формат('00010101000000' + ОстатокСекунд, "ДФ='d ""д."" H ""ч."" mm ""мин."" ss ""сек.""'");
Важная особенность: Спецификатор d в форматной строке выводит день месяца, а не общее количество прошедших дней. Если разница превысит 31 день (например, 100 дней), счетчик дней сбросится на начало нового месяца, и отображаемое значение станет некорректным. Для больших интервалов используйте только математический расчет из Способа 1.
Если расчет необходимо произвести в рамках выполнения сложной бизнес-логики на сервере, можно воспользоваться функцией языка запросов РАЗНОСТЬДАТ:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РАЗНОСТЬДАТ(&ДатаВычитаемая, &ДатаИзКоторойВычитаем, СЕКУНДА) КАК РазностьСекунд";
Запрос.УстановитьПараметр("ДатаВычитаемая", ТекущаяДата());
Запрос.УстановитьПараметр("ДатаИзКоторойВычитаем", ЦелеваяДата);
Выборка = Запрос.Выполнить().Выгрузить();
ОстатокСекунд = Выборка[0].РазностьСекунд;
Часто при создании таймеров на формах разработчики используют системный метод ПодключитьОбработчикОжидания() для обновления информации на экране каждую секунду. Однако при этом важно учитывать следующую специфику платформы:
ПодключитьОбработчикОжидания вызывается платформой только в момент состояния покоя (idle) клиентского приложения. Если пользователь активно редактирует данные, открывает формы или выполняет серверные вызовы, обработчик будет отложен и сработает позже релаксации системы.Счетчик = Счетчик - 1) приведёт к рассинхронизации реального времени и таймера.ЦелеваяДата - ТекущаяДата().Рассмотрим правильную реализацию таймера на форме:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Подключаем обработчик с интервалом в 1 секунду
ПодключитьОбработчикОжидания("ОбновитьВремя", 1, Ложь);
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьВремя()
ОстатокСекунд = Объект.ЦелеваяДата - ТекущаяДата();
Если ОстатокСекунд <= 0 Тогда
ОтключитьОбработчикОжидания("ОбновитьВремя");
Элементы.НадписьТаймер.Заголовок = "Время истекло!";
Возврат;
КонецЕсли;
Дней = Цел(ОстатокСекунд / 86400);
Часов = Цел((ОстатокСекунд % 86400) / 3600);
Минут = Цел((ОстатокСекунд % 3600) / 60);
Секунд = ОстатокСекунд % 60;
Элементы.НадписьТаймер.Заголовок = Строка(Дней) + " д. " + Формат(Часов, "Ч(0)2") + ":" + Формат(Минут, "Ч(0)2") + ":" + Формат(Секунд, "Ч(0)2");
КонецПроцедуры