В платформе 1С:Предприятие 8.х работа с датой и временем реализована максимально удобно: тип Дата содержит и календарное число, и время вплоть до секунд. Это позволяет выполнять простые арифметические операции, например, ТекущаяДата() + 3600 вернет время ровно через час. Однако в «семерке» (1С 7.7) ситуация иная: тип Дата хранит только число, месяц и год, а время обрабатывается отдельно как строка. Рассмотрим, как реализовать механизм работы с датами, аналогичный «восьмерке», и научим программу корректно прибавлять или отнимать секунды, учитывая переход через полночь.
Для начала разберем, как 1С 7.7 воспринимает данные. Когда мы пишем Дата1 + 1, система прибавляет к указанному числу ровно один день. Важно понимать, что платформа автоматически учитывает количество дней в месяцах и високосные годы. Наша задача сводится к тому, чтобы перевести произвольное количество секунд в количество полных дней и остаток секунд внутри текущих суток.
В сутках содержится 86 400 секунд (24 часа * 60 минут * 60 секунд). Это константа, на которой будет строиться вся наша математическая модель.
Чтобы совершать операции со временем, нам нужно научиться переводить строковое представление времени (например, «14:30:15») в числовое. Разберем функцию, которая разбивает строку и вычисляет общее количество секунд с начала дня.
Функция глВремяВСекунды(СтрВремя)
// Извлекаем часы, минуты и секунды из строки формата ЧЧ:ММ:СС
Час = Число(Лев(СтрВремя, 2));
Мин = Число(Сред(СтрВремя, 4, 2));
Сек = Число(Прав(СтрВремя, 2));
// Возвращаем общее количество секунд
Возврат Час * 3600 + Мин * 60 + Сек;
КонецФункции
Эта функция станет фундаментом для наших дальнейших расчетов. Проанализируем ее работу: мы используем встроенные строковые функции Лев(), Сред() и Прав() для выделения компонентов времени, преобразуем их в число и суммируем.
После проведения расчетов нам потребуется вернуть результат в привычный для пользователя и системы формат строки. Рассмотрим пример функции обратного преобразования:
Функция глСекундыВВремя(ВсегоСекунд)
// Ограничиваем количество секунд рамками одних суток
СекундВСутках = 86400;
ОстатокСекунд = ВсегоСекунд % СекундВСутках;
// Если число секунд отрицательное (при вычитании), корректируем его
Если ОстатокСекунд < 0 Тогда
ОстатокСекунд = ОстатокСекунд + СекундВСутках;
КонецЕсли;
Час = Цел(ОстатокСекунд / 3600);
Мин = Цел((ОстатокСекунд - Час * 3600) / 60);
Сек = ОстатокСекунд - Час * 3600 - Мин * 60;
// Форматируем результат с ведущими нулями
Возврат Формат(Час, "Ч(0)2") + ":" + Формат(Мин, "Ч(0)2") + ":" + Формат(Сек, "Ч(0)2");
КонецФункции
Здесь мы применяем функцию Формат() с параметром Ч(0)2, чтобы время всегда выглядело корректно (например, «09:05:01» вместо «9:5:1»). Также мы предусмотрели обработку отрицательного остатка, что критично для операций вычитания времени.
Теперь объединим все знания в одну универсальную процедуру. Допустим, нам нужно к 31.12.2022 23:00:00 прибавить 7200 секунд (2 часа). Мы должны получить 01.01.2023 01:00:00.
Разберем алгоритм по шагам:
N).Посмотрим на программную реализацию этой логики:
Процедура ПрибавитьСекундыКДатеВремя(ИсхДата, ИсхВремя, ПрибавитьСекунд, РезДата, РезВремя)
// 1. Получаем секунды текущего дня
СекундыНачала = глВремяВСекунды(ИсхВремя);
// 2. Вычисляем общую сумму секунд
ВсегоСекунд = СекундыНачала + ПрибавитьСекунд;
// 3. Считаем количество полных дней (может быть как положительным, так и отрицательным)
// Используем деление на 86400
КоличествоДней = Цел(ВсегоСекунд / 86400);
// 4. Получаем остаток секунд внутри суток
ОстатокСекунд = ВсегоСекунд % 86400;
// Особая обработка для отрицательных значений при переходе назад через полночь
Если ОстатокСекунд < 0 Тогда
КоличествоДней = КоличествоДней - 1;
КонецЕсли;
// 5. Результат
РезДата = ИсхДата + КоличествоДней;
РезВремя = глСекундыВВремя(ОстатокСекунд);
КонецПроцедуры
Проанализируем ситуацию: почему мы не вычисляем количество секунд в году или месяце вручную? Как справедливо заметили участники обсуждения, в разных месяцах разное количество дней, существуют високосные года. Используя встроенный механизм Дата + Число, мы перекладываем всю сложную календарную арифметику на плечи движка 1С 7.7. Наша задача — только правильно выделить целое число суток из произвольного количества секунд.
При работе с данными о приходе и уходе сотрудников (как в задаче автора темы), часто приходится вычислять разницу между двумя событиями. В этом случае мы рекомендуем:
ПолучитьУниверсальноеВремя(Дата, Время), которая возвращает количество секунд, прошедшее от какой-то фиксированной точки (например, 01.01.2000).Важный нюанс: при выполнении деления ВсегоСекунд / 86400 для получения количества дней, всегда используйте функцию Цел(). Это позволит избежать ошибок округления и некорректного типа данных в операциях с датами.
Таким образом, мы воссоздали поведение 1С 8.х в среде 7.7. Теперь любые операции с временными интервалами, будь то графики работы сотрудников или расчет сроков годности, будут выполняться математически точно и с учетом всех календарных переходов.