Часовой пояс для PostgreSQL при доступе через клиент и DBeaver

У меня есть одна таблица в базе данных postgresql (версия движка 10.11) со столбцом с именем resettime, который имеет тип данных как timestamptz. Часовой пояс по умолчанию для базы данных — Австралия/Сидней.

Столбец resettime имеет значение по умолчанию как timezone('UTC'::text, now()).

Я выполнил следующую команду, чтобы установить этот столбец в DBEaver.

update mytable set resettime = timezone('UTC', now()) + interval '1 hour' where id = 1;

Текущее время UTC – 11:47, соответствующее время AEST – 21:47.

После выполнения приведенного выше оператора я попытался получить время сброса с помощью следующего оператора в DBEaver.

select resettime from mytable where id=1

Из этого заявления я получил 2020-09-14 12:47:25.

Затем я запускаю следующую команду в DBEaver.

update mytable set resettime = resettime + interval '1 hour' where resettime < timezone('UTC', now());

После запуска этой команды я проверяю время сброса для записи с id=1, я обнаружил, что время сброса было сохранено, как я и ожидал. Это нормально.

Однако, когда я запустил тот же оператор обновления в своем приложении scala, он обновил время сброса как 2020-09-14 13:47:25. У меня такое ощущение, что время сброса по-прежнему считается временем AEST, если я получил к нему доступ через приложение scala. Я не хочу менять настройки часового пояса по умолчанию на UTC.

Как я должен убедиться, что мое приложение scala также ведет себя так же, как мой доступ через DBEaver? В приведенном выше примере я надеюсь, что время сброса не будет изменено моим приложением scala для запуска того же оператора обновления. Спасибо!


person yyuankm    schedule 14.09.2020    source источник


Ответы (1)


Проблема в том, что timezone('UTC', now()) преобразует текущую метку времени в timestamp without time zone — результатом является текущая метка времени, как она выглядела бы на часах, настроенных на время UTC.

Затем, когда вы присваиваете результат resettime, который является timestamp with time zone, значение преобразуется обратно, но на этот раз в соответствии с вашей текущей настройкой параметра timezome (который отличается от UTC).

Итак, сначала вы спрашиваете, как сейчас выглядят часы UTC, а затем интерпретируете результат в вашем текущем часовом поясе. Как следствие, вы получите значение, которое смещено.

Простое и правильное решение — вообще не преобразовывать два типа меток времени, а придерживаться timestamp with time zone:

update mytable
set resettime = now() + interval '1 hour'
where id = 1;

Это сделает именно то, что вы хотите.

person Laurenz Albe    schedule 14.09.2020
comment
Спасибо, Лоренц. Это очень хороший момент. Проблема в том, что мой часовой пояс по умолчанию должен быть AEST. Мне также нужно использовать мое приложение scala, чтобы установить начальное значение для времени сброса. Мое приложение scala использует часовой пояс UTC, поэтому я не могу использовать now() напрямую. Я также попробовал заменить timezone('UTC', now()) на CURRENT_TIMESTAMP AT TIME ZONE 'UTC' для всех вышеперечисленных команд, чтобы убедиться, что информация о часовом поясе сохранена. Однако та же проблема все еще существует. - person yyuankm; 14.09.2020
comment
CURRENT_TIMESTAMP AT TIME ZONE 'UTC' удаляет информацию о часовом поясе. Я не понимаю, почему вы не можете использовать now(), так как это временная метка с часовым поясом. Помните, что все временные метки с данными о часовых поясах хранятся в формате UTC, а затем отображаются в соответствии с настройками вашего сеанса. - person Jeremy; 14.09.2020
comment
Хм, я не знаю, как научить Scala делать очевидное. Но любой достойный ORM должен иметь способ сделать это. Если ничего не помогает, вы можете ALTER TABLE mytable ALTER resettime DEFAULT current_timestamp + INTERVAL '1 hour';, а затем UPDATE mytable SET resettime = DEFAULT WHERE id = 1;. - person Laurenz Albe; 14.09.2020
comment
Спасибо, Джереми Лоренц, просто дайте немного обновлений. Я изменил использование now() в своем приложении scala. Это работает. - person yyuankm; 18.09.2020