Одной из типовых задач при разработке в платформе 1С:Предприятие является проверка попадания заданной даты в определенный временной интервал. Разберем различные способы решения этой задачи как во встроенном языке, так и в языке запросов, а также проанализируем важные нюансы, связанные с учетом времени и обработкой пустых значений.
В простейшем случае для проверки вхождения даты в диапазон применяются стандартные операторы сравнения >= и <=. Однако в платформе 1С тип Дата всегда содержит составляющую времени (часы, минуты, секунды). Если правая граница диапазона передана без времени (по умолчанию 00:00:00), дата с ненулевым временем того же дня не войдет в интервал.
Чтобы избежать этой ошибки, правую границу диапазона приводят к концу суток с помощью функции КонецДня(). Рассмотрим пример:
ДатаПроверки = '20170416120000'; // 16.04.2017 12:00:00
ДатаНачала = '20160101000000'; // 01.01.2016 00:00:00
ДатаОкончания = '20171231000000';// 31.12.2017 00:00:00
Если ДатаПроверки >= ДатаНачала И ДатаПроверки <= КонецДня(ДатаОкончания) Тогда
// Дата входит в диапазон
ВходитВДиапазон = Истина;
Иначе
ВходитВДиапазон = Ложь;
КонецЕсли;
Проанализируем альтернативный подход во встроенном языке, исключающий возможные погрешности с миллисекундами на уровне СУБД. Вместо вызова КонецДня() можно проверить строгое неравенство со временем начала следующего дня:
Если ДатаПроверки >= ДатаНачала И ДатаПроверки < (НачалоДня(ДатаОкончания) + 86400) Тогда
ВходитВДиапазон = Истина;
КонецЕсли;
Прибавив 86400 секунд к началу дня границы окончания, мы получаем ровно 00:00:00 следующего календарного дня.
В языке запросов 1С для проверки вхождения даты в интервал применяется оператор МЕЖДУ (или конструкция BETWEEN). Он эквивалентен условию Поле >= &Начало И Поле <= &Конец, включая обе границы.
Посмотрим на пример формирования запроса с функцией КОНЕЦПЕРИОДА для корректного включения всего дня окончания:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВЫБОР
| КОГДА &ДатаПроверки МЕЖДУ &ДатаНачала И КОНЕЦПЕРИОДА(&ДатаОкончания, ДЕНЬ) ТОГДА ИСТИНА
| ИНАЧЕ ЛОЖЬ
| КОНЕЦ КАК ВходитВДиапазон";
Запрос.УстановитьПараметр("ДатаПроверки", ДатаПроверки);
Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
Запрос.УстановитьПараметр("ДатаОкончания", ДатаОкончания);
Результат = Запрос.Выполнить().Выгрузить();
Важно: если значение параметра &ДатаНачала окажется строго больше параметра &ДатаОкончания, конструкция МЕЖДУ всегда возвратит результат ЛОЖЬ.
В типовых конфигурациях и формах отчетов для задания интервалов часто применяется объект СтандартныйПериод. Разберем его ключевое преимущество:
ДатаОкончания автоматически устанавливается на 23:59:59 выбранного дня.КонецДня() или КОНЕЦПЕРИОДА перед передачей параметров в запрос.На практике границы периода могут быть не заданы (например, если период бессрочный). В 1С пустая дата равна 0001-01-01T00:00:00 ('00010101'). Посмотрим, как корректно составить условие во встроенном языке с учетом возможных незаполненных значений:
УсловиеНачала = (НЕ ЗначениеЗаполнено(ДатаНачала)) ИЛИ (ДатаПроверки >= ДатаНачала);
УсловиеКонца = (НЕ ЗначениеЗаполнено(ДатаОкончания)) ИЛИ (ДатаПроверки <= КонецДня(ДатаОкончания));
Если УсловиеНачала И УсловиеКонца Тогда
// Дата удовлетворяет диапазону (в том числе открытому с одной из сторон)
КонецЕсли;
При построении отчетов на базе СКД нет необходимости прописывать сложные условия в тексте запроса. Достаточно в настройках отбора добавить поле даты и выбрать стандартный вид сравнения В интервале. СКД автоматически выполнит корректное позиционирование дат с учетом начала и окончания выбранных периодов.