К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как отнять дату от даты в 1С

Как вычесть дату из даты в 1С: оператор минус, функция РазностьДат, запросы РАЗНОСТЬДАТ, расчёт месяцев и дней. Примеры кода, ошибки и проверка результата.

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

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

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

Как устроен тип «Дата» и почему вычитание даёт секунды

В 1С значение типа «Дата» хранит момент времени с точностью до секунды: год, месяц, день, часы, минуты, секунды. Когда вы пишете Результат = ДатаОкончания - ДатаНачала;, платформа возвращает число — количество секунд между двумя моментами. Это не дни и не месяцы, и именно здесь возникает первая типичная ошибка.

Например, вычитание двух дат, отличающихся на одни сутки, даст число 86400. Если эту величину вывести пользователю как «количество дней», отчёт покажет бессмысленное значение. Чтобы получить дни, результат нужно разделить на число секунд в сутках:

РазностьВСекундах = ДатаОкончания - ДатаНачала;

КоличествоДней = РазностьВСекундах / 86400; // 60 60 24

Обратная операция тоже работает: к дате можно прибавить число секунд и получить новую дату. Выражение НоваяДата = ТекущаяДата + 7 * 86400; сдвинет дату на неделю вперёд. Это удобно для точных интервалов, но не подходит для месяцев и лет, потому что их длина в секундах непостоянна.

Вычитание дат в коде: дни, часы и минуты

Базовый сценарий — посчитать целое число дней между двумя датами. Здесь есть тонкость: если даты содержат время, деление на 86400 даст дробное число. Для получения целых суток используйте функцию Цел() или предварительно отсеките время функцией НачалоДня():

ДнейМежду = Цел((НачалоДня(ДатаОкончания) - НачалоДня(ДатаНачала)) / 86400);

Такой вариант корректно считает «календарные» дни: разница между 10.03 23:50 и 11.03 00:10 составит 1 день, хотя фактически прошло 20 минут. Если нужна именно фактическая длительность, отсекать время не следует — округлите результат деления по правилам задачи.

Для часов и минут логика аналогична: делите разность в секундах на 3600 или на 60. Дробный остаток удобно получать оператором % (остаток от деления), чтобы разложить интервал на составляющие, например «2 дня 5 часов 30 минут».

Порядок расчёта разности в днях
  1. 1
    Проверьте, что обе даты заполнены: ЗначениеЗаполнено() для каждой
  2. 2
    Определите, нужны календарные сутки или фактическая длительность
  3. 3
    Для календарных суток примените НачалоДня() к обеим датам
  4. 4
    Вычтите даты и разделите результат на 86400
  5. 5
    Округлите через Цел() или Окр() по правилам вашей задачи
  6. 6
    Проверьте результат на контрольном примере с известным ответом

Разность в месяцах и годах: почему простым вычитанием не обойтись

Месяц — нефиксированная величина: от 28 до 31 дня. Поэтому оператор «минус» для месяцев не существует, а деление секунд на условные «30 дней» даёт погрешность, недопустимую в кадровых и финансовых расчётах. Для стажа, возраста и сроков действия договоров нужен другой подход.

Классический приём — цикл с функцией ДобавитьМесяц(): увеличиваем начальную дату на месяц, пока не превысим конечную, и считаем итерации. Функция корректно обрабатывает конец месяца: ДобавитьМесяц(Дата(2026,1,31), 1) вернёт последний день февраля, а не несуществующее 31 февраля.

Функция МесяцевМеждуДатами(ДатаНачала, ДатаОкончания)

Счетчик = 0;

Пока ДобавитьМесяц(ДатаНачала, Счетчик + 1) <= ДатаОкончания Цикл

Счетчик = Счетчик + 1;

КонецЦикла;

Возврат Счетчик;

КонецФункции

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

Разность дат в запросах: РАЗНОСТЬДАТ и ДОБАВИТЬКДАТЕ

Когда данные нужно выбирать из базы пакетно — например, посчитать просрочку по тысяче накладных, — вычисления в цикле по выборке неэффективны. Язык запросов 1С предоставляет встроенные функции дат, которые выполняются на стороне СУБД.

Функция РАЗНОСТЬДАТ(Дата1, Дата2, Единица) возвращает разность в заданных единицах: СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, МЕСЯЦ, КВАРТАЛ, ГОД. Это избавляет от ручного деления и циклов:

ВЫБРАТЬ

Реализация.Ссылка КАК Документ,

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

ИЗ

Документ.РеализацияТоваровУслуг КАК Реализация

ГДЕ

РАЗНОСТЬДАТ(Реализация.ДатаОплаты, &ТекущаяДата, ДЕНЬ) > 0

Обратная функция — ДОБАВИТЬКДАТЕ(Дата, Единица, Количество) — сдвигает дату на заданное число единиц, в том числе на месяцы и годы, что в запросе невозможно сделать арифметикой. Отрицательное количество работает как вычитание: ДОБАВИТЬКДАТЕ(&Дата, МЕСЯЦ, -3) отнимет три месяца.

Учтите особенность РАЗНОСТЬДАТ: она считает полные единицы. Разность между 31 января и 1 февраля в единицах МЕСЯЦ равна нулю, хотя в днях это 1. Для смешанной логики «месяцы плюс остаток дней» придётся комбинировать несколько вызовов функции.

Сравнение способов вычитания дат

Оператор минус (Дата1 - Дата2)

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

РАЗНОСТЬДАТ в запросе

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

ДобавитьМесяц в цикле

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

Типовые функции БСП/ЗУП

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

Вычитание дат в СКД и отчётах

