При работе с отчетами в системе 1С, особенно в Системе Компоновки Данных (СКД), часто возникает задача отобразить и корректно отсортировать только временную часть из поля типа ДатаВремя. Стандартные подходы, такие как простое форматирование, могут привести к потере возможности сортировки по времени как по отдельному значению. Давайте разберем, как эффективно решить эту проблему, используя различные методы и учитывая важные нюансы.
Представим, что у нас есть поле в источнике данных СКД под названием ДатаВремяСобытия, которое хранит и дату, и время. Нам необходимо в отчете сгруппировать данные по дате, но внутри каждой даты показать записи, отсортированные по времени события. Извлеченное время должно быть именно типом "Время", а не строкой или числом, чтобы СКД могла корректно с ним работать при сортировке.
Когда мы работаем с датами и временем в СКД, первый интуитивный подход — это использование функции Формат(). Например, выражение Формат(ДатаВремяСобытия, "ДЛФ=В") или Формат(ДатаВремяСобытия, "ВРЕМЯ") действительно извлечет временную часть в виде строки, например, "08:00:00". Однако, хотя на первый взгляд это выглядит как решение, возникают проблемы при попытке отсортировать по этому полю:
Формат() всегда является строка. СКД будет воспринимать это поле как текстовое.Мы выяснили, что для полноценной работы с компонентом времени нам нужен не строковый, а именно временной тип данных.
Самый прямой и корректный способ получить компонент времени как отдельное значение типа "Время" в запросах 1С, в том числе и в СКД, — это использование оператора ВЫРАЗИТЬ. Этот оператор позволяет явно привести значение одного типа к другому.
Как это работает:
Оператор ВЫРАЗИТЬ применяется в запросах 1С для явного преобразования типов данных. В нашем случае мы хотим "выразить" полное значение ДатаВремяСобытия как тип Время. СКД автоматически извлечет из комбинированного значения даты и времени только временную часть.
Пример кода в запросе СКД:
Предположим, у вас есть набор данных в СКД, основанный на запросе. В списке полей запроса или в вычисляемых полях СКД мы можем добавить следующее выражение:
ВЫРАЗИТЬ(Т_Таблица.ДатаВремяСобытия КАК Время) КАК ВремяСобытия
Где:
Т_Таблица — это псевдоним вашей таблицы или источника данных, содержащего поле.ДатаВремяСобытия — имя вашего поля типа ДатаВремя.КАК Время — указывает, что мы хотим привести значение к типу "Время".КАК ВремяСобытия — это псевдоним нового поля, которое будет доступно в СКД.После добавления этого поля в набор данных СКД, поле ВремяСобытия будет иметь тип "Время". Мы можем использовать его для:
Очень важный нюанс, который мы должны учитывать, — это возможность того, что поле ДатаВремяСобытия может содержать неопределенные значения (NULL). Если такое значение попытаться привести к типу "Время", запрос может выдать ошибку или вернуть некорректный результат в зависимости от СУБД и версии платформы. Чтобы избежать этого, рекомендуется использовать оператор ВЫБОР КОГДА ... ИНАЧЕ ... КОНЕЦ:
ВЫБОР
КОГДА Т_Таблица.ДатаВремяСобытия ЕСТЬ NULL
ТОГДА NULL
ИНАЧЕ ВЫРАЗИТЬ(Т_Таблица.ДатаВремяСобытия КАК Время)
КОНЕЦ КАК ВремяСобытия
В этом выражении мы сначала проверяем, является ли ДатаВремяСобытия неопределенным. Если да, то новое поле ВремяСобытия также будет NULL. В противном случае выполняется приведение типа. Это делает наше решение более робастным и защищенным от ошибок.
Иногда требуется получить временную часть не как тип "Время", а как числовое значение, например, количество секунд от начала дня. Это может быть полезно для сложных расчетов, когда оперировать непосредственно типом "Время" менее удобно, или для специфической сортировки, когда нужно гарантировать определенный числовой порядок.
Как это работает:
Мы можем использовать функцию РАЗНОСТЬДАТ() в сочетании с НАЧАЛОДНЯ(). Сначала мы определяем начало дня для нашего поля ДатаВремяСобытия с помощью НАЧАЛОДНЯ(ДатаВремяСобытия). Затем вычисляем разницу между полным значением ДатаВремяСобытия и началом этого дня в секундах.
Пример кода в запросе СКД:
РАЗНОСТЬДАТ(НАЧАЛОДНЯ(Т_Таблица.ДатаВремяСобытия), Т_Таблица.ДатаВремяСобытия, СЕКУНДА) КАК СекундыСНачалаДня
Где:
НАЧАЛОДНЯ(Т_Таблица.ДатаВремяСобытия) — возвращает дату и время 00:00:00 для даты ДатаВремяСобытия.Т_Таблица.ДатаВремяСобытия — наше исходное поле.СЕКУНДА — единица измерения, в которой мы хотим получить разницу.КАК СекундыСНачалаДня — новое поле, содержащее число секунд от 00:00:00 до времени события.Это поле СекундыСНачалаДня будет иметь тип "Число" и отлично подойдет для математических операций, а также для сортировки. Чем больше секунд, тем позже время события. Если вам потребуется отобразить это число в привычном формате времени, вы можете использовать функции форматирования или написать свою функцию для преобразования секунд в формат "ЧЧ:ММ:СС".
Пример форматирования числа секунд в СКД для отображения (в вычисляемом поле):
// Предполагаем, что поле "СекундыСНачалаДня" уже существует
// Для отображения времени в формате ЧЧ:ММ:СС из секунд
Строка(ЦЕЛ(СекундыСНачалаДня / 3600)) + ":" + Строка(ЦЕЛ((СекундыСНачалаДня % 3600) / 60)) + ":" + Строка(СекундыСНачалаДня % 60)
Этот пример демонстрирует, как можно извлечь часы, минуты и секунды из общего количества секунд и скомбинировать их в строку. Для более аккуратного форматирования с ведущими нулями (например, "08:05:01" вместо "8:5:1") потребуется использовать дополнительные функции форматирования строк, например, через дополнение нулями до двух символов.
Как мы уже обсуждали, Формат() не подходит для сортировки. Однако, если наша цель — исключительно вывести временную часть в удобном для чтения виде, и при этом сортировка по времени будет производиться по другому (скрытому) полю (например, по полю, полученному через ВЫРАЗИТЬ(ДатаВремяСобытия КАК Время)), то Формат() вполне уместен.
Пример использования:
Формат(Т_Таблица.ДатаВремяСобытия, "ДЛФ=В") КАК ВремяДляОтображения
Или, если нужен только временной компонент без даты:
Формат(Т_Таблица.ДатаВремяСобытия, "ЧЧ:мм:сс") КАК ВремяДляОтображения
Поле ВремяДляОтображения будет строковым и будет использоваться только для вывода информации в отчете.
Давайте разберем, как внедрить выбранное решение в ваш отчет на СКД.
В конфигураторе или в пользовательском режиме (если у отчета есть такая возможность) откройте структуру отчета и перейдите на вкладку "Наборы данных".
Перейдите на вкладку "Вычисляемые поля". Нажмите кнопку "Добавить" и создайте новое поле. Назовем его, например, ВремяСобытия.
В столбце "Выражение" для нового поля ВремяСобытия введите одно из описанных выше выражений. Например, для получения временного типа:
ВЫБОР
КОГДА ДатаВремяСобытия ЕСТЬ NULL
ТОГДА NULL
ИНАЧЕ ВЫРАЗИТЬ(ДатаВремяСобытия КАК Время)
КОНЕЦ
Обратите внимание: если вы пишете выражение в "Вычисляемых полях" СКД, вам не нужно указывать псевдоним таблицы (Т_Таблица.) перед именем поля ДатаВремяСобытия, так как СКД уже знает контекст.
Перейдите на вкладку "Настройки". Здесь мы можем определить, как наш отчет будет сгруппирован и отсортирован.
Добавьте группировку по полю НАЧАЛОДНЯ(ДатаВремяСобытия), чтобы сгруппировать записи по датам.
НАЧАЛОДНЯ(ДатаВремяСобытия)
Внутри этой группировки или в детальных записях добавьте сортировку по нашему новому полю ВремяСобытия (или СекундыСНачалаДня, если вы выбрали числовой подход). Убедитесь, что порядок сортировки установлен правильно (по возрастанию или убыванию).
На вкладке "Настройки" в списке "Выбранные поля" убедитесь, что поле ВремяСобытия (или ВремяДляОтображения, если вы использовали его) добавлено и видимо в отчете.
Сформируйте отчет и убедитесь, что данные сгруппированы по дате, а внутри каждой даты записи корректно отсортированы по времени, и временной компонент отображается так, как вы планировали.
ВЫРАЗИТЬ и НАЧАЛОДНЯ обычно нет значительных проблем с производительностью.
ВремяСобытия, СекундыСНачалаДня), чтобы другим разработчикам (или вам самим в будущем) было понятно их назначение.
ВЫРАЗИТЬ(ПолеДатаВремя КАК Время) — это наиболее предпочтительный и "чистый" метод.РАЗНОСТЬДАТ(НАЧАЛОДНЯ(ПолеДатаВремя), ПолеДатаВремя, СЕКУНДА) подойдет лучше, так как возвращает число.Формат(ПолеДатаВремя, "ЧЧ:мм:сс"), если не требуется сортировка по этому полю.Таким образом, мы видим, что извлечение и корректная работа с временным компонентом поля ДатаВремя в СКД — это задача, которая имеет элегантные и эффективные решения. Выбрав подходящий метод из описанных, мы обеспечим не только правильное отображение данных, но и их функциональную пригодность для сортировки и анализа в отчетах 1С.