Неправильный часовой пояс при импорте данных через HTTP-интерфейс

371 views
Skip to first unread message

Владислав Денисов

unread,
Oct 28, 2016, 12:36:14 PM10/28/16
to ClickHouse
Столкнулся с такой проблемой. Суть в заголовке.

Импортирую таким образом – всё ок:
echo -ne "'test', '2016-10-28 09:59:59','2016-10-28'" | clickhouse-client --query="INSERT INTO analytics.test FORMAT CSV";

С той же машины, но curl'ом – на 3 часа больше:
echo "INSERT INTO analytics.test VALUES ('test', '2016-10-28 09:59:59','2016-10-28')" | curl 'url' --data-binary @-

Вот такой ответ:
:) select * from analytics.test

┌─app_name─┬─────────update_time─┬─update_date─┐
│ test     │ 2016-10-28 12:59:59 │  2016-10-28 │
└──────────┴─────────────────────┴─────────────┘
┌─app_name─┬─────────update_time─┬─update_date─┐
│ test     │ 2016-10-28 09:59:59 │  2016-10-28 │
└──────────┴─────────────────────┴─────────────┘

Не подскажете, как избежать? В документации не нашел примеров передачи данных с тайм-зоной.

man...@gmail.com

unread,
Oct 29, 2016, 6:40:08 PM10/29/16
to ClickHouse
Тип данных DateTime хранит абсолютный момент времени. Внутреннее представление - unix timestamp: число секунд прошедших с 1 января 1970 в UTC.
Таким образом, хранимые в таблице данные (данные, которые уже записаны в таблицу), не зависят от часовых поясов и не содержат информации о часовых поясах.

Существуют форматы данных для ввода и вывода (для представления результата SELECT и для записи данных при INSERT), в которых DateTime представлен в разобоанном по компонентам, текстовом виде: YYYY-MM-DD hh:mm:ss. В частности, в формате Values при INSERT-е, и в формате PrettyCompact, который использует clickhouse-client для вывода результата в интерактивном режиме, DateTime представлен в таком текстовом виде.
Это значит, что при вводе или выводе данных в таких форматах, требуется выполнить преобразование из unix timestamp в разобранный вид или наоборот.

Чтобы перевести unix timestamp в вид YYYY-MM-DD hh:mm:ss или наоборот, прочитать из такого текстового вида unix timestamp, используется некоторый часовой пояс. В случае, если преобразованием формата занимается сервер, используется часовой пояс сервера, а если клиент - часовой пояс клиента.

Судя по вашему примеру, у вас используется часовой пояс UTC на сервере и Europe/Moscow на клиенте.
Рассмотрим подробнее, что происходит.


echo -ne "'test', '2016-10-28 09:59:59','2016-10-28'" | clickhouse-client --query="INSERT INTO analytics.test FORMAT CSV";

- клиент взял время 2016-10-28 09:59:59 по Москве, преобразовал его в unix timestamp и отправил на сервер. Сервер сохранил его в таблицу.

echo "INSERT INTO analytics.test VALUES ('test', '2016-10-28 09:59:59','2016-10-28')" | curl 'url' --data-binary @-

- программа curl отправила по http на сервер текст, содержащий 2016-10-28 09:59:59.
Сервер получил этот текст и преобразовал его в unix timestamp согласно своему часовому поясу. Это получилось

2016-10-28 09:59:59 в UTC.


:) select * from analytics.test

┌─app_name─┬─────────update_time─┬─update_date─┐
│ test     │ 2016-10-28 12:59:59 │  2016-10-28 │
└──────────┴─────────────────────┴─────────────┘
┌─app_name─┬─────────update_time─┬─update_date─┐
│ test     │ 2016-10-28 09:59:59 │  2016-10-28 │
└──────────┴─────────────────────┴─────────────┘

Клиент запросил с сервера данные. Сервер отправил ему даты-с-временем во внутреннем формате (unix timestamp). Клиент получил эти данные, и преобразовал в текстовый вид, используя часовой пояс клиента - Europe/Moscow.
Заметим, что когда в UTC 2016-10-28 09:59:59, то в Москве уже 2016-10-28 12:59:59.


Какие есть возможности управлять часовыми поясами?

Во-первых, вы можете выставить часовой пояс при запуске клиента. Вот пример на моей машине:

$ clickhouse-client --query="SELECT now()"
2016-10-29 21:38:04
$ TZ=UTC clickhouse-client --query="SELECT now()"
2016-10-29 18:38:09

Во-вторых, в ClickHouse есть функции преобразования часовых поясов.

https://clickhouse.yandex/reference_ru.html#%D0%9F%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B6%D0%BA%D0%B0%20%D1%87%D0%B0%D1%81%D0%BE%D0%B2%D1%8B%D1%85%20%D0%BF%D0%BE%D1%8F%D1%81%D0%BE%D0%B2

Владислав Денисов

unread,
Oct 29, 2016, 9:00:23 PM10/29/16
to ClickHouse
Спасибо! Ответ более чем подробный.

С временными зонами натупил, действительно. Сбивал параметр event_date, который в таком случае "отсекал" первые три часа дня и добавлял их к следующему. Получалось, что для event_date '2016-10-24' у меня в другой тайм-зоне были event_time с '2016-10-24 03:00:00' по '2016-10-25 2:59:59'.

суббота, 29 октября 2016 г., 21:40:08 UTC+3 пользователь man...@gmail.com написал:
Reply all
Reply to author
Forward
0 new messages