Как правильно извлечь компонент времени из поля типа "ДатаВремя" в 1С СКД для сортировки?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с отчетами в системе 1С, особенно в Системе Компоновки Данных (СКД), часто возникает задача отобразить и корректно отсортировать только временную часть из поля типа ДатаВремя. Стандартные подходы, такие как простое форматирование, могут привести к потере возможности сортировки по времени как по отдельному значению. Давайте разберем, как эффективно решить эту проблему, используя различные методы и учитывая важные нюансы.

Представим, что у нас есть поле в источнике данных СКД под названием ДатаВремяСобытия, которое хранит и дату, и время. Нам необходимо в отчете сгруппировать данные по дате, но внутри каждой даты показать записи, отсортированные по времени события. Извлеченное время должно быть именно типом "Время", а не строкой или числом, чтобы СКД могла корректно с ним работать при сортировке.

Понимание проблемы: почему не подходит простое форматирование?

Когда мы работаем с датами и временем в СКД, первый интуитивный подход — это использование функции Формат(). Например, выражение Формат(ДатаВремяСобытия, "ДЛФ=В") или Формат(ДатаВремяСобытия, "ВРЕМЯ") действительно извлечет временную часть в виде строки, например, "08:00:00". Однако, хотя на первый взгляд это выглядит как решение, возникают проблемы при попытке отсортировать по этому полю:

  1. Тип данных: Результатом функции Формат() всегда является строка. СКД будет воспринимать это поле как текстовое.
  2. Сортировка строк: Текстовая сортировка может работать некорректно в сложных сценариях или если формат времени не унифицирован. Хотя для стандартного формата HH:MM:SS она чаще всего совпадает с хронологической, мы теряем возможность выполнять с этим полем другие операции, специфичные для типа "Время".
  3. Ограниченные возможности: Если в дальнейшем потребуется выполнять арифметические операции со временем (например, вычислять разницу во времени между событиями), строковый тип будет непригоден.

Мы выяснили, что для полноценной работы с компонентом времени нам нужен не строковый, а именно временной тип данных.

Решение 1: Использование функции ВЫРАЗИТЬ для явного приведения типа (рекомендуемый способ)

Самый прямой и корректный способ получить компонент времени как отдельное значение типа "Время" в запросах 1С, в том числе и в СКД, — это использование оператора ВЫРАЗИТЬ. Этот оператор позволяет явно привести значение одного типа к другому.

Как это работает:

Оператор ВЫРАЗИТЬ применяется в запросах 1С для явного преобразования типов данных. В нашем случае мы хотим "выразить" полное значение ДатаВремяСобытия как тип Время. СКД автоматически извлечет из комбинированного значения даты и времени только временную часть.

Пример кода в запросе СКД:

Предположим, у вас есть набор данных в СКД, основанный на запросе. В списке полей запроса или в вычисляемых полях СКД мы можем добавить следующее выражение:

ВЫРАЗИТЬ(Т_Таблица.ДатаВремяСобытия КАК Время) КАК ВремяСобытия

Где:

После добавления этого поля в набор данных СКД, поле ВремяСобытия будет иметь тип "Время". Мы можем использовать его для:

  1. Корректной хронологической сортировки.
  2. Отображения в отчете.
  3. Возможно, для дальнейших временных расчетов, если это потребуется (хотя для расчетов часто удобнее работать с числовым представлением времени).

Обработка NULL-значений

Очень важный нюанс, который мы должны учитывать, — это возможность того, что поле ДатаВремяСобытия может содержать неопределенные значения (NULL). Если такое значение попытаться привести к типу "Время", запрос может выдать ошибку или вернуть некорректный результат в зависимости от СУБД и версии платформы. Чтобы избежать этого, рекомендуется использовать оператор ВЫБОР КОГДА ... ИНАЧЕ ... КОНЕЦ:


ВЫБОР
    КОГДА Т_Таблица.ДатаВремяСобытия ЕСТЬ NULL
        ТОГДА NULL
    ИНАЧЕ ВЫРАЗИТЬ(Т_Таблица.ДатаВремяСобытия КАК Время)
КОНЕЦ КАК ВремяСобытия

В этом выражении мы сначала проверяем, является ли ДатаВремяСобытия неопределенным. Если да, то новое поле ВремяСобытия также будет NULL. В противном случае выполняется приведение типа. Это делает наше решение более робастным и защищенным от ошибок.

Решение 2: Извлечение времени как числа секунд от начала дня (альтернативный способ)

Иногда требуется получить временную часть не как тип "Время", а как числовое значение, например, количество секунд от начала дня. Это может быть полезно для сложных расчетов, когда оперировать непосредственно типом "Время" менее удобно, или для специфической сортировки, когда нужно гарантировать определенный числовой порядок.

Как это работает:

Мы можем использовать функцию РАЗНОСТЬДАТ() в сочетании с НАЧАЛОДНЯ(). Сначала мы определяем начало дня для нашего поля ДатаВремяСобытия с помощью НАЧАЛОДНЯ(ДатаВремяСобытия). Затем вычисляем разницу между полным значением ДатаВремяСобытия и началом этого дня в секундах.

