Расчет разницы между датами — одна из самых частых задач при разработке в 1С:Предприятие 8.3. Без этого не обойтись при расчете просроченных задолженностей, определении стажа сотрудников, анализе временных интервалов в отчетах или автоматизации бизнес-процессов. Казалось бы, простая операция, но в 1С есть несколько способов получить разность дат — от элементарных встроенных функций до сложных запросов с группировкой по периодам.
Главная проблема: платформа не возвращает разницу в привычном формате"X дней". Вместо этого вы получаете количество секунд, минут или произвольный интервал, который еще нужно правильно интерпретировать. В этой статье разберем 5 рабочих методов — от базовых до продвинутых, с учетом нюансов календарных дней, рабочего времени и часовых поясов. Вы узнаете, как избежать ошибок при переходе на зимнее/летнее время, почему РазностьДат иногда выдает неточные результаты, и как оптимизировать расчеты для больших массивов данных.
1. Встроенная функция РазностьДат: синтаксис и подводные камни
Самый очевидный способ — использовать стандартную функцию РазностьДат. Она возвращает разницу между двумя датами в заданных единицах: секундах, минутах, часах, днях или даже месяцах. Синтаксис простой:
РазностьДат(Дата2, Дата1, ЕдиницаИзмерения)
Где ЕдиницаИзмерения может принимать значения:
- 🕒
"С"— секунды - 🕒
"М"— минуты - 🕒
"Ч"— часы - 📅
"Д"— дни (самый популярный вариант) - 📆
"МЕС"— месяцы - 🗓️
"КВ"— кварталы - 📅
"ГОД"— годы
Пример кода:
ДатаНачала ='2026-01-15';
ДатаОкончания ='2026-02-20';
РазницаВДнях = РазностьДат(ДатаОкончания, ДатаНачала,"Д");
// Вернет 36 (дней)
Если вам нужна разница в полных календарных днях (без учета времени), предварительно обнулите время у обеих дат функцией НачалоДня.
⚠️ Внимание: Функция учитывает астрономическое время, а не календарные сутки. Это означает, что разница между '2026-01-01 23:59:59' и '2026-01-02 00:00:01' составит 2 секунды, а не 1 день. Для бизнес-логики это часто критично!
2. Альтернативный метод: вычитание дат как чисел
Менее известный, но эффективный способ — воспользоваться тем, что в 1С даты внутренне хранятся как числа (количество секунд с 1 января 1899 года). Их можно просто вычесть:
Дата1 ='2026-01-01';
Дата2 ='2026-01-10';
РазницаВСекундах = Дата2 - Дата1;
// Вернет 777600 (секунд = 9 дней)
Чтобы перевести результат в дни, разделите на 86400 (количество секунд в сутках):
РазницаВДнях = (Дата2 - Дата1) / 86400;
Преимущества метода:
- ⚡ Быстрее работает на больших массивах данных
- 🔧 Позволяет гибко настраивать единицы измерения (например, получить часы с дробной частью)
- 📊 Легко интегрируется в математические выражения
⚠️ Внимание: При вычитании дат с временем результат будет включать дробную часть (часы/минуты). Для чисто календарных расчетов предварительно применяйте НачалоДня.
3. Расчет разности в запросах 1С (SQL-подобный синтаксис)
Если вам нужно получить разницу дат для большого количества записей (например, просроченные заказы или время выполнения задач), оптимально использовать запросы 1С. В языке запросов есть специальная функция РАЗНОСТЬДАТ, аналогичная встроенной, но работающая в контексте выборки.
Пример запроса:
ВЫБРАТЬ
ЗаказыПокупателей.Номер КАК НомерЗаказа,
РАЗНОСТЬДАТ(ТЕКУЩАЯДАТА, ЗаказыПокупателей.Дата,"Д") КАК ПросрочкаДней
ИЗ
Документ.ЗаказыПокупателей КАК ЗаказыПокупателей
ГДЕ
ЗаказыПокупателей.Статус = ЗНАЧЕНИЕ(Справочник.СтатусыЗаказов.НеВыполнен)
Особенности работы с РАЗНОСТЬДАТ в запросах:
- 📊 Можно использовать в
ВЫБРАТЬ,ГДЕиУПОРЯДОЧИТЬ ПО - 🔄 Поддерживает те же единицы измерения, что и встроенная функция
- ⚡ Работает значительно быстрее, чем построчный расчет в цикле
Для сложных аналитических задач (например, группировки по неделям или кварталам) комбинируйте РАЗНОСТЬДАТ с другими функциями:
ВЫБРАТЬ
НЕДЕЛЯ(Документы.Дата) КАК Неделя,
СУММА(РАЗНОСТЬДАТ(Документы.ДатаОплаты, Документы.Дата,"Д")) / КОЛИЧЕСТВО(*) КАК СредняяПросрочка
ИЗ
Документ.РеализацияТоваровУслуг КАК Документы
СГРУППИРОВАТЬ ПО
НЕДЕЛЯ(Документы.Дата)
4. Учет рабочих и календарных дней
Стандартные функции 1С не различают рабочие и выходные дни. Если вам нужно рассчитать разницу с учетом производственного календаря (например, для расчета сроков доставки или времени выполнения задач), потребуется дополнительная логика.
Вариант 1. Использовать справочник"ПроизводственныеКалендари"
В типовой конфигурации 1С:ERP или 1С:Управление торговлей есть справочник с предопределенными календарями. Пример кода:
Календарь = Справочники.ПроизводственныеКалендари.ОсновнойКалендарь;
Разница = Календарь.РазностьДат(ДатаОкончания, ДатаНачала);
// Вернет количество рабочих дней
Вариант 2. Самописная функция с учетом выходных
Если типового календаря нет, можно написать собственную функцию:
Функция РабочиеДниМеждуДатами(ДатаНачала, ДатаОкончания)
ДатаТекущая = НачалоДня(ДатаНачала);
КоличествоДней = 0;
Пока ДатаТекущая <= ДатаОкончания Цикл
Если НЕ (ДеньНедели(ДатаТекущая) = 6 ИЛИ ДеньНедели(ДатаТекущая) = 7) Тогда
КоличествоДней = КоличествоДней + 1;
КонецЕсли;
ДатаТекущая = ДатаТекущая + 86400; // +1 день
КонецЦикла;
Возврат КоличествоДней;
КонецФункции
⚠️ Внимание: Не забывайте про праздничные дни, которые могут выпадать на будни! Для точных расчетов нужно интегрировать официальный производственный календарь РФ (обновляется ежегодно).
☑️ Подготовка к расчету рабочих дней
5. Работа с часовыми поясами и летним временем
Если ваша система работает в нескольких часовых поясах (например, филиалы компании в разных регионах), стандартные функции 1С могут давать некорректные результаты. Проблема усугубляется при переходе на зимнее/летнее время, когда местное время сдвигается на час.
Решение 1. Хранить даты в UTC
Лучшая практика — сохранять все даты в базе в формате UTC (всемирное координированное время), а при отображении конвертировать в локальное время пользователя:
// Преобразование в UTC
ДатаUTC = ДатаЛокальная + ЧасовойПояс * 3600;
// Обратное преобразование
ДатаЛокальная = ДатаUTC - ЧасовойПояс * 3600;
Решение 2. Использовать функцию"ЛокальнаяДата"
В современных версиях платформы есть функция ЛокальнаяДата, которая автоматически учитывает настройки часовых поясов текущего пользователя:
ДатаСервера = ТекущаяДата;
ДатаПользователя = ЛокальнаяДата(ДатаСервера);
| Сценарий | Проблема | Решение |
|---|---|---|
| Филиалы в разных часовых поясах | Разница между датами считается некорректно | Хранить даты в UTC, конвертировать при отображении |
| Переход на зимнее/летнее время | Разница в часах может"потеряться" или удвоиться | Использовать ЛокальнаяДата или библиотеку работы с поясами |
| Расчет времени выполнения задач | Время может отличаться у исполнителей в разных регионах | Привязывать задачи к UTC и конвертировать в локальное время при отчетах |
⚠️ Внимание: Настройки часовых поясов в 1С берутся из операционной системы сервера и клиентских машин. Если они не синхронизированы, возможны расхождения! Проверяйте настройки через Администрирование → Настройки программы → Часовые пояса.
6. Оптимизация производительности для больших данных
При расчете разницы дат для тысяч записей (например, в отчетах или фоновых заданиях) стандартные методы могут тормозить систему. Вот 3 способа ускорить обработку:
1. Кэширование результатов
Если один и тот же интервал дат используется многократно (например, в отчете за месяц), закэшируйте результат:
Процедура ПолучитьКэшированнуюРазницу(Дата1, Дата2)
КлючКэша ="Разница_" + Формат(Дата1,"ДЛФ=DT") +"_" + Формат(Дата2,"ДЛФ=DT");
Если НЕ Кэш.Получить(КлючКэша, Разница) Тогда
Разница = РазностьДат(Дата2, Дата1,"Д");
Кэш.Поместить(КлючКэша, Разница, 3600); // Кэш на 1 час
КонецЕсли;
Возврат Разница;
КонецПроцедуры
2. Массовая обработка в запросах
Как показано в разделе 3, использование РАЗНОСТЬДАТ в запросе в десятки раз быстрее, чем построчный расчет в цикле.
3. Предварительный расчет
Если разница дат нужна для отчетов, рассчитайте ее заранее и сохраните в регистре сведений или дополнительном реквизите. Пример структуры:
РегистрСведений.РазницыДат
- Измерение: ДокументСсылка (Тип: Документ.ЗаказПокупателя)
- Ресурс: ПросрочкаДней (Тип: Число, 10, 0)
Для максимальной производительности комбинируйте эти методы. Например:
- Рассчитайте разницы в фоне и сохраните в регистре
- В отчете берите готовые значения из регистра
- Обновляйте кэш раз в час
Для массивов данных свыше 10 000 записей запросы 1С работают в 50-100 раз быстрее, чем построчная обработка на встроенном языке.
7. Типичные ошибки и как их избежать
Даже опытные разработчики 1С иногда допускают ошибки при работе с датами. Вот самые распространенные:
Ошибка 1. Игнорирование времени
Если не обнулить время у дат функцией НачалоДня, разница между '2026-01-01 23:59:59' и '2026-01-02 00:00:01' составит 2 секунды вместо 1 дня. Всегда приводите даты к началу дня для календарных расчетов!
Ошибка 2. Неучет високосных годов
Функция РазностьДат корректно обрабатывает високосные годы, но если вы пишете собственную логику (например, прибавляете 365 дней к дате), не забывайте про 29 февраля:
// Некорректно для 29.02.2026
НоваяДата = ДатаНачала + 365 * 86400; // Пропустит 29.02.2026
// Корректно
НоваяДата = ДобавитьМесяц(ДобавитьГод(ДатаНачала, 1), 0);
Ошибка 3. Путаница с часовыми поясами
Если сервер и клиенты находятся в разных часовых поясах, ТекущаяДата на сервере и у пользователя может отличаться на несколько часов. Всегда уточняйте, в каком поясе должна отображаться дата.
Ошибка 4. Неоптимальные расчеты в циклах
Избегайте таких конструкций:
// Плохо (медленно для больших массивов)
Для Каждого Строка Из Таблица Цикл
Строка.Разница = РазностьДат(Строка.Дата2, Строка.Дата1,"Д");
КонецЦикла;
Лучше используйте запросы или массовые операции.
Что будет если не учитывать часовые пояса?
При сравнении дат между филиалами в Москве (+3 UTC) и Владивостоке (+10 UTC) разница в 7 часов может привести к ошибкам в отчетах. Например, документ, созданный в 18:00 по московскому времени, во Владивостоке будет иметь дату следующего дня (01:00), что исказит аналитику по дням.
FAQ: Частые вопросы по разности дат в 1С
Как получить разницу между датами в месяцах с учетом неполных месяцев?
Используйте комбинацию функций Год и Месяц:
РазницаМесяцев = (Год(Дата2) - Год(Дата1)) * 12 + (Месяц(Дата2) - Месяц(Дата1));
Если День(Дата2) < День(Дата1) Тогда
РазницаМесяцев = РазницаМесяцев - 1;
КонецЕсли;
Этот метод учитывает, что 1.03 и 15.04 — это 1 полный месяц и 14 дней, а не 2 месяца.
Почему РазностьДат возвращает отрицательное значение?
Функция вычитает первую дату из второй (Дата2 - Дата1). Если Дата1 позже Дата2, результат будет отрицательным. Чтобы избежать этого, используйте:
Разница = Абс(РазностьДат(Дата2, Дата1,"Д"));
Как посчитать количество полных недель между датами?
Разделите разницу в днях на 7 и округлите вниз:
ПолныхНедель = Цел(РазностьДат(Дата2, Дата1,"Д") / 7);
Для учета неполных недель используйте Окр вместо Цел.
Можно ли получить разницу в годах с учетом високосных?
Да, но стандартной функции нет. Используйте такой код:
Функция РазницаВГодах(Дата1, Дата2)
Возврат Год(Дата2) - Год(Дата1) -
?(Месяц(Дата2) < Месяц(Дата1) ИЛИ
(Месяц(Дата2) = Месяц(Дата1) И День(Дата2) < День(Дата1)), 1, 0);
КонецФункции
Как учитывать праздничные дни в расчетах?
Создайте справочник"ПраздничныеДни" с датами и модифицируйте функцию расчета рабочих дней:
Функция РабочиеДниСПраздниками(ДатаНачала, ДатаОкончания)
//... базовая логика из раздела 4...
Если Справочники.ПраздничныеДни.НайтиПоНаименованию(Формат(ДатаТекущая,"ДЛФ=Д")) <> Неопределено Тогда
Продолжить; // Пропускаем праздничный день
КонецЕсли;
//...
КонецФункции
Не забудьте обновлять справочник раз в год!