Разработка и Конфигурация · 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 или напишите собственную функцию в общем модуле.
Сравнение способов
Работает везде, без зависимостей. Ограничение: только дни и меньшие единицы, для месяцев и лет не подходит.
Удобна для дней, месяцев, кварталов и лет. Ограничение: требует внедрённой Библиотеки стандартных подсистем.
Считает на стороне СУБД, быстро на больших выборках. Ограничение: только внутри запроса, результат нельзя переиспользовать вне выборки.
Способ 3: функция РАЗНОСТЬДАТ в запросе
Когда разность дат нужна в отчёте или выборке, считать её в цикле по строкам результата — плохая идея: это медленно и загромождает код. В языке запросов есть встроенная функция:
ВЫБРАТЬ
Заказы.Ссылка КАК Заказ,
РАЗНОСТЬДАТ(Заказы.ДатаОтгрузки, Заказы.ДатаОплаты, ДЕНЬ) КАК ДнейОплаты
ИЗ
Документ.ЗаказПокупателя КАК Заказы
Синтаксис: РАЗНОСТЬДАТ(Дата1; Дата2; Единица), где единица — СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, МЕСЯЦ, КВАРТАЛ, ГОД. Функция возвращает количество полных единиц между датами. Разность между 31.01 и 01.02 в месяцах будет 0, а в днях — 1.
Если дата может быть пустой (значение 01.01.0001), результат будет огромным числом. Защититесь условием:
ВЫБОР
КОГДА Заказы.ДатаОплаты = ДАТАВРЕМЯ(1, 1, 1)
ТОГДА 0
ИНАЧЕ РАЗНОСТЬДАТ(Заказы.ДатаОтгрузки, Заказы.ДатаОплаты, ДЕНЬ)
КОНЕЦ КАК ДнейОплаты
РАЗНОСТЬДАТ(ДатаНачала, ДатаОкончания, ДЕНЬ) КАК КоличествоДнейРазность дат в СКД и вычисляемых полях
В системе компоновки данных разность дат обычно считается на уровне запроса набора данных — функцией РАЗНОСТЬДАТ, как показано выше. Это предпочтительный путь: вычисление выполняется один раз при формировании отчёта.
Если нужно посчитать дни от текущей даты (например, «дней до наступления срока»), в запросе используйте параметр &ТекущаяДата, который передаётся при формировании отчёта, или функцию ТекущаяДатаСеанса() в коде перед компоновкой. Прямой вызов текущей даты внутри текста запроса недоступен — только через параметр.
Для вычисляемых полей СКД доступен собственный язык выражений, но функции разности дат там ограничены. Надёжнее всегда выносить расчёт в запрос, а в СКД оставлять только группировки и оформление.
Учёт рабочих и календарных дней
Всё описанное выше считает календарные дни. Если задача — посчитать рабочие дни между датами (для производственных календарей, сроков доставки, кадровых расчётов), простой арифметики недостаточно: нужно обращаться к регистру сведений с производственным календарём.
В типовых конфигурациях для этого есть регистр сведений «Данные производственного календаря» (или аналогичный). Логика расчёта: запросом выбираются записи календаря в диапазоне дат с видом дня «Рабочий» и считается их количество. В БСП есть готовые функции в модулях работы с календарями — ищите их по слову «Календар» в составе подсистемы.
Самостоятельная реализация без производственного календаря (просто исключить субботу и воскресенье) даст ошибку на праздничных и перенесённых днях, которых в году бывает заметное количество. Для расчётов, влияющих на деньги и сроки, такой упрощённый подход неприемлем.
Типичные ошибки и как их избежать
Первая и самая частая ошибка — забыть про секунды и вывести в отчёт «сырую» разность дат. Пользователь видит число вроде 345600 вместо 4 дней. Признак проблемы: значения ровно в 86400 раз больше ожидаемых.
Вторая ошибка — неверная обработка границ. Вопрос «сколько дней с 1 по 5 марта» имеет два ответа: 4 (разность) или 5 (включительно обеих дат). Для включительного подсчёта добавьте единицу: Цел((НачалоДня(Дата2) - НачалоДня(Дата1)) / 86400) + 1. Какой вариант правильный — определяет предметная область: дни болезни считают включительно, дни просрочки — обычно разностью.
Третья группа ошибок — пустые даты. Пустая дата в 1С равна 01.01.0001, и разность с ней даёт миллионы дней, которые потом «взрывают» итоги отчёта. Всегда проверяйте ЗначениеЗаполнено() или сравнение с ДАТАВРЕМЯ(1,1,1) в запросе.
Проверка результата перед использованием
Любую функцию расчёта дат стоит проверить на контрольных примерах до того, как она попадёт в рабочие документы. Минимальный набор тестов: одинаковые даты (ожидается 0), соседние даты (1), переход через месяц (31.01 → 01.02 даёт 1 день), переход через год, високосный февраль (28.02 → 01.03 в високосный год даёт 2 дня).
Для запросов проверка делается через консоль запросов: выполните выборку по нескольким известным документам и сравните колонку с ручным подсчётом. Для функций в модулях удобно временно вывести результат через Сообщить() или проверить в отладчике.
Как проверить результат
Результат 0
1 или дробное число — не отсечено время
Результат 1
86400 — забыто деление на секунды
0 или пропуск строки
Число в сотни тысяч — нет проверки заполненности
1 день
Отрицательное или нулевое значение
Часто задаваемые вопросы
Как посчитать разность дат в днях, включая обе даты?
Добавьте единицу к обычной разности: Цел((НачалоДня(Дата2) - НачалоДня(Дата1)) / 86400) + 1. Такой подсчёт применяется, например, для больничных и отпусков, где первый и последний день входят в период.
Почему при вычитании дат получается огромное число?
Результат вычитания дат в 1С — секунды, а не дни. Разделите значение на 86400. Если число порядка миллионов даже после деления — скорее всего, одна из дат пустая (01.01.0001), добавьте проверку ЗначениеЗаполнено().
Как посчитать разность в месяцах или годах?
Делением на секунды это сделать нельзя — месяцы имеют разную длину. Используйте функцию РазностьДат из БСП с параметром «Месяц» или «Год», либо РАЗНОСТЬДАТ(Дата1; Дата2; МЕСЯЦ) в запросе. Обе функции считают полные календарные единицы.
Как получить количество рабочих дней между датами?
Нужен производственный календарь. В типовых конфигурациях это регистр сведений с видами дней; запросом подсчитываются записи с рабочими днями в нужном диапазоне. Простое исключение суббот и воскресений даст ошибку на праздниках и переносах.
Что делать, если даты хранятся с временем?
Примените функцию НачалоДня() к обеим датам перед вычитанием. Тогда время суток не повлияет на результат, и разность всегда будет целым числом календарных дней.
Можно ли посчитать разность дат прямо в отчёте СКД без изменения запроса?
Надёжнее всего добавить РАЗНОСТЬДАТ в запрос набора данных. В вычисляемых полях СКД язык выражений ограничен, и корректный расчёт календарных разностей там реализовать сложно. Расчёт на уровне запроса выполняется быстрее и прозрачнее для отладки.
Что важно запомнить
Вычитание дат в 1С даёт секунды — делите на 86400 для получения дней. В запросах используйте РАЗНОСТЬДАТ с единицей ДЕНЬ. Отсекайте время через НачалоДня, проверяйте пустые даты и заранее решите, нужен ли включительный подсчёт границ. Для рабочих дней применяйте производственный календарь, а не арифметику.