Разработка и Конфигурация · 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, хотя календарно это разные дни. Если нужно считать именно календарные дни независимо от времени, даты предварительно приводят к началу дня функцией НАЧАЛОПЕРИОДА(Дата, ДЕНЬ).
Передавать параметр даты в запрос следует через &Параметр, а не конкатенацией строки текста запроса — это защищает от ошибок формата и упрощает поддержку кода.
Как посчитать разность в месяцах и годах корректно
Расчёт в месяцах и годах сложнее расчёта в днях, потому что месяцы имеют разную длину. Функции платформы считают полные месяцы и годы: между 15.01 и 14.02 полного месяца нет, и РАЗНОСТЬДАТ вернёт 0, хотя прошло 30 дней.
Для задач вроде расчёта стажа в формате «лет, месяцев, дней» обычно пишут последовательный алгоритм: сначала вычисляют полные годы, затем от оставшейся даты — полные месяцы, затем дни. Универсальной встроенной функции «разность в формате ГГ ММ ДД» в платформе нет.
Лет = РазностьДат(ДатаНачала, ДатаОкончания, ТипРазностиДат.Год);
ДатаПослеЛет = ДобавитьМесяц(ДатаНачала, Лет * 12);
Месяцев = РазностьДат(ДатаПослеЛет, ДатаОкончания, ТипРазностиДат.Месяц);
ДатаПослеМесяцев = ДобавитьМесяц(ДатаПослеЛет, Месяцев);
Дней = РазностьДат(ДатаПослеМесяцев, ДатаОкончания, ТипРазностиДат.День);
При таком подходе проверяйте граничные случаи: даты вроде 31.01 → 28.02, високосные годы, ситуации, когда день окончания меньше дня начала. Функция ДобавитьМесяц() корректно обрабатывает переход через конец месяца (31.01 + 1 месяц даст конец февраля), что упрощает алгоритм.
Для отчётов по просрочке задолженности удобнее считать разность в днях через РАЗНОСТЬДАТ с НАЧАЛОПЕРИОДА, а интервалы (1–30, 31–60, 61–90 дней) формировать конструкцией ВЫБОР КОГДА — так запрос работает быстрее, чем постобработка во встроенном языке.
Выбор способа: встроенный язык или запрос
Если данные уже получены из базы и обрабатываются в коде — используйте РазностьДат() или вычитание с делением. Если разность нужна как поле выборки из большой таблицы (например, «дней просрочки» для тысяч документов), вычисляйте её прямо в запросе через РАЗНОСТЬДАТ: это сокращает объём передаваемых данных и упрощает код.
Сравнение вариантов
Подходит для быстрых расчётов в днях в коде. Ограничение: даёт дробный результат при наличии времени, требует ручного округления
Универсальный вариант в коде, поддерживает все единицы от секунд до лет. Ограничение: недоступна в платформах ниже 8.3.6
Оптимальна для выборок и отчётов, вычисляется на уровне СУБД. Ограничение: только целые полные единицы, нельзя получить дробное значение
В типовых конфигурациях также встречаются готовые функции общих модулей, например процедуры расчёта стажа в кадровых библиотеках. Перед написанием собственного алгоритма проверьте, нет ли подходящей функции в общих модулях вашей конфигурации — это сэкономит время и уменьшит риск расхождений с типовой логикой.
Проверка результата и граничные случаи
Любой алгоритм расчёта разности дат стоит проверить на контрольных примерах до использования в рабочей базе. Особое внимание уделите ситуациям, где легко получить ошибку на одну единицу.
Как проверить результат
Разность равна 0 в любых единицах
Отрицательное значение или 1 — ошибка в порядке аргументов или округлении
Разность в днях равна 1
0 или 2 — проблема с учётом времени или границ периода
В месяцах — 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С возвращает секунды. Для расчёта в днях, месяцах и годах используйте РазностьДат() в коде и РАЗНОСТЬДАТ() в запросах, помня, что обе считают полные единицы. Проверяйте порядок аргументов, пустые даты и влияние времени на результат.