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

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

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

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

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

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

Как 1С хранит даты и почему вычитание даёт секунды

Тип «Дата» в платформе 1С содержит и календарную дату, и время с точностью до секунды. Когда вы пишете выражение ДатаОкончания - ДатаНачала, платформа возвращает число — количество секунд между двумя моментами. Никакой автоматической конвертации в дни не происходит.

Чтобы получить количество дней из секунд, результат делят на число секунд в сутках — 86400 (60 × 60 × 24). Пример:

bsl
РазностьСекунд = ДатаОкончания - ДатаНачала;
КоличествоДней = Цел(РазностьСекунд / 86400);

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

Функция РазностьДат из Библиотеки стандартных подсистем

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

Точное имя и состав параметров зависят от версии библиотеки, поэтому перед использованием откройте конфигуратор и найдите функцию через глобальный поиск по слову «РазностьДат». Типичный вызов выглядит так:

bsl
// Примерный синтаксис — уточните в своей версии БСП
ДнейПросрочки = ОбщегоНазначения.РазностьДат(ДатаОплаты, ТекущаяДатаСеанса(), "День");

Преимущество функций БСП в том, что они уже обрабатывают краевые случаи: пустые даты, перестановку аргументов, отрицательный результат. Если конфигурация не содержит БСП, функцию легко написать самостоятельно на основе вычитания и деления.

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

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

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

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

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

Разные единицы измерения ведут себя по-разному, и бездумное применение одного подхода ко всем задачам приводит к ошибкам в учётных данных.

Дни и календарные сутки

Для большинства хозяйственных расчётов (просрочка, срок доставки) подходит деление секунд на 86400 или РАЗНОСТЬДАТ с единицей ДЕНЬ. Различие появляется на границах: между 10:00 понедельника и 09:00 вторника — 23 часа, то есть 0 полных суток, но РАЗНОСТЬДАТ в днях может дать 1. Проверяйте поведение на тестовых данных с временем.

Месяцы и годы

Делить дни на 30 или 365 — грубая ошибка: месяцы имеют разную длину, а годы бывают високосными. Для расчёта полных месяцев и лет корректнее использовать функции работы с датами: ДобавитьМесяц(), Год(), Месяц(), День() и сравнение составляющих. Типовой алгоритм возраста: разность лет минус 1, если месяц и день рождения ещё не наступили в текущем году.

bsl
Процедура РассчитатьВозраст(ДатаРождения, НаДату)
	Лет = Год(НаДату) - Год(ДатаРождения);
	Если Месяц(НаДату) < Месяц(ДатаРождения)
		Или (Месяц(НаДату) = Месяц(ДатаРождения) И День(НаДату) < День(ДатаРождения)) Тогда
		Лет = Лет - 1;
	КонецЕсли;
КонецПроцедуры

Производственный календарь и рабочие дни

Частая бизнес-задача — посчитать не календарные, а рабочие дни между датами: сроки выполнения заказа, нормы выработки, кадровые расчёты. Простым вычитанием это не решается, потому что выходные и праздники нужно исключать.

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

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

Проверка результата и типичные ошибки

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

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

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

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

Результат равен 0

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

Результат 1 или отрицательное число

Даты с разным временем в пределах суток
Норма

Ожидаемое число полных дней по вашей логике

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

Скачок на единицу из-за границы суток

Пустая дата в одном из параметров
Норма

Расчёт пропущен или выдано понятное сообщение

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

Огромное число секунд или дней в отчёте

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

Отрицательный результат или обработанная ошибка

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

Молчаливый неверный положительный результат

Типичные ошибки
01
Считать, что вычитание дат даёт дни — на самом деле результат в секундах, и без деления на 86400 отчёты показывают огромные числа.
02
Делить дни на 30 для получения месяцев — из-за разной длины месяцев накапливается погрешность, критичная для стажа и процентов.
03
Игнорировать время в датах — документы обычно содержат время, и расчёт на границе суток ведёт себя неочевидно.
04
Не проверять заполненность дат — пустая дата даёт разность в сотни тысяч дней и ломает итоги отчёта.
05
Считать рабочие дни простым вычитанием — без производственного календаря выходные и праздники ошибочно включаются в срок.

Как выбрать подходящий способ

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

Маршрут решения

Как выбрать действие

Нужна разность в коде модуля между двумя конкретными датамиИспользуйте вычитание с делением на 86400 для дней или функцию РазностьДат из БСП
Расчёт нужен в отчёте или по большой выборке документовПрименяйте РАЗНОСТЬДАТ в тексте запроса — это быстрее перебора в цикле
Требуются рабочие, а не календарные дниИспользуйте производственный календарь и функции подсистемы КалендарныеГрафики
Нужен возраст или стаж в полных годахСчитайте через сравнение года, месяца и дня, а не делением дней на 365
Конфигурация самописная, без БСПНапишите собственную функцию в общем модуле с проверкой пустых дат и порядка аргументов

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

Итог

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

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

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

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

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

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

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

Что вернёт РАЗНОСТЬДАТ, если даты стоят в обратном порядке?

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

Как посчитать стаж или возраст в полных годах?

Вычтите год рождения из текущего года и уменьшите результат на единицу, если месяц и день рождения ещё не наступили в текущем году. Деление дней на 365 для этой задачи не подходит из-за високосных лет.

Можно ли использовать РАЗНОСТЬДАТ в условии ГДЕ запроса?

Да, функцию можно применять и в секции ГДЕ, и в условиях соединений. Это позволяет отбирать, например, только просроченные документы, не выгружая в код всю выборку. Учитывайте, что такие условия могут замедлять запрос на больших таблицах.

Что делать, если разность нужна в часах или минутах?

В коде разделите результат вычитания на 3600 для часов или на 60 для минут. В запросе передайте в РАЗНОСТЬДАТ единицу ЧАС или МИНУТА — функция вернёт число полных единиц между датами.