Как округлить время в дате до ближайшего часа в запросе 1С?

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

При построении отчетов, группировке интервалов и подготовке аналитических выборок нередко возникает задача округлить дату до целого часа по правилам математического округления: если количество минут равно или превышает 30, округляем в большую сторону (к началу следующего часа), а если меньше 30 — отбрасываем минуты и округляем в меньшую сторону (к началу текущего часа).

Разберем различные подходы к решению этой задачи на языке запросов 1С:Предприятие, а также рассмотрим особенности обработки дат во встроенном языке.

Способ 1. Условная конструкция ВЫБОР в запросе

Проанализируем базовый вариант, предложенный на форуме. В нем используется ветвление с помощью оператора ВЫБОР и стандартных функций работы с датами:


ВЫБОР
    КОГДА МИНУТА(&Дата) >= 30 
        ТОГДА ДОБАВИТЬКДАТЕ(КОНЕЦПЕРИОДА(&Дата, ЧАС), СЕКУНДА, 1)
    ИНАЧЕ НАЧАЛОПЕРИОДА(&Дата, ЧАС)
КОНЕЦ

Разберем по шагам логику работы данного выражения:

  1. Функция МИНУТА(&Дата) извлекает текущее значение минут (от 0 до 59).
  2. Если минут 30 или больше, берется конец текущего часа с помощью функции КОНЕЦПЕРИОДА(&Дата, ЧАС) (получаем значение вида 01:59:59).
  3. К полученному значению добавляется одна секунда через ДОБАВИТЬКДАТЕ(..., СЕКУНДА, 1), что дает ровно 02:00:00.
  4. Если минут меньше 30, срабатывает ветка ИНАЧЕ, где функция НАЧАЛОПЕРИОДА(&Дата, ЧАС) отсекает минуты и секунды, возвращая 01:00:00.

Способ 2. Оптимальное округление через смещение на 30 минут

Рассмотрим более компактный и производительный способ, не требующий ветвления CASE WHEN на стороне СУБД. Суть метода заключается в предварительном сдвиге исходной даты вперед на половину целевого интервала (на 30 минут) с последующим получением начала часа:

НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&Дата, МИНУТА, 30), ЧАС)

Посмотрим на пример работы этого алгоритма:

  1. Значение меньше границы: если время 01:29:59, после добавления 30 минут мы получаем 01:59:59. Функция НАЧАЛОПЕРИОДА(..., ЧАС) возвращает 01:00:00 (округление вниз).
  2. Значение на границе: если время 01:30:00, после сдвига получается 02:00:00. Функция НАЧАЛОПЕРИОДА вернет 02:00:00 (округление вверх).
  3. Значение больше границы: если время 01:45:00, после прибавления 30 минут получаем 02:15:00, и начало часа даст 02:00:00.

Этот вариант короче в написании, легче читается и эффективнее выполняется сервером баз данных.

Способ 3. Округление до произвольного интервала времени

Если требуется округлить дату не строго до часа, а до произвольного шага (например, 15, 30 минут или 2 часа), используем пересчет разницы секунд относительно фиксированной базовой даты:


ДОБАВИТЬКДАТЕ(
    ДАТАВРЕМЯ(2000, 1, 1), 
    СЕКУНДА, 
    ВЫРАЗИТЬ((РАЗНОСТЬДАТ(ДАТАВРЕМЯ(2000, 1, 1), &Дата, СЕКУНДА) + 1800) / 3600 КАК ЧИСЛО(15, 0)) * 3600
)

В этой формуле число 3600 — это размер интервала в секундах (1 час), а 1800 — половина этого интервала (30 минут). Для шага в 15 минут достаточно заменить эти коэффициенты на 900 и 450 соответственно.

Важные нюансы и ограничения платформы

При работе с операциями над датами в запросах необходимо учитывать следующие особенности платформы 1С:

  1. Переход через сутки и года: функции ДОБАВИТЬКДАТЕ и КОНЕЦПЕРИОДА платформы корректно обрабатывают переход между днями (например, с 23:40 на 00:00 следующего дня) и смену календарного года.
  2. Учет секунд: при использовании условия МИНУТА(&Дата) >= 30 секунды игнорируются. Если требуется строго учитывать время вплоть до секунды (например, 01:29:59), метод со смещением ДОБАВИТЬКДАТЕ(&Дата, МИНУТА, 30) или сдвиг по секундам работает математически точнее.
  3. Границы типа Дата: максимальная поддерживаемая дата в платформе — 31.12.3999 23:59:59. Прибавление минут к граничным датам может приводить к ошибке переполнения.

Округление даты во встроенном языке (вне запроса)

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

ОкругленнаяДата = НачалоЧаса(ИсходнаяДата + 1800);

Здесь к значению переменной ИсходнаяДата прибавляется 1800 секунд (30 минут), а затем функция НачалоЧаса() отсекает лишние минуты и секунды, возвращая требуемый результат.

← На главную