При разработке отчетов и обработок в 1С часто возникает необходимость не просто получить данные из справочников или документов, но и произвести с ними вычисления. Одной из популярных задач является вычисление количества дней, прошедших между двумя датами. Давайте разберем ситуацию, когда нам нужно рассчитать разницу между датой принятия заказа и датой его полной готовности, а затем, в зависимости от того, превышает ли эта разница 6 дней, выполнить определенные действия.
Проанализируем начальные условия. У нас есть запрос, который получает даты из справочника, и нам необходимо задать условие: если разность дат больше или равна 6, то это одна ситуация, а все остальное должно попадать в блок «иначе». Рассмотрим по шагам, как правильно реализовать эту логику с точки зрения синтаксиса языка запросов 1С и последующей обработки результата встроенным языком.
Если наша задача состоит исключительно в том, чтобы оставить в выборке только те строки, где разница между датами составляет 6 или более дней, мы можем использовать секцию ГДЕ. Это самый простой способ отсечь ненужные данные еще на этапе выполнения запроса на сервере базы данных.
Посмотрим на пример такого условия:
ВЫБРАТЬ
Мойсправочник.ПринятияЗаказа КАК ПринятиеЗаказа,
Мойсправочник.ПолнаяГотовность КАК ПолнаяГотовность,
РАЗНОСТЬДАТ(Мойсправочник.ПринятияЗаказа, Мойсправочник.ПолнаяГотовность, ДЕНЬ) КАК РазностьВДнях
ИЗ
Справочник.Мойсправочник КАК Мойсправочник
ГДЕ
РАЗНОСТЬДАТ(Мойсправочник.ПринятияЗаказа, Мойсправочник.ПолнаяГотовность, ДЕНЬ) >= 6
Однако этот вариант не подходит, если нам нужны все записи справочника, но для каждой из них нужно установить некий признак или статус в зависимости от срока выполнения заказа.
Чтобы реализовать логику «если ... то ... иначе» внутри самого запроса, мы применим специальную конструкцию ВЫБОР. Разберем подробнее её синтаксис. Конструкция позволяет проверить одно или несколько условий и вернуть соответствующий результат в новое поле запроса.
Посмотрим, как будет выглядеть итоговый запрос, который вернет булево значение (Истина или Ложь) в зависимости от того, превышен ли срок в 6 дней:
ВЫБРАТЬ
Мойсправочник.Ссылка КАК Ссылка,
Мойсправочник.ПринятияЗаказа КАК ПринятиеЗаказа,
Мойсправочник.ПолнаяГотовность КАК ПолнаяГотовность,
ВЫБОР
КОГДА РАЗНОСТЬДАТ(Мойсправочник.ПринятияЗаказа, Мойсправочник.ПолнаяГотовность, ДЕНЬ) >= 6
ТОГДА ИСТИНА
ИНАЧЕ ЛОЖЬ
КОНЕЦ КАК РазницаБольшеШести
ИЗ
Справочник.Мойсправочник КАК Мойсправочник
В этом примере мы создали вычисляемое поле РазницаБольшеШести. Система проверит каждую запись: если разница дат больше или равна 6 дням, в это поле будет записано значение ИСТИНА, во всех остальных случаях — ЛОЖЬ.
Часто начинающие разработчики пытаются вставить функции встроенного языка, такие как Сообщить(), прямо в текст запроса. Важно понимать: язык запросов 1С работает только с данными базы, он не умеет взаимодействовать с интерфейсом и выводить сообщения пользователю.
Чтобы решить задачу информирования пользователя, мы должны выполнить запрос, получить выборку и обойти ее в цикле с помощью кода на встроенном языке. Разберем по шагам, как это сделать:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Мойсправочник.Ссылка КАК Ссылка,
| РАЗНОСТЬДАТ(Мойсправочник.ПринятияЗаказа, Мойсправочник.ПолнаяГотовность, ДЕНЬ) КАК РазностьВДнях
|ИЗ
| Справочник.Мойсправочник КАК Мойсправочник";
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Выполняем проверку условия уже в коде на встроенном языке
Если Выборка.РазностьВДнях >= 6 Тогда
Сообщить("Заказ " + Строка(Выборка.Ссылка) + " готовился 6 или более дней!");
Иначе
Сообщить("Заказ " + Строка(Выборка.Ссылка) + " уложился в нормативы.");
КонецЕсли;
КонецЦикла;
В данном скрипте мы получаем точное количество дней из поля РазностьВДнях и уже в модуле проверяем условие через Если ... Тогда ... Иначе. Это наиболее гибкий и правильный подход для вывода текстовых сообщений.
При работе с функцией РАЗНОСТЬДАТ существуют подводные камни, которые могут привести к неверным результатам в отчетах. Проанализируем самые критичные из них:
>= 6 не отработает так, как вы ожидали.01.01.0001. Если реквизит ПолнаяГотовность не заполнен, то разница между датой создания документа и пустой датой составит тысячи лет со знаком минус (или плюс, смотря что из чего вычитаем). Чтобы избежать логических ошибок, всегда отсекайте пустые даты в параметрах запроса или проверяйте их через условие ГДЕ Мойсправочник.ПолнаяГотовность <> ДАТАВРЕМЯ(1, 1, 1).ДЕНЬ в функцию, система не высчитывает количество полных 24-часовых интервалов. Она считает количество фактов пересечения полуночи (границы дня). Если заказ принят в 23:55 понедельника, а готов в 00:05 вторника, функция РАЗНОСТЬДАТ вернет значение 1 (один день), хотя по факту прошло всего 10 минут. Если для ваших бизнес-процессов критична точность, вычисляйте разность в часах или секундах с параметрами ЧАС или СЕКУНДА, а затем делите полученное число математически.Используя приведенные выше конструкции и учитывая особенности работы с датами, вы сможете писать надежные запросы, корректно обрабатывать условия и безошибочно выводить нужную информацию пользователям вашей конфигурации 1С.