Как правильно рассчитать разницу во времени в 1С:Предприятие 8

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Расчет временных интервалов — одна из самых частых задач в программировании на платформе 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 часам)

Таким образом, обычное вычитание является универсальным инструментом для любых интервалов, если переменные содержат полные данные о дате.

Работа с раздельными реквизитами даты и времени

Часто в интерфейсе программы для удобства пользователя дату и время разносят в разные поля (реквизиты). Например, ДатаРабот и ВремяРабот. Выясним, как их правильно объединить для расчета.

Существует два основных способа объединения:

  1. Строковый метод (менее предпочтительный): Мы преобразуем дату и время в строки, "склеиваем" их и преобразуем обратно в тип Дата. Однако этот метод сильно зависит от настроек локализации системы и работает медленнее.
  2. Арифметический метод (рекомендуемый): Это более надежный и быстрый способ. Мы берем начало дня от даты и прибавляем к нему время, выделенное из "временного" реквизита.

Разберем по шагам арифметический метод:


// Предположим, у нас есть:
// Объект.ДатаНачала (тип Дата, время 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) для этого существуют специальные функции в общих модулях, которые позволяют получить количество рабочих секунд в интервале за вычетом выходных, праздников и обеденных перерывов. Всегда проверяйте наличие таких функций в вашей конфигурации перед тем, как писать собственный сложный алгоритм.

← На главную