Пример кода в запросе СКД:


РАЗНОСТЬДАТ(НАЧАЛОДНЯ(Т_Таблица.ДатаВремяСобытия), Т_Таблица.ДатаВремяСобытия, СЕКУНДА) КАК СекундыСНачалаДня

Где:

Это поле СекундыСНачалаДня будет иметь тип "Число" и отлично подойдет для математических операций, а также для сортировки. Чем больше секунд, тем позже время события. Если вам потребуется отобразить это число в привычном формате времени, вы можете использовать функции форматирования или написать свою функцию для преобразования секунд в формат "ЧЧ:ММ:СС".

Пример форматирования числа секунд в СКД для отображения (в вычисляемом поле):


// Предполагаем, что поле "СекундыСНачалаДня" уже существует
// Для отображения времени в формате ЧЧ:ММ:СС из секунд
Строка(ЦЕЛ(СекундыСНачалаДня / 3600)) + ":" + Строка(ЦЕЛ((СекундыСНачалаДня % 3600) / 60)) + ":" + Строка(СекундыСНачалаДня % 60)

Этот пример демонстрирует, как можно извлечь часы, минуты и секунды из общего количества секунд и скомбинировать их в строку. Для более аккуратного форматирования с ведущими нулями (например, "08:05:01" вместо "8:5:1") потребуется использовать дополнительные функции форматирования строк, например, через дополнение нулями до двух символов.

Решение 3: Использование функции Формат() исключительно для отображения

Как мы уже обсуждали, Формат() не подходит для сортировки. Однако, если наша цель — исключительно вывести временную часть в удобном для чтения виде, и при этом сортировка по времени будет производиться по другому (скрытому) полю (например, по полю, полученному через ВЫРАЗИТЬ(ДатаВремяСобытия КАК Время)), то Формат() вполне уместен.

Пример использования:

Формат(Т_Таблица.ДатаВремяСобытия, "ДЛФ=В") КАК ВремяДляОтображения

Или, если нужен только временной компонент без даты:

Формат(Т_Таблица.ДатаВремяСобытия, "ЧЧ:мм:сс") КАК ВремяДляОтображения

Поле ВремяДляОтображения будет строковым и будет использоваться только для вывода информации в отчете.

Пошаговая реализация в СКД

Давайте разберем, как внедрить выбранное решение в ваш отчет на СКД.

  1. Откройте схему компоновки данных.

    В конфигураторе или в пользовательском режиме (если у отчета есть такая возможность) откройте структуру отчета и перейдите на вкладку "Наборы данных".

  2. Добавьте вычисляемое поле.

    Перейдите на вкладку "Вычисляемые поля". Нажмите кнопку "Добавить" и создайте новое поле. Назовем его, например, ВремяСобытия.

  3. Укажите выражение для поля.

    В столбце "Выражение" для нового поля ВремяСобытия введите одно из описанных выше выражений. Например, для получения временного типа:

    
    ВЫБОР
        КОГДА ДатаВремяСобытия ЕСТЬ NULL
            ТОГДА NULL
        ИНАЧЕ ВЫРАЗИТЬ(ДатаВремяСобытия КАК Время)
    КОНЕЦ
    

    Обратите внимание: если вы пишете выражение в "Вычисляемых полях" СКД, вам не нужно указывать псевдоним таблицы (Т_Таблица.) перед именем поля ДатаВремяСобытия, так как СКД уже знает контекст.

  4. Настройте группировки и сортировки.

    Перейдите на вкладку "Настройки". Здесь мы можем определить, как наш отчет будет сгруппирован и отсортирован.

    1. Группировка по дате:

      Добавьте группировку по полю НАЧАЛОДНЯ(ДатаВремяСобытия), чтобы сгруппировать записи по датам.

      НАЧАЛОДНЯ(ДатаВремяСобытия)
    2. Сортировка по времени:

      Внутри этой группировки или в детальных записях добавьте сортировку по нашему новому полю ВремяСобытия (или СекундыСНачалаДня, если вы выбрали числовой подход). Убедитесь, что порядок сортировки установлен правильно (по возрастанию или убыванию).

  5. Добавьте поле в выбранные поля отчета.

    На вкладке "Настройки" в списке "Выбранные поля" убедитесь, что поле ВремяСобытия (или ВремяДляОтображения, если вы использовали его) добавлено и видимо в отчете.

  6. Проверьте результат.

    Сформируйте отчет и убедитесь, что данные сгруппированы по дате, а внутри каждой даты записи корректно отсортированы по времени, и временной компонент отображается так, как вы планировали.

Важные соображения и рекомендации

Таким образом, мы видим, что извлечение и корректная работа с временным компонентом поля ДатаВремя в СКД — это задача, которая имеет элегантные и эффективные решения. Выбрав подходящий метод из описанных, мы обеспечим не только правильное отображение данных, но и их функциональную пригодность для сортировки и анализа в отчетах 1С.

← На главную