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

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

Как получить разницу между датами в 1С

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

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

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

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

Вычитание дат оператором «минус»: что получится на самом деле

Самый очевидный способ — вычесть одну дату из другой обычным оператором. Важно понимать, что результатом будет число секунд между датами, поскольку тип «Дата» в 1С всегда содержит и время.

ДатаНачала = '20260115093000';

ДатаОкончания = '20260120120000';

РазницаВСекундах = ДатаОкончания - ДатаНачала; // 441000 секунд

РазницаВДнях = РазницаВСекундах / 86400; // 5,104...

Чтобы получить целое число дней, результат делят на 86400 (количество секунд в сутках) и при необходимости отбрасывают дробную часть функцией Цел(). Однако такой подход даёт погрешность, если время в датах различается: интервал с 15 января 12:00 до 16 января 11:00 формально меньше суток, хотя календарно это разные дни.

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

Функция РазностьДат: разница в днях, месяцах и годах

Во встроенном языке 1С есть специальная функция РазностьДат(), которая возвращает разницу между двумя датами в указанной единице измерения. Это предпочтительный способ для вычислений в коде, потому что он корректно работает с месяцами и годами разной длины.

ДатаНачала = '20220310';

ДатаОкончания = '20260115';

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

Месяцев = РазностьДат(ДатаНачала, ДатаОкончания, "МЕСЯЦ");

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

В качестве третьего параметра указывается единица измерения: СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, МЕСЯЦ, КВАРТАЛ, ГОД (или английские синонимы SECOND, MINUTE, HOUR, DAY, MONTH, QUARTER, YEAR). Функция возвращает целое число — количество полных единиц между датами.

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

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

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

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

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

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

| РАЗНОСТЬДАТ(Заказы.ДатаОтгрузки, &ТекущаяДата, ДЕНЬ) КАК ДнейПросрочки

|ИЗ

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

|ГДЕ

| РАЗНОСТЬДАТ(Заказы.ДатаОтгрузки, &ТекущаяДата, ДЕНЬ) > 0";

Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДатаСеанса());

Синтаксис аналогичен встроенной функции: первые два параметра — даты, третий — единица измерения без кавычек (ДЕНЬ, МЕСЯЦ, ГОД и т.д.). Результат также целочисленный и отражает полные периоды.

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

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

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

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

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

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

Функция СтажТекстом(ДатаНачала, ДатаОкончания)

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

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

Месяцев = РазностьДат(ДатаПром, ДатаОкончания, "МЕСЯЦ");

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

Дней = РазностьДат(ДатаПром, ДатаОкончания, "ДЕНЬ");

Возврат СтрШаблон("%1 г. %2 мес. %3 дн.", Лет, Месяцев, Дней);

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

Имейте в виду, что в типовых конфигурациях (ЗУП, Бухгалтерия) уже есть готовые механизмы расчёта стажа с учётом требований законодательства. Прежде чем писать собственный алгоритм, проверьте наличие подходящих функций в общих модулях — самодельный расчёт может расходиться с официальной методикой.

Учёт времени и часовых поясов

Для задач вроде учёта длительности операций, SLA по заявкам или времени простоя оборудования разница нужна в часах и минутах. Здесь достаточно вычитания дат с последующим делением: часы — на 3600, минуты — на 60.

РазницаСекунд = ДатаОкончания - ДатаНачала;

ЧасовВсего = Цел(РазницаСекунд / 3600);

МинутОстаток = Цел((РазницаСекунд - ЧасовВсего * 3600) / 60);

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

Функция ТекущаяДатаСеанса() возвращает дату с учётом настроек сеанса, а ТекущаяДата() на клиенте — локальное время компьютера. Смешивание этих значений в одном вычислении — частый источник «съезжающих» интервалов. В серверном коде предпочтительна ТекущаяДатаСеанса().

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

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

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

Особое внимание уделите граничным случаям: даты с 29 февраля, интервалы с 31 числа по 30 число, пустые даты и даты с разным временем. Именно на таких данных расчёты чаще всего дают расхождения с ожиданиями пользователей.

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

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

Разница между 01.01 и 01.01 следующего года
Норма

Ровно 1 год или 12 месяцев

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

365/366 дней при запросе в годах или дробное значение

Интервал с 31.01 по 28.02
Норма

Осознанно выбранный результат: 0 или 1 месяц по методике

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

Результат не совпадает с регламентом расчёта

Даты с разным временем суток
Норма

Время отсечено НачалоДня() или учтено явно

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

Разница в днях «плавает» на единицу

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

Обработана проверкой ЗначениеЗаполнено()

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

Гигантское число дней попадает в отчёт

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

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

Отсеките время у обеих дат функцией НачалоДня(), затем либо используйте РазностьДат(НачалоДня(Дата1), НачалоДня(Дата2), "ДЕНЬ"), либо вычтите даты и разделите результат на 86400. Первый вариант читается понятнее и меньше подвержен ошибкам.

Почему вычитание дат возвращает огромное число вроде 86400?

Потому что результатом вычитания дат в 1С является количество секунд, а не дней. 86400 — это ровно одни сутки. Разделите результат на 86400, чтобы получить дни, или используйте функцию РазностьДат с нужной единицей измерения.

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

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

Что делать, если даты могут идти в обратном порядке?

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

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

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

Какая разница между ТекущаяДата() и ТекущаяДатаСеанса() при расчётах?

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

Итог

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

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