В системе компоновки данных разность дат чаще всего считается на уровне запроса набора данных — той же функцией РАЗНОСТЬДАТ. Поле с разностью затем выводится как ресурс или группировка. Это самый производительный вариант: расчёт выполняется один раз при формировании отчёта.

Если разность нужно вычислить на уровне вычисляемого поля СКД, доступны функции языка выражений компоновки, но их набор ограничен. Сложную логику — например, «полных месяцев и остаток дней» — лучше выносить в запрос или во временную таблицу, рассчитанную кодом перед компоновкой.

Типичный сценарий — отчёт по дебиторской задолженности с группировкой по срокам давности: до 30 дней, 30–60, свыше 60. Такую группировку реализуют через вычисляемое поле с конструкцией ВЫБОР по значению РАЗНОСТЬДАТ, а не через пользовательские поля, чтобы сохранить производительность на больших объёмах.

Если отчёт с РАЗНОСТЬДАТ тормозит, проверьте, не вычисляется ли функция в условии ГДЕ по неиндексированному выражению. Часто быстрее сначала поместить документы во временную таблицу с отбором по диапазону дат, а разность считать уже в финальном запросе по сокращённому набору.
ПЗ
Практическое замечание

Частые ошибки и как проверить результат

Первая ошибка — забыть, что вычитание возвращает секунды, и вывести их как дни. Вторая — не обработать пустые даты: документ без даты оплаты даст разность в сотни тысяч лет и «сломает» итоги отчёта. Третья — перепутать порядок операндов и получить отрицательные значения там, где бизнес-логика ожидает положительные.

Отдельная группа проблем — время в датах. Дата документа в 1С почти всегда содержит время, поэтому РАЗНОСТЬДАТ(НачалоДня(Дата), КонецДня(Дата), ДЕНЬ) даст 0, а не 1. Если по логике задачи «сегодня» должно считаться одним днём, добавляйте единицу или пересматривайте формулу.

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

Типичные ошибки
01
Вывод секунд как дней без деления на 86400 — в отчётах появляются огромные числа
02
Игнорирование пустых дат — разность с 01.01.0001 искажает средние и итоги
03
Расчёт месяцев делением дней на 30 — накапливается ошибка в стаже и сроках
04
Перепутанный порядок операндов — отрицательная просрочка проходит проверки как 'нет долга'
05
Сравнение дат со временем, когда нужны календарные сутки — граничные документы выпадают из выборки
Контрольные точки

Как проверить результат

Разность соседних дат одного дня
Норма

Ровно 86400 секунд или 1 день

Тревожный признак

Дробное или отличное значение — значит, в датах есть время

Пустая дата в одном из операндов
Норма

Расчёт пропускается или выдаёт NULL/ноль по правилам задачи

Тревожный признак

Гигантское число секунд попадает в итоги

Переход через конец месяца (31.01 → 01.02)
Норма

1 день, 0 полных месяцев

Тревожный признак

1 месяц при расчёте делением на 30

Обратный порядок дат
Норма

Отрицательное значение или явная обработка

Тревожный признак

Молчаливый неверный знак в отчёте

FAQ: частые вопросы о вычитании дат в 1С

Как получить разность дат именно в днях, а не секундах?

Разделите результат вычитания на 86400 — число секунд в сутках. Если даты содержат время и нужны календарные сутки, сначала примените НачалоДня() к обеим датам, затем вычтите и поделите. В запросе используйте РАЗНОСТЬДАТ(Дата1, Дата2, ДЕНЬ) — она сразу возвращает дни.

Можно ли вычесть из даты месяц или год оператором «минус»?

Нет, арифметика дат работает только в секундах. Для сдвига на месяцы и годы используйте ДобавитьМесяц() в коде (отрицательный аргумент отнимает месяцы) или ДОБАВИТЬКДАТЕ с отрицательным количеством в запросе. Эти функции корректно обрабатывают разную длину месяцев.

Что будет, если вычесть из большей даты меньшую наоборот?

Получится отрицательное число секунд. Платформа не выдаст ошибку, поэтому порядок операндов контролирует разработчик. Если по смыслу разность не может быть отрицательной, добавьте проверку или используйте Макс() для нормализации результата.

Как посчитать возраст или стаж в полных годах?

Для регламентированных расчётов используйте типовые функции конфигурации (в ЗУП и БСП они есть). Самостоятельно логика строится так: разность годов минус поправка, если месяц и день конечной даты меньше месяца и дня начальной. Делить дни на 365 нельзя — из-за високосных лет накапливается ошибка.

Почему РАЗНОСТЬДАТ между сегодня и завтра в месяцах даёт 0 или 1 неожиданным образом?

Функция считает полные единицы между датами, а не пересечённые границы календаря. Между 31 января и 1 февраля нет полного месяца, поэтому результат — 0. Если нужна логика «число месяцев, которых коснулся период», комбинируйте РАЗНОСТЬДАТ с НАЧАЛОПЕРИОДА и добавляйте единицу.

Как вычесть даты в управляемой форме без обращения к серверу?

Простое вычитание и деление на 86400 выполняется и на клиенте — это обычная арифметика. Но если расчёт требует данных из базы или типовых функций общих модулей, выносите его в серверную процедуру. Для полей ввода дат на форме часто достаточно клиентского пересчёта в обработчике ПриИзменении.

Итог

Что важно запомнить

Вычитание дат оператором «минус» даёт секунды — для дней делите на 86400. Месяцы и годы считайте через ДобавитьМесяц, РАЗНОСТЬДАТ или типовые функции конфигурации. Всегда проверяйте заполненность дат, порядок операндов и наличие времени в значениях. Для кадровых и регламентированных расчётов применяйте только штатные механизмы конфигурации.