Подтвердить что ты не робот

PostgreSQL 9.2 Драйвер JDBC использует часовой пояс клиента?

Я столкнулся с интересной задачей, используя базу данных PostgreSQL с драйвером JDBC PostgreSQL. Похоже, что последняя версия драйвера 9.2 использует часовой пояс клиента при выполнении совпадений даты/времени.

Это становится проблемой, когда сервер (сервер JasperReports) установлен в UTC, а сервер базы данных установлен в US/Eastern.

Если я запустил следующий запрос от клиента, установленного в часовой пояс UTC, я получаю разные результаты, используя драйвер 9.0 JDBC и драйвер JDBC 9.2.

select now(), extract(timezone FROM now()), current_setting('TIMEZONE'), now()-interval '1 hour' as "1HourAgo"

Результаты с использованием драйвера 9.0 JDBC:

now                         date_part   current_setting     1HourAgo
2013-08-26 15:33:57.590089  -14,400     US/Eastern          2013-08-26 14:33:57.590089

Результаты с использованием 9.2 драйвера JDBC:

now                         date_part   current_setting     1HourAgo
2013-08-26 15:41:49.067903  0           UTC                 2013-08-26 14:41:49.067903

Это приводит к тому, что оператор запроса WHERE в запросе возвращает неверные результаты. Например,

WHERE end_time between now() - interval '1 hour' and now()

работает как ожидалось, используя драйвер 9,0, но не возвращает результаты с использованием драйвера 9,2, поскольку драйвер, как представляется, компенсирует значение end_time для соответствия UTC (часовой пояс клиента). Ниже приведено обходное решение, но уродливое:

WHERE end_time at time zone 'EDT' between now() - interval '1 hour' and now()

Вопросы:

  • Кто-нибудь еще сталкивается с этим раньше?
  • Есть ли объяснение этого изменения в поведении? Я не смог найти что-либо в примечаниях к выпуску JDBC.
  • Любые советы о том, как обойти это, кроме отката драйвера к более старой версии?

Спасибо!

4b9b3361

Ответ 1

Я сам столкнулся с этим вопросом. Я подтвердил, что драйвер postgres jdbc действительно собирает часовой пояс соединения из jvm, и я не смог найти способ переопределить это поведение. Было бы неплохо, если бы они предоставили для этой цели параметр подключения URL-адреса jdbc.

В качестве обходного пути я обнаружил, что моя библиотека пула соединений (HikariCP) может выполнять оператор sql для каждого нового соединения:

hikariConfig.setConnectionInitSql("set time zone 'UTC'");

Ответ 2

Использование локального часового пояса в качестве часового пояса по умолчанию требуется стандартом JDBC (и документацией API) и явно выражается PreparedStatement.setTimestamp. Однако это также относится ко всем другим областям, где JDBC устанавливает или извлекает временные данные.

См. также мой ответ на Является ли java.sql.Timestamp конкретным часовым поясом?

Ответ 3

На всякий случай другие борются с этим - вы можете отредактировать файл conf, запускающий SQLDeveloper, и добавить следующую строку:

AddVMOption -Duser.timezone=UTC

Я нашел этот файл на своей машине по адресу:

/opt/sqldeveloper/ide/bin/ide.conf

Благодаря @a_horse_with_no_name для указания меня в правильном направлении с комментарием в одном из других ответов

Ответ 4

Я не знаю JasperReports, но, вообще говоря, использование типов даты и времени JSR-310 (Java 8) (поддерживаемых JDBC 4.2) должно работать, не беспокоясь о несоответствиях часовых поясов между сервером базы данных и клиентом.

См. Использование классов Java 8 Дата и время в документации драйвера JDBC PostgreSQL.