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

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

Как посчитать разность дат в днях в 1С

Как посчитать разность дат в днях в 1С: вычитание дат, функция РазностьДат, расчёт в запросах и СКД. Примеры кода, типичные ошибки и ответы на вопросы.

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

Главная ловушка для начинающих: при вычитании двух дат в 1С результат получается не в днях, а в секундах. Тип «Дата» в платформе хранит значение с точностью до секунды, поэтому простое выражение Дата2 - Дата1 вернёт число секунд между моментами времени. Чтобы получить дни, результат нужно разделить на количество секунд в сутках — 86400.

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

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

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

Поэтому базовая формула для получения дней выглядит так:

КоличествоДней = (ДатаОкончания - ДатаНачала) / 86400;

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

Важный нюанс: разность между 10.03 15:00 и 12.03 09:00 составит 1,75 дня. Округлять такое значение вверх или вниз — решение прикладной логики: для расчёта просрочки обычно берут целую часть, для начисления неустойки иногда округляют в большую сторону.

Способ 1: вычитание дат с делением на секунды

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

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

Если Не ЗначениеЗаполнено(ДатаНачала) Или Не ЗначениеЗаполнено(ДатаОкончания) Тогда

Возврат 0;

КонецЕсли;

Возврат Цел((НачалоДня(ДатаОкончания) - НачалоДня(ДатаНачала)) / 86400);

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

Обратите внимание на применение НачалоДня() к обеим датам. Это отсекает время и гарантирует, что разность между 01.03 и 05.03 всегда будет ровно 4 дня, независимо от того, в какое время суток создан документ. Без этого шага документ, проведённый в 23:59, и документ в 00:01 следующего дня могут дать неожиданный результат.

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

Способ 2: функция РазностьДат из БСП

В конфигурациях на базе Библиотеки стандартных подсистем (1С:Бухгалтерия, 1С:ERP, 1С:ЗУП, Управление торговлей) доступен программный интерфейс для работы с датами. В зависимости от версии БСП используется общий модуль ОбщегоНазначения или специализированные функции работы с датами.

Типовой вызов для расчёта разности в днях выглядит так:

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

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

Если конфигурация самописная и БСП не внедрена, этой функции не будет — используйте способ с делением на 86400 или напишите собственную функцию в общем модуле.

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

Деление на 86400

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

РазностьДат из БСП

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

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

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

Способ 3: функция РАЗНОСТЬДАТ в запросе

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

ВЫБРАТЬ

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

РАЗНОСТЬДАТ(Заказы.ДатаОтгрузки, Заказы.ДатаОплаты, ДЕНЬ) КАК ДнейОплаты

ИЗ

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

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

Если дата может быть пустой (значение 01.01.0001), результат будет огромным числом. Защититесь условием:

ВЫБОР

КОГДА Заказы.ДатаОплаты = ДАТАВРЕМЯ(1, 1, 1)

ТОГДА 0

ИНАЧЕ РАЗНОСТЬДАТ(Заказы.ДатаОтгрузки, Заказы.ДатаОплаты, ДЕНЬ)

КОНЕЦ КАК ДнейОплаты

1c-query
РАЗНОСТЬДАТ(ДатаНачала, ДатаОкончания, ДЕНЬ) КАК КоличествоДней

Разность дат в СКД и вычисляемых полях

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

Если нужно посчитать дни от текущей даты (например, «дней до наступления срока»), в запросе используйте параметр &ТекущаяДата, который передаётся при формировании отчёта, или функцию ТекущаяДатаСеанса() в коде перед компоновкой. Прямой вызов текущей даты внутри текста запроса недоступен — только через параметр.

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

Учёт рабочих и календарных дней

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

В типовых конфигурациях для этого есть регистр сведений «Данные производственного календаря» (или аналогичный). Логика расчёта: запросом выбираются записи календаря в диапазоне дат с видом дня «Рабочий» и считается их количество. В БСП есть готовые функции в модулях работы с календарями — ищите их по слову «Календар» в составе подсистемы.

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

Типичные ошибки и как их избежать

Первая и самая частая ошибка — забыть про секунды и вывести в отчёт «сырую» разность дат. Пользователь видит число вроде 345600 вместо 4 дней. Признак проблемы: значения ровно в 86400 раз больше ожидаемых.

Вторая ошибка — неверная обработка границ. Вопрос «сколько дней с 1 по 5 марта» имеет два ответа: 4 (разность) или 5 (включительно обеих дат). Для включительного подсчёта добавьте единицу: Цел((НачалоДня(Дата2) - НачалоДня(Дата1)) / 86400) + 1. Какой вариант правильный — определяет предметная область: дни болезни считают включительно, дни просрочки — обычно разностью.

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

Типичные ошибки
01
Забыли разделить на 86400 — в отчёте секунды вместо дней
02
Не отсекли время через НачалоДня — дробные дни и «плавающие» результаты
03
Не проверили пустую дату — гигантские числа ломают итоги
04
Перепутали включительный подсчёт с разностью — расхождение на 1 день
05
Считают рабочие дни вычитанием выходных вручную — ошибки на праздниках и переносах

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

Любую функцию расчёта дат стоит проверить на контрольных примерах до того, как она попадёт в рабочие документы. Минимальный набор тестов: одинаковые даты (ожидается 0), соседние даты (1), переход через месяц (31.01 → 01.02 даёт 1 день), переход через год, високосный февраль (28.02 → 01.03 в високосный год даёт 2 дня).

Для запросов проверка делается через консоль запросов: выполните выборку по нескольким известным документам и сравните колонку с ручным подсчётом. Для функций в модулях удобно временно вывести результат через Сообщить() или проверить в отладчике.

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

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

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

Результат 0

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

1 или дробное число — не отсечено время

Соседние даты 01.03 и 02.03
Норма

Результат 1

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

86400 — забыто деление на секунды

Пустая дата в данных
Норма

0 или пропуск строки

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

Число в сотни тысяч — нет проверки заполненности

Переход через месяц 31.01–01.02
Норма

1 день

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

Отрицательное или нулевое значение

Часто задаваемые вопросы

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

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

Почему при вычитании дат получается огромное число?

Результат вычитания дат в 1С — секунды, а не дни. Разделите значение на 86400. Если число порядка миллионов даже после деления — скорее всего, одна из дат пустая (01.01.0001), добавьте проверку ЗначениеЗаполнено().

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

Делением на секунды это сделать нельзя — месяцы имеют разную длину. Используйте функцию РазностьДат из БСП с параметром «Месяц» или «Год», либо РАЗНОСТЬДАТ(Дата1; Дата2; МЕСЯЦ) в запросе. Обе функции считают полные календарные единицы.

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

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

Что делать, если даты хранятся с временем?

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

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

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

Итог

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

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