Временные зоны
В статье собрана полная информация по работе с временными зонами в платформе WT.
Временные зоны в БД
В таблице public.time_zone_info хранится полный список доступных временных зон.
В колонке name указано имя временной зоны в формате IANA. В колонке id_title указан ключ для получения названия временной зоны из таблицы строковых ресурсов public.strings с учетом локали приложения. В колонке by_default отмечается временная зона по умолчанию, которая будет присваиваться новым пользователям.
В таблице public.timezone_intervals для каждой временной зоны хранится полная история сдвигов относительно UTC.
В колонках date_utc и date_local указана начальная дата периода, в котором применялся сдвиг из колонки offset.
Настройки
Временная зона сервера
Даты со временем хранятся в базе данных во временной зоне сервера, по умолчанию это Etc/GMT. Чтобы задать иную временную зону, необходимо в серверный файл настроек (appsettings.json) добавить строки:
В качестве значения вложенного поля TimeZone ожидается имя временной зоны в формате IANA, которое можно взять в таблице public.time_zone_info в поле name.
Временная зона клиента
Для задания временной зоны клиента используется колонка time_zone_info_id в таблице public.user.
По умолчанию новым клиентам присваивается идентификатор временной зоны со значением True
в колонке by_default
.
На временную зону клиента не влияют настройки часового пояса в системе Windows.
Правила передачи времени между сервером и клиентом
Дата со временем
Дата со временем (в формате даты) между клиентом и сервером всегда передается в UTC.
Когда дату со временем передаем с формы на сервер, клиентская часть автоматически переводит время из временной зоны клиента в UTC, а сервер полученную дату переводит из UTC в свою временную зону.
Аналогичное преобразование происходит и в обратную сторону. Сервер получает дату со временем из база данных, переводит ее в UTC и передает клиентской части. Клиент, получив дату со временем, переводит ее из UTC в свою временную зону.
Дата или время
Если между клиентом и сервером передается только дата или только время, то значение не переводится в UTC. Сервер, получив дату или время, запишет их в базу данных без приведения к своей временной зоне.
Как работает приведение
Автоматическое преобразование
Автоматическое преобразование происходит на стороне сервера и клиента только для дат со временем.
Для текущей временной зоны пользователя на основе таблицы public.timezone_intervals строится два словаря временных интервалов: один для перевода времени из UTC в клиентскую временную зону, второй для обратного приведения. Для первого словаря используются колонки date_utc и offset, а для второго - date_local и offset. Оба словаря передаются клиентскому приложению. Подобные словари строятся и для сервера для его временной зоны.
Для даты со временем находится наименьший интервал, значение сдвига которого либо добавляется к дате со временем, если идет преобразование из UTC, либо вычитается, если идет преобразование в UTC.
Ручное преобразование
Ручное преобразование дат или времени на стороне сервера следует реализовывать в трех случаях.
Даты в фильтрах
Дата или время передаются с формы на сервер для фильтрации данных по полю типа timestamp (дата со временем).
Пример подробно разбирается в уроке 7 в разделе Временные зоны и фильтры по дате.
Для такого преобразования используется функция:
Первое использование конструкции at time zone
означает, что дата указана во временной зоне пользователя (переменная _time_zone_name), а второе использование конструкции at time zone
указывает временную зону сервера, к которой необходимо преобразовать время. Для получения временной зоны сервера используется обращение к параметру конфигурации ws.server_time_zone
.
В конце статьи есть описание параметров конфигурации и конструкции at time zone
.
Даты в JSON-объекте
Когда на сервер приходит JSON-объект, то он обрабатывается как строка без автоматического преобразования дат со временем. При формировании JSON-объекта, как правило, даты приводятся к UTC. А преобразование к временной зоне сервера необходимо реализовать самостоятельно.
JSON-объекты могут приходить либо с форм (урок 26 - Работа с JSON на форме), либо от сторонних сервисов через кастомные API-запросов (урок 25 - Кастомные типы параметров).
Для такого преобразования используется функция:
Даты в строках
Иногда бывают ситуации, когда на стороне сервера собирается строка и отправляется клиенту. В таком случае необходимо сразу привести дату со временем из временной зоны сервера во временную зону клиента, которому отправится готовая строка.
Для такого преобразования используется функция:
Дополнительные материалы
Параметры конфигурации
В приведенных выше SQL-функциях используются параметры конфигурации, значения которым сервер задает, выполняя перед каждым обращением к базе данных системные запросы.
Первым запросом серверу PostgreSQL для текущего сеанса устанавливается временная зона:
В запросе используется значение временной зоны сервера из серверного файла настроек (appsettings.json).
Вторым запросом задаются значения параметрам конфигурации:
Тексты этих запросов указываются в описании ошибки в журнале событий Windows.
Конструкция at time zone
at time zone
Рассмотрим на примерах, как работает конструкция at time zone
.
Допустим, что в качестве временной зоны сервера PostgreSQL задано значение Europe/Moscow, которую можно задать с помощью запроса:
Начнем с запроса приведения строки с датой и временем к типу timestamp:
Результатом запроса будет значение типа timestamp without time zone:
Считается, что это значение во временной зоны сервера PostgreSQL (Europe/Moscow).
Добавим в запрос конструкцию at time zone
с заданием часового пояса UTC:
Результатом запроса будет значение типа timestamp with time zone:
Время изменилось на 3 часа, что соответствует временному сдвигу для часового пояса Europe/Moscow относительно UTC.
Конструкция at time zone
говорит, что дата и время указаны во временной зоне 'utc', сколько это будет во временной зоне сервера PostgreSQL(Europe/Moscow). Таким образом, произошло неявное приведение времени из UTC во временную зону сервера.
Рассмотрим пример, когда дата и время указаны во временной зоне Asia/Yekaterinburg, и мы хотим узнать, сколько это будет во временной зоне сервера PostgreSQL(Europe/Moscow):
Результатом запроса будет значение типа timestamp with time zone:
Произошло вычитание 2х часов из времени, что соответствует разнице между зонами Asia/Yekaterinburg и Europe/Moscow.
Если необходимо явно привести время к нужной временной зоне, то следует указывать вторую конструкцию at time zone
:
Результатом запроса будет значение типа timestamp without time zone:
Первое использование конструкции at time zone
означает, что дата указана во временной зоне Europe/Moscow, а второе использование конструкции at time zone
указывает временную зону Asia/Yekaterinburg, к которой необходимо преобразовать время.
Текущее время
При запуске серверной части приложения отправляется запрос на сторонний сервис для получение точного времени в UTC.
Если сервис не отвечает, то запрос отправляется на сервер WS.Server (общий для всех приложений), который предоставляет текущее время UTC из операционной системы.
Получив текущее время UTC, серверная часть приложения вычисляет смещение между полученным временем UTC и своим временем. Вычисленное смещение записывается в базу данных.
Если сервер WS.Server не отвечает и смещение уже записано в базу данных, то ничего не происходит. Если смещение отсутствует в базе данных, то берется текущее время UTC из Windows, на котором запускается веб-сервер.
Этот алгоритм отрабатывается раз в сутки, чтобы на сервере хранилась актуальная информация о смещении.
Смещение времени серверной части относительно точного времени UTC необходимо для корректного расчета текущего времени во временных зонах сервера и пользователя на формах.
Last updated