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

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

Как вычислить разность дат в 1С

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

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

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

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

Что возвращает обычное вычитание дат в 1С

Если написать выражение Дата2 - Дата1, где оба операнда имеют тип «Дата», результатом будет число — количество секунд между моментами времени. Это следует из того, что дата в 1С хранится с точностью до секунды, и арифметика с датами работает именно на этом уровне.

РазностьСекунд = Дата2 - Дата1; // число секунд

РазностьДней = (Дата2 - Дата1) / 86400; // дней может быть дробным

Чтобы получить целое число дней, результат делят на 86400 (60 × 60 × 24). Однако здесь есть нюанс: если даты содержат ненулевое время, деление даст дробное значение. Например, разница между 01.03 12:00 и 03.03 00:00 составит 1,5 дня. Для получения целых календарных дней применяют функцию Цел() или предварительно отсекают время функцией НачалоДня().

Функция РазностьДат во встроенном языке

Штатный способ вычисления разности во встроенном языке — функция РазностьДат(<Дата1>, <Дата2>, <ТипРазности>). Она возвращает разность между второй и первой датой в указанных единицах. Третий параметр задаётся значением системного перечисления ТипРазностиДат.

Значение ТипРазностиДатЧто возвращает
СекундаРазность в секундах
МинутаРазность в минутах
ЧасРазность в часах
ДеньРазность в днях
МесяцРазность в полных месяцах
КварталРазность в кварталах
ГодРазность в полных годах

Пример использования для расчёта возраста или стажа:

КоличествоДней = РазностьДат(ДатаНачала, ДатаОкончания, ТипРазностиДат.День);

ПолныхЛет = РазностьДат(ДатаРождения, ТекущаяДатаСеанса(), ТипРазностиДат.Год);

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

Функция РАЗНОСТЬДАТ в языке запросов

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

ВЫБРАТЬ

Заказ.Ссылка КАК Заказ,

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

ИЗ

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

Важная особенность: РАЗНОСТЬДАТ считает именно полные единицы. Разница между 31.01 и 01.03 в месяцах даст 1, а разница между 15.01 23:00 и 16.01 01:00 в днях — 0, хотя календарно это разные дни. Если нужно считать именно календарные дни независимо от времени, даты предварительно приводят к началу дня функцией НАЧАЛОПЕРИОДА(Дата, ДЕНЬ).

Передавать параметр даты в запрос следует через &Параметр, а не конкатенацией строки текста запроса — это защищает от ошибок формата и упрощает поддержку кода.

Типичные ошибки
01
Перепутан порядок дат в РАЗНОСТЬДАТ — результат получается отрицательным, и условие «просрочка больше нуля» никогда не срабатывает
02
Ожидание дробного результата: РАЗНОСТЬДАТ всегда возвращает целое число полных единиц, «хвост» отбрасывается
03
Сравнение дат со временем без приведения к началу дня — документ за 23:59 попадает в «завтрашний» расчёт
04
Использование РазностьДат в старой платформе ниже 8.3.6 — код выдаёт ошибку «Процедура или функция не определена»

Как посчитать разность в месяцах и годах корректно

Расчёт в месяцах и годах сложнее расчёта в днях, потому что месяцы имеют разную длину. Функции платформы считают полные месяцы и годы: между 15.01 и 14.02 полного месяца нет, и РАЗНОСТЬДАТ вернёт 0, хотя прошло 30 дней.

Для задач вроде расчёта стажа в формате «лет, месяцев, дней» обычно пишут последовательный алгоритм: сначала вычисляют полные годы, затем от оставшейся даты — полные месяцы, затем дни. Универсальной встроенной функции «разность в формате ГГ ММ ДД» в платформе нет.

Лет = РазностьДат(ДатаНачала, ДатаОкончания, ТипРазностиДат.Год);

ДатаПослеЛет = ДобавитьМесяц(ДатаНачала, Лет * 12);

Месяцев = РазностьДат(ДатаПослеЛет, ДатаОкончания, ТипРазностиДат.Месяц);

ДатаПослеМесяцев = ДобавитьМесяц(ДатаПослеЛет, Месяцев);

Дней = РазностьДат(ДатаПослеМесяцев, ДатаОкончания, ТипРазностиДат.День);

При таком подходе проверяйте граничные случаи: даты вроде 31.01 → 28.02, високосные годы, ситуации, когда день окончания меньше дня начала. Функция ДобавитьМесяц() корректно обрабатывает переход через конец месяца (31.01 + 1 месяц даст конец февраля), что упрощает алгоритм.

Для отчётов по просрочке задолженности удобнее считать разность в днях через РАЗНОСТЬДАТ с НАЧАЛОПЕРИОДА, а интервалы (1–30, 31–60, 61–90 дней) формировать конструкцией ВЫБОР КОГДА — так запрос работает быстрее, чем постобработка во встроенном языке.
ПЗ
Практическое замечание

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

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

Сравнение вариантов

Вычитание дат и деление на 86400

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

РазностьДат() во встроенном языке

Универсальный вариант в коде, поддерживает все единицы от секунд до лет. Ограничение: недоступна в платформах ниже 8.3.6

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

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

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

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

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

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

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

Одинаковые даты
Норма

Разность равна 0 в любых единицах

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

Отрицательное значение или 1 — ошибка в порядке аргументов или округлении

Соседние дни без времени (01.03 и 02.03)
Норма

Разность в днях равна 1

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

0 или 2 — проблема с учётом времени или границ периода

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

В месяцах — 1, в днях — 29 или 30 в зависимости от года

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

Значение в месяцах 2 — вероятно, считаются начатые, а не полные месяцы

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

Отрицательное число, которое код обрабатывает явно

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

Отрицательное значение попадает в отчёт как корректное

Отдельно проверьте поведение при пустых датах: значение '00010101' (пустая дата) в расчёте даст огромную разность, которая «по-тихому» исказит отчёт. Перед вычислением добавляйте проверку ЗначениеЗаполнено(Дата) или условие Дата <> ДАТАВРЕМЯ(1,1,1) в запросе.

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

Почему РАЗНОСТЬДАТ между соседними датами возвращает 0?

Потому что функция считает полные единицы. Если даты содержат время, например 01.03 18:00 и 02.03 09:00, полного дня между ними нет. Приведите обе даты к началу дня через НАЧАЛОПЕРИОДА(Дата, ДЕНЬ) и повторите расчёт.

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

Добавьте к результату единицу: РазностьДат(Дата1, Дата2, ТипРазностиДат.День) + 1. Так считают, например, длительность отпуска, когда и первый, и последний день входят в период.

Функция РазностьДат не найдена — в чём причина?

Функция появилась в платформе 8.3.6. Если конфигурация работает на более ранней версии или в режиме совместимости с ограничениями, используйте вычитание дат с делением на 86400 или функции из общих модулей конфигурации.

Можно ли вычислить разность дат в СКД без запроса?

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

Как посчитать только рабочие дни между датами?

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

Почему при пустой дате отчёт показывает огромные числа?

Пустая дата равна 01.01.0001, поэтому разность с текущей датой составляет сотни тысяч дней. Добавьте в запрос условие на заполненность даты или оберните вычисление в ВЫБОР КОГДА Дата = ДАТАВРЕМЯ(1,1,1) ТОГДА 0.

Итог

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

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