В процессе разработки отчетов и автоматизации бизнес-логики в 1С часто возникает задача определения временного интервала. Например, нам нужно узнать, сколько дней осталось до конца срока исполнения услуги или сколько дней составляет просрочка. В этой статье мы подробно разберем, как реализовать вычисление разницы дат двумя способами: непосредственно в запросе и с помощью встроенного языка 1С.
Использование запросов — наиболее эффективный и правильный метод с точки зрения производительности, особенно если данных много. В языке запросов 1С существует специальная функция РАЗНОСТЬДАТ. Рассмотрим её синтаксис и практическое применение на примере документа с табличной частью.
Проанализируем структуру функции:
РАЗНОСТЬДАТ(<Дата1>, <Дата2>, <ТипРазности>)
Рассмотрим ситуацию: у нас есть документ Журнал9 с табличной частью Услуги. В табличной части хранится реквизит ДатаИсполненияСрок. Нам нужно вычислить, сколько дней осталось от текущей даты до этого срока. Разберем код запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Журнал9.Ссылка КАК Ссылка,
| РАЗНОСТЬДАТ(&ТекущаяДата, ВТ_Услуги.ДатаИсполненияСрок, ДЕНЬ) КАК ДниДоОкончания,
| Журнал9.Контрагент
|ИЗ
| Документ.Журнал9 КАК Журнал9
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.Журнал9.Услуги КАК ВТ_Услуги
| ПО Журнал9.Ссылка = ВТ_Услуги.Ссылка
|ГДЕ
| Журнал9.Дата МЕЖДУ &НачалоПериода И &КонецПериода";
Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДата());
Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
Запрос.УстановитьПараметр("КонецПериода", КонецПериода);
Обратим внимание на важный нюанс: если Дата1 больше, чем Дата2, функция вернет отрицательное число. Если вы хотите получить количество дней просрочки (когда текущая дата уже позже срока), поменяйте даты местами или используйте конструкцию ВЫБОР для обработки просроченных обязательств.
Разберем основные трудности, с которыми сталкиваются разработчики:
Неоднозначное поле "Ссылка". Это происходит потому, что поле Ссылка есть и в шапке документа, и в табличной части. Всегда используйте псевдонимы таблиц (например, Журнал9 и ВТ_Услуги), чтобы явно указать источнику данных.&ТекущаяДата через метод УстановитьПараметр. Запрос не имеет прямого доступа к системным функциям встроенного языка типа ТекущаяДата().СУММА), поле с РАЗНОСТЬДАТ обязательно должно быть включено в секцию СГРУППИРОВАТЬ ПО.Иногда вычисление требуется выполнить "на лету" в коде модуля формы или обработки. В 1С при вычитании одной даты из другой результат получается в секундах. Чтобы перевести его в дни, необходимо разделить полученное число на количество секунд в сутках (86 400).
Рассмотрим пример программного расчета:
// Получаем разницу в секундах
РазницаВСекундах = Объект.ДатаОкончания - ТекущаяДата();
// Переводим в целые дни
КоличествоДней = Цел(РазницаВСекундах / (60 * 60 * 24));
Сообщить("До окончания услуги осталось дней: " + КоличествоДней);
Проанализируем этот метод. Он кажется простым, но таит в себе подводные камни, связанные с временем. Если ДатаОкончания установлена на "01.01.2024 00:00:00", а текущее время "31.12.2023 15:00:00", то чистая разница в секундах при делении даст меньше единицы, и функция Цел() вернет 0, хотя фактически день еще не закончился. Для более точных расчетов рекомендуем приводить обе даты к началу дня с помощью функции НачалоДня().
Выясним причину, по которой расчет может быть неточным. Функция РАЗНОСТЬДАТ в запросе считает количество переходов через границу периода. Если сравнить 23:59:59 текущего дня и 00:00:01 следующего дня, функция с параметром ДЕНЬ вернет 1. Это стандартное поведение СУБД.
Если вам необходимо учитывать только рабочие дни, стандартных функций 1С будет недостаточно. В этом случае алгоритм усложняется:
Если вы строите отчет на СКД, расчет разности дат можно вынести в "Вычисляемые поля". Это позволяет не загромождать основной запрос. В выражении вычисляемого поля можно написать:
РазностьДаты(ДатаСрока, &ТекущаяДата, "День")
Преимущество этого метода в том, что СКД автоматически обрабатывает NULL значения. Если дата в табличной части не заполнена, отчет не "упадет" с ошибкой, а просто выведет пустой результат или 0, если применить функцию ЕСТЬNULL.
Подводя итог, можно сказать: для массовых отчетов всегда выбирайте Способ 1 (Запросы). Для простых проверок в формах документов используйте Способ 2 (Встроенный язык), предварительно нормализовав время до начала или конца дня. Правильное использование этих инструментов сделает ваш код надежным и быстрым.