Разработка и Конфигурация · 10 мин
1С: как из одной даты вычесть другую
Как в 1С вычесть одну дату из другой: оператор минус, функция РАЗНОСТЬДАТ в запросе, расчёт дней, месяцев и лет между датами. Примеры кода и типичные ошибки.
Вычитание дат — одна из базовых операций при разработке и доработке конфигураций 1С: она нужна для расчёта сроков оплаты, стажа сотрудников, просрочки задолженности, возраста товара на складе и десятков других задач. При этом у начинающих разработчиков часто возникает путаница: обычный оператор «минус» возвращает секунды, а не дни, а для получения разницы в месяцах или годах требуется отдельный подход.
В 1С существует два основных способа вычесть одну дату из другой: встроенный оператор вычитания в коде на встроенном языке и функция РАЗНОСТЬДАТ в языке запросов. У каждого способа свои единицы измерения результата, ограничения и типичные сценарии применения. Ниже разобраны оба варианта с примерами кода, а также частые ошибки и способы их проверки.
Как 1С хранит даты и что возвращает вычитание
Тип «Дата» в 1С хранит момент времени с точностью до секунды. Даже если реквизит документа отображается только как календарное число, внутри хранится полное значение — дата плюс время (для «чистой» даты время равно 00:00:00). Это важно понимать, потому что результат вычитания зависит от временной составляющей.
Когда вы пишете Дата2 - Дата1, платформа возвращает число — количество секунд между двумя моментами. Если Дата2 позже Дата1, результат положительный; если раньше — отрицательный. Это удобно для точных расчётов, но требует пересчёта в привычные единицы: минуты, часы, дни.
Отдельный нюанс — пустая дата. Значение '00010101000000' (1 января года 1) является корректной датой, и вычитание с её участием даст огромное число секунд. Перед расчётами всегда проверяйте заполненность дат функцией ЗначениеЗаполнено() или сравнением с пустой датой.
Вычитание дат оператором «минус» в коде
Самый простой способ — обычное вычитание в модуле. Чтобы получить разницу в днях, результат делят на количество секунд в сутках — 86400:
РазницаВСекундах = ДатаОкончания - ДатаНачала;
РазницаВДнях = РазницаВСекундах / 86400;
РазницаВЧасах = РазницаВСекундах / 3600;
Если нужно целое число дней без дробной части, используйте функцию Цел(). Учтите: при делении дробная часть просто отбрасывается, поэтому период в 1 день и 23 часа даст результат 1. Если требуется округление по правилам математики, применяйте Окр().
Для проверки знака результата удобно сравнивать даты напрямую: условие Если Дата2 > Дата1 Тогда работает корректно для типа «Дата» без каких-либо преобразований.
Расчёт разницы в днях с учётом и без учёта времени
На практике чаще всего нужна разница именно в календарных днях: сколько дней прошло с даты отгрузки, сколько дней до срока оплаты. Чтобы время суток не влияло на расчёт, приведите обе даты к началу дня:
ДнейМежду = (НачалоДня(Дата2) - НачалоДня(Дата1)) / 86400;
Такой вариант гарантирует целое число дней независимо от того, в какое время суток были установлены даты. Это стандартный приём для расчёта просрочки платежей, сроков хранения и подобных показателей.
Если же задача требует точности до часов или минут (например, контроль SLA по заявкам), не отсекайте время и работайте с секундами или часами напрямую. Здесь дробный результат — не ошибка, а нужная точность.
- 1Проверьте, что обе даты заполнены (ЗначениеЗаполнено)
- 2Приведите даты к началу дня функцией НачалоДня()
- 3Вычтите меньшую дату из большей оператором «минус»
- 4Разделите результат на 86400
- 5Проверьте знак результата при неизвестном порядке дат
Функция РАЗНОСТЬДАТ в запросах 1С
В языке запросов вычитание оператором «минус» для дат недоступно — вместо него используется специальная функция РАЗНОСТЬДАТ. Она принимает три параметра: начальную дату, конечную дату и единицу измерения результата.
ВЫБРАТЬ
РАЗНОСТЬДАТ(Заказ.Дата, &ТекущаяДата, ДЕНЬ) КАК ДнейСДатыЗаказа,
РАЗНОСТЬДАТ(Сотрудник.ДатаРождения, &ТекущаяДата, ГОД) КАК Возраст
ИЗ
Документ.ЗаказПокупателя КАК Заказ
Допустимые единицы измерения: СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, МЕСЯЦ, КВАРТАЛ, ГОД. Функция возвращает целое число — количество полных единиц, уместившихся между датами. Например, между 31 января и 1 февраля разность в месяцах равна 1, хотя прошло всего два дня.
Если первая дата позже второй, результат будет отрицательным. Это удобно для определения просрочки: отрицательное значение РАЗНОСТЬДАТ по сроку оплаты сразу показывает, что срок уже наступил.
Разница в месяцах и годах: нюансы и подводные камни
Расчёт в месяцах и годах концептуально сложнее, чем в днях, потому что месяцы имеют разную длину. РАЗНОСТЬДАТ считает переход через границу месяца: между 15 января и 14 февраля разница в месяцах равна 0 (полный месяц не прошёл), а между 15 января и 15 февраля — уже 1.
Для точного расчёта возраста или стажа в годах одной РАЗНОСТЬДАТ с единицей ГОД обычно недостаточно: она корректно считает полные годы, но если нужна проверка «достиг ли человек 18 лет», надёжнее сравнить дату рождения с датой, полученной через ДОБАВИТЬКДАТЕ(&ТекущаяДата, ГОД, -18). Такое сравнение учитывает високосные годы корректнее ручной арифметики.
В коде на встроенном языке для сдвига дат на месяцы и годы используйте функцию ДобавитьМесяц(). Она корректно обрабатывает концы месяцев: добавление месяца к 31 января даст последний день февраля, а не несуществующую дату.
Способы вычесть даты в 1С
Подходит для точных расчётов в секундах, минутах, часах и днях. Требует ручного пересчёта единиц и отсечения времени.
Удобна для отчётов и выборок: сразу возвращает дни, месяцы или годы. Считает только полные единицы, недоступна вне запроса.
Лучший вариант для проверок наступления срока (возраст, годовщина): сдвигаете дату и сравниваете напрямую.
Типичные ошибки при вычитании дат
Самая распространённая ошибка — забыть, что оператор «минус» возвращает секунды. Разработчик записывает разницу в числовой реквизит «ДнейПросрочки» без деления на 86400 и получает значения в десятки тысяч. Такая ошибка особенно опасна, если по результату рассчитываются пени или блокируются отгрузки.
Вторая частая проблема — игнорирование времени суток. Дата документа в 1С часто содержит время проведения, и «вчерашний» документ в 23:59 формально отстоит от «сегодняшнего» в 00:01 всего на 2 минуты, хотя календарно это разные дни. Для отчётов по дням всегда приводите даты к началу дня.
Третья группа ошибок — работа с незаполненными датами. Вычитание пустой даты не вызывает исключения, а молча возвращает огромное число, которое потом попадает в отчёты и расчёты.
Проверка результата и контрольные точки
После написания расчёта проверьте его на граничных случаях. Минимальный набор тестов: одинаковые даты (должно быть 0), соседние дни с разным временем суток, период через границу месяца и года, а также ситуация с незаполненной датой.
Для быстрой отладки в коде используйте Сообщить() с выводом обеих дат и результата, а в консоли запросов — выводите сами даты рядом с РАЗНОСТЬДАТ, чтобы визуально сверить значения. Если результат отличается от ожидаемого на порядки, почти наверняка потеряно деление на 86400.
Как проверить результат
Результат равен 1 дню (или 86400 секунд)
Дробное или нулевое значение — проверьте отсечение времени
Результат равен 0
Ненулевое значение — даты содержат разное время
Разница за месяц — около 30 дней
Значения в миллионах — это секунды без пересчёта
Расчёт пропускается или выдаёт предупреждение
Огромное число попадает в отчёт
Часто задаваемые вопросы
Как в 1С получить количество дней между двумя датами?
В коде: вычтите одну дату из другой и разделите результат на 86400, предварительно применив НачалоДня() к обеим датам. В запросе используйте РАЗНОСТЬДАТ(Дата1; Дата2; ДЕНЬ) — функция вернёт целое число полных дней.
Почему при вычитании дат получается огромное число?
Оператор «минус» для дат возвращает разницу в секундах, а не в днях. Например, одни сутки — это 86400. Разделите результат на 86400, чтобы получить дни. Если число неправдоподобно велико (миллиарды), проверьте, не участвует ли в расчёте пустая дата.
Можно ли вычесть даты прямо в запросе без РАЗНОСТЬДАТ?
Нет, язык запросов 1С не поддерживает арифметику дат оператором «минус». Для разности используйте РАЗНОСТЬДАТ, а для сдвига даты на заданный интервал — ДОБАВИТЬКДАТЕ с положительным или отрицательным количеством единиц.
Как посчитать возраст сотрудника в полных годах?
Самый надёжный способ — сравнить дату рождения с датой, сдвинутой на нужное число лет назад: ДОБАВИТЬКДАТЕ(&ТекущаяДата, ГОД, -18). Если дата рождения меньше или равна полученной, возраст достигнут. Деление дней на 365 даёт погрешность из-за високосных лет.
Что вернёт вычитание, если вторая дата раньше первой?
Оператор «минус» вернёт отрицательное число секунд, а РАЗНОСТЬДАТ — отрицательное целое. Это удобно для определения просрочки: отрицательный результат означает, что контрольная дата уже прошла. При необходимости берите модуль или сортируйте даты перед расчётом.
Как учесть только рабочие дни между датами?
Стандартные функции вычитания считают календарные дни. Для рабочих дней нужен производственный календарь: в типовых конфигурациях используется регистр сведений с графиком работы, по которому запросом подсчитывают количество рабочих дней в интервале. Универсальной встроенной функции для этого нет.
Что важно запомнить
В коде даты вычитаются оператором «минус» с результатом в секундах — делите на 86400 для дней и отсекайте время через НачалоДня(). В запросах используйте РАЗНОСТЬДАТ с нужной единицей измерения. Всегда проверяйте заполненность дат и тестируйте расчёт на граничных случаях.