В программировании на платформе 1С:Предприятие работа с датами имеет свои особенности, которые часто сбивают с толку начинающих разработчиков. Основной вопрос, который мы сегодня разберем: как корректно вычесть одну дату из другой и что именно мы получаем в результате. Мы проанализируем различные подходы — от простой арифметики до сложных функций встроенного языка и запросов.
Для начала давайте разберем, что представляет собой тип данных Дата в системе 1С. Внутренне любая дата хранится как количество секунд, прошедших с начала нашей эры (0001-01-01 00:00:00). Это критически важный момент для понимания всей арифметики дат.
Когда мы выполняем операцию Дата1 - Дата2, система фактически вычитает одно количество секунд из другого. Результатом такой операции всегда будет Число (разница в секундах), а не объект типа Дата. Именно поэтому фраза "вычесть дату и получить дату" требует уточнения логики.
Рассмотрим простейшую ситуацию: нам нужно узнать, сколько времени прошло между двумя событиями. Как мы уже выяснили, результат будет в секундах. Чтобы привести его к человекочитаемому виду, применим простую математику.
Проанализируем пример кода:
ДатаНачала = '20230101000000'; // 1 января 2023 года
ДатаКонца = '20230102120000'; // 2 января 2023 года, полдень
РазницаВСекундах = ДатаКонца - ДатаНачала;
РазницаВМинутах = РазницаВСекундах / 60;
РазницаВЧасах = РазницаВСекундах / 3600;
РазницаВСутках = РазницаВСекундах / 86400;
Этот метод идеально подходит для вычисления длительности процессов. Однако стоит помнить, что если в переменных Дата присутствуют часы и минуты, результат будет точным до секунды. Если же вам нужно посчитать количество календарных дней, лучше предварительно "очистить" даты от времени, используя функцию НачалоДня().
Иногда программисту требуется получить результат именно в типе Дата, чтобы, например, отобразить его в поле ввода с определенным форматом. Для этого можно использовать "пустую" дату (начало летоисчисления) и прибавить к ней полученную разницу в секундах.
Разберем, как это работает на практике:
Дата1 = ТекущаяДата();
Дата2 = Объект.ДатаРегистрации;
// Получаем количество секунд разницы
СекундПрошло = Дата1 - Дата2;
// Прибавляем секунды к пустой дате '00010101'
РезультатДата = '00010101' + СекундПрошло;
// Теперь в переменной РезультатДата хранится объект типа Дата.
// Например, если разница была 1 день и 2 часа,
// мы получим '00010102020000'
Важно: Этот метод имеет свои ограничения. Он корректно работает для небольших интервалов, но если разница составляет несколько лет, возникнут проблемы с високосными годами, так как в пустом (первом) году нашей эры календарная сетка может не совпадать с текущими реалиями бизнес-логики.
Если ваша задача — не вычислить разницу, а "отмотать" время назад (например, получить дату, которая была месяц назад от текущей), использование секунд становится неудобным из-за разного количества дней в месяцах. Для этого в 1С предусмотрена функция ДобавитьМесяц().
Посмотрим на пример, как правильно вычитать месяцы:
ТекущаяДата = ТекущаяДата(); // Допустим, 31 марта
ДатаМесяцНазад = ДобавитьМесяц(ТекущаяДата, -1);
// Результат будет 28 (или 29) февраля, система сама определит конец месяца.
Этот метод является наиболее безопасным для календарных расчетов, так как он учитывает логику переходов между месяцами и годами.
В языке запросов 1С мы не можем просто поставить знак минус между двумя полями дат. Для этого используется специальная функция РАЗНОСТЬДАТ. Она принимает три параметра: начальную дату, конечную дату и тип периода (Секунда, Минута, Час, День, Месяц, Квартал, Год).
Проанализируем особенности работы этой функции:
ВЫБРАТЬ
РАЗНОСТЬДАТ(Заказ.Дата, &ТекущаяДата, ДЕНЬ) КАК ДнейПросрочки
ИЗ
Документ.ЗаказПокупателя КАК Заказ
Критически важный нюанс: Функция РАЗНОСТЬДАТ в запросе считает количество границ периодов. Это означает, что разница в днях между "23:59:59" сегодня и "00:00:01" завтра будет равна 1, хотя фактически прошла всего 2 секунды. Аналогично, разница в годах между 31 декабря и 1 января будет равна 1. Учитывайте это при построении отчетов.
В бизнес-задачах часто требуется не просто вычесть даты, а найти разницу в рабочих днях. Обычное вычитание здесь не поможет, так как оно вернет календарные секунды.
Для решения таких задач в типовых конфигурациях (использующих БСП) мы рекомендуем обращаться к специализированным модулям. Выясним, какие функции могут быть полезны:
КалендарныеГрафики.РазностьДатовКалендарныхДнях(Дата1, Дата2, График) — позволяет вычислить количество дней по конкретному графику работы.КалендарныеГрафики.ПолучитьДатуПоГрафику(ДатаНачала, -КоличествоДней, График).Если вам нужно получить результат в виде "X лет, Y месяцев, Z дней", простым вычитанием этого не добиться. Профессиональный подход подразумевает последовательное сравнение компонентов дат.
Рассмотрим логику алгоритма:
В современных конфигурациях для этого часто используется функция ОбщегоНазначения.РассчитатьВозраст(), которая возвращает структуру с готовыми данными. Для готового расчета интервала с учетом високосных лет и выводом результата в виде текста можно использовать алгоритм вычисления разницы между датами.
Мы выяснили, что операция "Дата минус Дата" в 1С — это всегда работа с секундами. Для получения корректного результата в виде даты или сложного интервала придерживайтесь следующих правил:
- Для простых интервалов используйте арифметику секунд.
- Для смещения даты на месяцы или годы используйте ДобавитьМесяц() с отрицательным числом.
- В запросах всегда используйте РАЗНОСТЬДАТ и помните о правиле "границ периодов".
- Для учета праздников и выходных обращайтесь к регистрам сведений Производственного календаря.
Правильный выбор метода позволит вам избежать ошибок при переходе через границы суток, високосные года и праздничные дни, делая ваш код надежным и точным.