Расчет временных интервалов — одна из самых частых задач в программировании на платформе 1С. Несмотря на кажущуюся простоту, при работе с датами и временем разработчики часто сталкиваются с нюансами: переходом через полночь, хранением даты и времени в разных реквизитах или особенностями работы запросов. В этой статье мы подробно разберем все способы вычисления разницы во времени и научимся избегать типичных ошибок.
В системе 1С:Предприятие тип Дата всегда содержит в себе и календарную дату, и время (с точностью до секунды). Основное правило, которое нам необходимо запомнить: разница между двумя датами в 1С — это всегда число, равное количеству секунд между ними.
Рассмотрим стандартную ситуацию. Если у нас есть время начала и время окончания в рамках одного дня, мы используем обычное вычитание:
ДатаНачала = '20220718080000'; // 18.07.22 08:00:00
ДатаОкончания = '20220718200000'; // 18.07.22 20:00:00
РазницаВСекундах = ДатаОкончания - ДатаНачала;
РазницаВМинутах = РазницаВСекундах / 60;
РазницаВЧасах = РазницаВСекундах / 3600;
Разберем ситуацию, когда время начала приходится на один день, а время окончания — на следующий (например, ночная смена). Проанализируем пример: начало 17.07.22 в 21:00, окончание 18.07.22 в 08:00. Поскольку тип Дата хранит в себе и число, и месяц, и год, система автоматически учитывает смену суток. Нам не нужно писать дополнительные условия "если время окончания меньше времени начала".
Посмотрим на код:
ДатаНачала = '20220717210000'; // 17 июля, 21:00
ДатаОкончания = '20220718080000'; // 18 июля, 08:00
РазницаВСекундах = ДатаОкончания - ДатаНачала;
// Результат будет 39 600 секунд (что соответствует 11 часам)
Таким образом, обычное вычитание является универсальным инструментом для любых интервалов, если переменные содержат полные данные о дате.
Часто в интерфейсе программы для удобства пользователя дату и время разносят в разные поля (реквизиты). Например, ДатаРабот и ВремяРабот. Выясним, как их правильно объединить для расчета.
Существует два основных способа объединения:
Дата. Однако этот метод сильно зависит от настроек локализации системы и работает медленнее.Разберем по шагам арифметический метод:
// Предположим, у нас есть:
// Объект.ДатаНачала (тип Дата, время 00:00:00)
// Объект.ВремяНачала (тип Дата, дата 01.01.0001, заполнено только время)
ПолнаяДатаНачала = НачалоДня(Объект.ДатаНачала) + (Объект.ВремяНачала - НачалоДня(Объект.ВремяНачала));
ПолнаяДатаОкончания = НачалоДня(Объект.ДатаОкончания) + (Объект.ВремяОкончания - НачалоДня(Объект.ВремяОкончания));
Разница = ПолнаяДатаОкончания - ПолнаяДатаНачала;
Иногда при попытке расчета возникает ошибка "Преобразование значения к типу Число не может быть выполнено". Проанализируем причину ее возникновения на примере неверного кода:
// ОШИБОЧНЫЙ КОД
РасчетВремени = ((Дата1 - Дата2 - 1) / 60);
Почему это происходит? Если хотя бы одна из переменных (Дата1 или Дата2) не является датой (например, это пустая строка или неопределено), вычитание не сработает. Также важно следить за скобками: операция Дата - Дата дает число, и из него можно вычитать 1. Но если вы попытаетесь вычесть число напрямую из даты (Дата - 1), система воспримет это как "дата минус одна секунда". Ошибка часто кроется в пустых значениях. Всегда проверяйте, заполнены ли реквизиты перед расчетом с помощью функции ЗначениеЗаполнено().
В запросах для вычисления интервалов используется специальная функция РАЗНОСТЬДАТ. Рассмотрим пример получения разницы в секундах между двумя полями:
ВЫБРАТЬ
РАЗНОСТЬДАТ(Документ.ДатаНачала, Документ.ДатаОкончания, СЕКУНДА) КАК ИнтервалВСекундах
ИЗ
Документ.Работы КАК Документ
Важный нюанс: если вы используете в запросе РАЗНОСТЬДАТ с параметром ЧАС или МИНУТА, система считает количество "границ" периодов, а не фактическую астрономическую разницу. Например, разница между 10:59 и 11:01 в минутах составит 2, а в часах — 1 (так как пройдена граница часа), хотя по факту прошло всего 2 минуты. Поэтому для точных расчетов в запросах всегда считайте разницу в секундах, а затем делите на нужное число в коде или в самом запросе.
Полученное число секунд неудобно для чтения пользователем. Нам нужно привести его к виду "ЧЧ:ММ:СС". Проанализируем изящный способ форматирования через прибавление к пустой дате:
РазницаВСекундах = ДатаОкончания - ДатаНачала;
// '00010101' - это пустая дата начала времен
СтрокаВремени = Формат('00010101' + РазницаВСекундах, "ДФ=ЧЧ:мм:сс");
Внимание: Этот метод корректно работает, если общая разница не превышает 24 часа. Если интервал больше суток, время в строке "обнулится", так как формат ЧЧ показывает только время внутри дня. В таких случаях необходимо отдельно вычислять количество дней:
ВсегоСекунд = ДатаОкончания - ДатаНачала;
Дней = Цел(ВсегоСекунд / 86400);
ОстатокСекунд = ВсегоСекунд % 86400;
Результат = Строка(Дней) + " дн. " + Формат('00010101' + ОстатокСекунд, "ДФ=ЧЧ:мм:сс");
Если ваша задача — рассчитать не просто астрономическое время, а рабочие часы сотрудника, обычного вычитания будет недостаточно. В этом случае необходимо использовать производственный календарь или регистры графиков работы. В типовых конфигурациях (ЗУП, ERP) для этого существуют специальные функции в общих модулях, которые позволяют получить количество рабочих секунд в интервале за вычетом выходных, праздников и обеденных перерывов. Всегда проверяйте наличие таких функций в вашей конфигурации перед тем, как писать собственный сложный алгоритм.