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

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

Как отнять дату в 1С: способы вычитания дат и расчёта разности

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

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

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

Ниже разобраны все рабочие способы с примерами кода, особенностями поведения платформы и типичными ошибками, которые приводят к неверным расчётам.

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

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

ДатаНачала = '20260101';

ДатаОкончания = '20260115';

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

РазностьВДнях = РазностьВСекундах / 86400; // 14

Число 86400 — это количество секунд в сутках (60 × 60 × 24). Если нужны часы, делите на 3600, если минуты — на 60. Для получения целого числа дней при наличии времени в датах используйте функцию Цел(), чтобы отбросить дробную часть.

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

Как отнять от даты дни, месяцы и годы

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

Вычитание дней и часов

Для сдвига на дни умножьте количество дней на 86400 и вычтите из исходной даты:

НоваяДата = ТекущаяДата - 7 * 86400; // неделей раньше

ДатаПоЧасам = ТекущаяДата - 5 * 3600; // на 5 часов раньше

Вычитание месяцев функцией ДобавитьМесяц

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

ДатаТриМесяцаНазад = ДобавитьМесяц(ТекущаяДата, -3);

ДатаГодНазад = ДобавитьМесяц(ТекущаяДата, -12);

Особый случай — вычитание месяца из даты вроде 31 марта. Функция ДобавитьМесяц вернёт последний день февраля (28 или 29 число), а не несуществующее 31 февраля. Это штатное поведение платформы, и его нужно учитывать, если дальше вы снова прибавляете месяц и ожидаете вернуться к 31 числу — обратного перехода не произойдёт.

Расчёт разности в днях, месяцах и годах в коде

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

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

РазностьМесяцев = (Год(Дата2) - Год(Дата1)) * 12

+ Месяц(Дата2) - Месяц(Дата1);

Если День(Дата2) < День(Дата1) Тогда

РазностьМесяцев = РазностьМесяцев - 1;

КонецЕсли;

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

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

bsl
ДнейПросрочки = Цел((ТекущаяДатаСеанса() - Документ.ДатаОплаты) / 86400);
Если ДнейПросрочки > 0 Тогда
    Сообщить("Просрочка: " + ДнейПросрочки + " дн.");
КонецЕсли;

Вычитание дат в запросах: функция РАЗНОСТЬДАТ

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

ВЫБРАТЬ

РАЗНОСТЬДАТ(Заказ.Дата, &ТекущаяДата, ДЕНЬ) КАК ДнейСЗаказа,

РАЗНОСТЬДАТ(Заказ.Дата, &ТекущаяДата, МЕСЯЦ) КАК МесяцевСЗаказа

ИЗ

Документ.ЗаказПокупателя КАК Заказ

В качестве единицы измерения допустимы СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, МЕСЯЦ, КВАРТАЛ, ГОД. Функция считает полные единицы: разность между 31 января и 1 февраля в месяцах равна нулю, хотя прошли сутки. Это важно при расчёте стажа и сроков — «календарный» и «полный» месяц здесь не совпадают.

Текущую дату лучше передавать в запрос параметром, а не вызывать функции текущей даты внутри текста запроса — так запрос предсказуемее и проще тестируется. Параметр устанавливается перед выполнением: Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДатаСеанса()).

Сравнение способов

Оператор «минус» в коде

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

ДобавитьМесяц с минусом

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

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

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

Типичные ошибки при вычитании дат

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

Вторая ошибка — игнорирование времени внутри даты. Например, документ проведён 10 марта в 14:30, а сравнивается с датой 10 марта 00:00:00. Разность в днях через Цел() даст 0, хотя визуально даты «одинаковые», а при сравнении на равенство даты окажутся разными. Для сравнения только календарных дат используйте НачалоДня() к обоим значениям.

Третья группа ошибок связана с пустыми датами. Пустая дата в 1С — это 01.01.0001 00:00:00. Вычитание из неё реальной даты даст огромное отрицательное число, а разность «как бы просрочки» — тысячи дней. Перед расчётом проверяйте дату на заполненность: Если ЗначениеЗаполнено(ДатаОплаты) Тогда.

Типичные ошибки
01
Сравнение результата вычитания с числом дней без деления на 86400 — условие срабатывает неверно
02
Расчёт месяцев через 30 дней в секундах — накопительная ошибка сдвигает дату
03
Игнорирование времени в дате — сравнение «одинаковых» дат возвращает ложь
04
Отсутствие проверки на пустую дату — в отчёт попадают огромные значения просрочки
05
Использование ТекущаяДата() на сервере вместо ТекущаяДатаСеанса() — риск расхождения часовых поясов

Проверка результата и граничные случаи

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

Особое внимание уделите границам: первая и последняя секунды суток, 29 февраля, 31-е число при сдвиге на месяц назад, даты вокруг полуночи. Именно на таких значениях всплывают ошибки округления и неверной обработки времени.

Если результат используется в регламентных расчётах (начисление пени, расчёт стажа, сроки хранения), зафиксируйте логику в комментариях к коду и согласуйте методику с постановщиком задачи: считать ли день начала и день окончания включительно, что считать полным месяцем. Разные методики дают разные числа, и «правильный» ответ определяется требованиями учёта, а не платформой.

Контрольные точки

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

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

86400 секунд или 1 день после деления

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

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

ДобавитьМесяц от 31 марта с шагом -1
Норма

Последний день февраля

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

Ошибка или 31 февраля — такого быть не должно

Расчёт с пустой датой
Норма

Ветка кода не выполняется благодаря проверке заполненности

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

Огромные значения просрочки в отчёте

Частые вопросы

В каких единицах возвращается результат вычитания дат в 1С?

Результат вычитания двух значений типа Дата — это число секунд между ними. Чтобы получить минуты, часы или дни, разделите результат на 60, 3600 или 86400 соответственно. Для получения целых дней примените функцию Цел().

Как отнять от даты один месяц?

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

Почему разность дат в запросе в месяцах равна нулю, хотя прошло 30 дней?

Функция РАЗНОСТЬДАТ считает только полные единицы. Если между датами не прошло полного календарного месяца по её логике, результат будет нулевым. Для таких случаев считайте разность в днях и при необходимости делите в коде.

Как сравнить две даты без учёта времени?

Приведите обе даты к началу дня функцией НачалоДня() и затем сравнивайте. В запросе аналогичного эффекта добиваются через НАЧАЛОПЕРИОДА(Дата, ДЕНЬ). Это исключает влияние времени документов на результат сравнения.

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

Ошибки не будет — результатом станет отрицательное число секунд. Это удобно для определения просрочки: отрицательное значение означает, что срок ещё не наступил, положительное — что дата уже прошла.

Итог

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

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