Как из даты вычесть дату и получить результат в формате даты или временного интервала

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

В программировании на платформе 1С:Предприятие работа с датами имеет свои особенности, которые часто сбивают с толку начинающих разработчиков. Основной вопрос, который мы сегодня разберем: как корректно вычесть одну дату из другой и что именно мы получаем в результате. Мы проанализируем различные подходы — от простой арифметики до сложных функций встроенного языка и запросов.

Основы хранения даты в 1С

Для начала давайте разберем, что представляет собой тип данных Дата в системе 1С. Внутренне любая дата хранится как количество секунд, прошедших с начала нашей эры (0001-01-01 00:00:00). Это критически важный момент для понимания всей арифметики дат.

Когда мы выполняем операцию Дата1 - Дата2, система фактически вычитает одно количество секунд из другого. Результатом такой операции всегда будет Число (разница в секундах), а не объект типа Дата. Именно поэтому фраза "вычесть дату и получить дату" требует уточнения логики.

Вариант 1: Получение разности в секундах, минутах и днях

Рассмотрим простейшую ситуацию: нам нужно узнать, сколько времени прошло между двумя событиями. Как мы уже выяснили, результат будет в секундах. Чтобы привести его к человекочитаемому виду, применим простую математику.

Проанализируем пример кода:


ДатаНачала = '20230101000000'; // 1 января 2023 года
ДатаКонца  = '20230102120000'; // 2 января 2023 года, полдень

РазницаВСекундах = ДатаКонца - ДатаНачала;
РазницаВМинутах  = РазницаВСекундах / 60;
РазницаВЧасах    = РазницаВСекундах / 3600;
РазницаВСутках   = РазницаВСекундах / 86400;

Этот метод идеально подходит для вычисления длительности процессов. Однако стоит помнить, что если в переменных Дата присутствуют часы и минуты, результат будет точным до секунды. Если же вам нужно посчитать количество календарных дней, лучше предварительно "очистить" даты от времени, используя функцию НачалоДня().

Вариант 2: Получение объекта "Дата" из разности (технический прием)

Иногда программисту требуется получить результат именно в типе Дата, чтобы, например, отобразить его в поле ввода с определенным форматом. Для этого можно использовать "пустую" дату (начало летоисчисления) и прибавить к ней полученную разницу в секундах.

Разберем, как это работает на практике:


Дата1 = ТекущаяДата();
Дата2 = Объект.ДатаРегистрации;

// Получаем количество секунд разницы
СекундПрошло = Дата1 - Дата2;

// Прибавляем секунды к пустой дате '00010101'
РезультатДата = '00010101' + СекундПрошло;

// Теперь в переменной РезультатДата хранится объект типа Дата.
// Например, если разница была 1 день и 2 часа, 
// мы получим '00010102020000'

Важно: Этот метод имеет свои ограничения. Он корректно работает для небольших интервалов, но если разница составляет несколько лет, возникнут проблемы с високосными годами, так как в пустом (первом) году нашей эры календарная сетка может не совпадать с текущими реалиями бизнес-логики.

Вариант 3: Вычитание периодов с помощью ДобавитьМесяц()

Если ваша задача — не вычислить разницу, а "отмотать" время назад (например, получить дату, которая была месяц назад от текущей), использование секунд становится неудобным из-за разного количества дней в месяцах. Для этого в 1С предусмотрена функция ДобавитьМесяц().

Посмотрим на пример, как правильно вычитать месяцы:


ТекущаяДата = ТекущаяДата(); // Допустим, 31 марта
ДатаМесяцНазад = ДобавитьМесяц(ТекущаяДата, -1);
// Результат будет 28 (или 29) февраля, система сама определит конец месяца.

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

Вариант 4: Вычисление разности в запросах

В языке запросов 1С мы не можем просто поставить знак минус между двумя полями дат. Для этого используется специальная функция РАЗНОСТЬДАТ. Она принимает три параметра: начальную дату, конечную дату и тип периода (Секунда, Минута, Час, День, Месяц, Квартал, Год).

Проанализируем особенности работы этой функции:


ВЫБРАТЬ
    РАЗНОСТЬДАТ(Заказ.Дата, &ТекущаяДата, ДЕНЬ) КАК ДнейПросрочки
ИЗ
    Документ.ЗаказПокупателя КАК Заказ

Критически важный нюанс: Функция РАЗНОСТЬДАТ в запросе считает количество границ периодов. Это означает, что разница в днях между "23:59:59" сегодня и "00:00:01" завтра будет равна 1, хотя фактически прошла всего 2 секунды. Аналогично, разница в годах между 31 декабря и 1 января будет равна 1. Учитывайте это при построении отчетов.

Вариант 5: Использование производственного календаря

В бизнес-задачах часто требуется не просто вычесть даты, а найти разницу в рабочих днях. Обычное вычитание здесь не поможет, так как оно вернет календарные секунды.

Для решения таких задач в типовых конфигурациях (использующих БСП) мы рекомендуем обращаться к специализированным модулям. Выясним, какие функции могут быть полезны:

  1. КалендарныеГрафики.РазностьДатовКалендарныхДнях(Дата1, Дата2, График) — позволяет вычислить количество дней по конкретному графику работы.
  2. Для вычисления даты через определенное количество рабочих дней в прошлом используется метод КалендарныеГрафики.ПолучитьДатуПоГрафику(ДатаНачала, -КоличествоДней, График).

Методика расчета точного возраста (Стаж)

Если вам нужно получить результат в виде "X лет, Y месяцев, Z дней", простым вычитанием этого не добиться. Профессиональный подход подразумевает последовательное сравнение компонентов дат.

Рассмотрим логику алгоритма:

  1. Сначала вычисляем разницу в годах.
  2. Проверяем, наступил ли уже день рождения (или день месяца) в текущем году. Если нет — уменьшаем количество лет на 1.
  3. Аналогично высчитываем остаток месяцев и дней.

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

Подведение итогов

Мы выяснили, что операция "Дата минус Дата" в 1С — это всегда работа с секундами. Для получения корректного результата в виде даты или сложного интервала придерживайтесь следующих правил:

- Для простых интервалов используйте арифметику секунд.
- Для смещения даты на месяцы или годы используйте ДобавитьМесяц() с отрицательным числом.
- В запросах всегда используйте РАЗНОСТЬДАТ и помните о правиле "границ периодов".
- Для учета праздников и выходных обращайтесь к регистрам сведений Производственного календаря.

Правильный выбор метода позволит вам избежать ошибок при переходе через границы суток, високосные года и праздничные дни, делая ваш код надежным и точным.

← На главную