Разработка и Конфигурация · 10 мин
Как в 1С получить разницу между датами
Как в 1С получить разницу дат в днях, месяцах, годах: функция РазностьДат в запросе, вычитание дат в коде, типовые ошибки и примеры для разработчика.
Задача вычислить разницу между двумя датами встречается в 1С постоянно: посчитать стаж сотрудника, определить просрочку по договору, рассчитать возраст товара на складе или число дней до окончания гарантии. В зависимости от контекста — код на встроенном языке или запрос — используются разные инструменты, и у каждого есть свои ограничения.
Главное, что нужно понимать сразу: встроенный язык 1С не имеет отдельной функции «разница в месяцах» или «разница в годах». Простое вычитание дат даёт результат в секундах, а всё остальное приходится пересчитывать. В языке запросов, наоборот, есть штатная функция РАЗНОСТЬДАТ, но она работает только внутри запроса и не всегда доступна в произвольных выражениях СКД.
Ниже разобраны оба способа с примерами кода, типичными ошибками и рекомендациями, какой вариант выбрать в конкретной ситуации.
Разница дат встроенным языком: вычитание и секунды
Самый простой способ — вычесть одну дату из другой оператором «минус». Результатом будет число секунд между моментами времени. Это частая ловушка для начинающих: разработчик ожидает дни, а получает большое число вроде 2592000.
Чтобы перевести результат в нужные единицы, используйте деление:
РазницаВСекундах = ДатаОкончания - ДатаНачала;
РазницаВДнях = РазницаВСекундах / 86400; // 86400 = 60 60 24
РазницаВЧасах = РазницаВСекундах / 3600;
Обратите внимание: если даты содержат время (а в 1С тип «Дата» всегда хранит время с точностью до секунды), результат деления будет дробным. Например, разница между 10.03 15:00 и 12.03 09:00 даст 1,75 дня. Если нужны целые календарные дни, предварительно отсечь время функцией НачалоДня():
ДнейМежду = (НачалоДня(ДатаОкончания) - НачалоДня(ДатаНачала)) / 86400;
Такой подход корректно считает дни, но не подходит для месяцев и лет: месяцы имеют разную длину, и делить на 30 или 30,44 — значит получать приблизительный результат, неприемлемый для кадровых и финансовых расчётов.
Функция РАЗНОСТЬДАТ в языке запросов
В языке запросов 1С есть штатная функция, которая решает задачу напрямую. Синтаксис:
РАЗНОСТЬДАТ(ДатаНачала, ДатаОкончания, ЕдиницаИзмерения)
Третий параметр задаёт единицу результата: СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, МЕСЯЦ, ГОД. Функция возвращает целое число — количество полных единиц между датами.
ВЫБРАТЬ
Сотрудники.Ссылка КАК Сотрудник,
РАЗНОСТЬДАТ(Сотрудники.ДатаРождения, &ТекущаяДата, ГОД) КАК Возраст,
РАЗНОСТЬДАТ(Сотрудники.ДатаПриема, &ТекущаяДата, ДЕНЬ) КАК СтажВДнях
ИЗ
Справочник.Сотрудники КАК Сотрудники
Важная особенность: РАЗНОСТЬДАТ считает именно полные единицы. Между 31.01 и 01.03 разница в месяцах равна 1, хотя прошло 30 дней — чуть меньше «календарного» месяца. Между 15.06.2000 и 14.06.2010 разница в годах — 9, а не 10, потому что десятый год ещё не завершился.
Если дата начала больше даты окончания, функция вернёт отрицательное значение. Это удобно для определения просрочки: отрицательный результат по дате оплаты означает, что срок ещё не наступил.
РазницаДней = РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, ДЕНЬ)Как посчитать месяцы и годы в коде без запроса
Если запрос недоступен или неудобен (например, расчёт идёт в цикле по строкам табличной части), месяцы и годы вычисляют комбинацией стандартных функций работы с датами.
Базовый приём для полных месяцев — сравнение годов и месяцев с поправкой на день:
Функция МесяцевМеждуДатами(Дата1, Дата2) Экспорт
Месяцев = (Год(Дата2) - Год(Дата1)) * 12 + (Месяц(Дата2) - Месяц(Дата1));
Если День(Дата2) < День(Дата1) Тогда
Месяцев = Месяцев - 1;
КонецЕсли;
Возврат Месяцев;
КонецФункции
Для лет логика аналогична: из разницы годов вычитается единица, если месяц-день конечной даты раньше начальной. Именно так считается возраст человека или полный стаж.
Альтернатива — функция ДобавитьМесяц() в цикле: прибавляйте по месяцу к начальной дате, пока не превысите конечную. Способ медленнее, но наглядно показывает границы периодов и удобен, когда нужно не только число, но и перечень месяцев (например, для графика платежей).
Разница дат в СКД и произвольных выражениях
В схеме компоновки данных функция РАЗНОСТЬДАТ доступна только в тексте самого запроса набора данных. В вычисляемых полях и выражениях ресурсов СКД она не работает — там действует ограниченный набор функций языка выражений компоновки.
Практическое решение: вычисляйте разницу дат на уровне запроса набора данных и передавайте в СКД уже готовое числовое поле. Если разница должна зависеть от параметра отчёта (например, «на дату, указанную пользователем»), передайте её параметром в запрос:
РАЗНОСТЬДАТ(Заказы.ДатаОтгрузки, &ПериодОтчета, ДЕНЬ) КАК ДнейПросрочки
Если запрос изменить нельзя (типовой отчёт без снятия с поддержки), остаётся вариант с вычисляемым полем через функции общего модуля: в выражении СКД можно вызвать функцию из общего модуля с признаком «Сервер», которая выполнит нужный расчёт. Учтите, что такой вызов выполняется для каждой строки и может замедлить отчёт на больших выборках.
Сравнение вариантов
Подходит для дней, часов, секунд. Просто и быстро, но не даёт корректных месяцев и лет.
Оптимально для отчётов и выборок: любые единицы, выполняется на сервере СУБД. Недоступна вне запроса.
Для расчётов в коде, где нужны полные месяцы и годы без запроса. Требует аккуратной обработки дней.
Запасной вариант для типовых отчётов. Медленнее и требует серверного общего модуля.
Типичные ошибки и как их проверить
Первая ошибка — забыть про время в составе даты. Две даты одного календарного дня, но с разным временем, дают разницу меньше суток, и сравнение «равно 1 день» не срабатывает. Приводите даты к началу дня перед сравнением и вычитанием.
Вторая — перепутанный порядок аргументов РАЗНОСТЬДАТ. Первым идёт начальная дата, вторым конечная. При обратном порядке вы получите отрицательные числа, что в отчёте о просрочке перевернёт картину: должники станут «добросовестными».
Третья — ожидание дробного результата от РАЗНОСТЬДАТ. Функция всегда возвращает целое число полных единиц. Если нужна большая точность, выбирайте более мелкую единицу и делите сами.
Для проверки результата используйте контрольные пары дат с известным ответом: 01.01–01.01 (0 дней), 31.01–01.02 (1 день, 0 месяцев), 15.03.2000–14.03.2010 (9 полных лет). Если функция проходит эти точки, она с высокой вероятностью корректна.
Как проверить результат
0 дней, 0 месяцев, 0 лет
1 день или любое ненулевое значение
1 полный месяц
2 месяца или дробное значение
Просроченные документы дают положительное число дней
Знак результата противоположен ожидаемому
Выбор способа под задачу
Для отчётов и любых выборок из базы однозначно выбирайте РАЗНОСТЬДАТ в запросе: расчёт выполняется на стороне СУБД, не требует перебора строк и работает быстро даже на больших таблицах.
Для проверок в коде («прошло ли больше 14 дней», «не просрочен ли документ») достаточно вычитания дат с приведением к началу дня. Это читаемо и не требует запроса.
Для кадровых и финансовых расчётов, где важны полные месяцы и годы (стаж, возраст, сроки договоров), пишите отдельную функцию в общем модуле и покрывайте её контрольными примерами — такой код будет переиспользоваться и не разъедется между доработками.
Как выбрать действие
Частые вопросы
Почему вычитание дат даёт огромное число вместо дней?
Потому что результат вычитания — секунды. Число 86400 означает ровно одни сутки. Разделите результат на 86400, чтобы получить дни, и на 3600 — чтобы получить часы.
Можно ли использовать РАЗНОСТЬДАТ вне запроса?
Нет, это функция языка запросов. В коде на встроенном языке используйте вычитание дат, функции Год(), Месяц(), День() и ДобавитьМесяц() либо выполните небольшой запрос, если это оправдано.
Как посчитать возраст сотрудника в полных годах?
В запросе: РАЗНОСТЬДАТ(ДатаРождения, &ТекущаяДата, ГОД) — функция вернёт число полных лет. В коде: разность годов минус единица, если месяц и день рождения в текущем году ещё не наступили.
Что вернёт РАЗНОСТЬДАТ, если даты равны?
Ноль в любой единице измерения. Это удобно для проверок: условие «разность больше нуля» сразу отсекает текущий день.
Как учесть время при сравнении дат?
Либо сравнивайте даты напрямую с точностью до секунды, либо осознанно отсекайте время через НачалоДня() или КонецДня(). Смешивание подходов в одном алгоритме — частый источник ошибок «на границе суток».
Есть ли в 1С аналог DATEDIF из Excel?
Отдельной встроенной функции нет. Ближайший аналог — РАЗНОСТЬДАТ в запросах. Для кода эквивалент реализуют самостоятельно через комбинацию Год(), Месяц(), День() и ДобавитьМесяц().
Что важно запомнить
Вычитание дат в коде даёт секунды — делите на 86400 для дней и отсекайте время через НачалоДня(). В запросах применяйте РАЗНОСТЬДАТ с единицей ДЕНЬ, МЕСЯЦ или ГОД: она возвращает целые полные единицы. Для месяцев и лет в коде пишите отдельную функцию и проверяйте её на контрольных парах дат.