web-dev-qa-db-ja.com

Javaを使用してデータベース接続でMySQLタイムゾーンを変更する方法は?

MySQLはタイムゾーン「GMT + 8」で動作しますが、Tomcatは「GMT」で動作します。 datetimeをデータベースに保存すると、すべて問題ないようですが、データベースのdatetime値を確認すると、「GMT」値が表示されます。

また、データベースから値を取得しようとすると、値が変更されます。データベースの値は「GMT + 8」と見なされるため、Javaは値を「GMT」に変更します。

接続URLを次のように設定しました。

useTimezone=true&serverTimezone=GMT

しかし、それは機能しません。

39
Xilang

useTimezoneは古い回避策です。 MySQLチームは最近setTimestamp/getTimestampコードを書き直しましたが、接続パラメーターuseLegacyDatetimeCode = falseを設定し、最新バージョンのmysql JDBCコネクターを使用している場合にのみ有効になります。たとえば、次のとおりです。

String url =
 "jdbc:mysql://localhost/mydb?useLegacyDatetimeCode=false

Mysql-connectorのソースコードをダウンロードしてsetTimestampを見ると、何が起こっているかを簡単に確認できます。

レガシーの日時コード= falseを使用すると、newSetTimestampInternal(...)が呼び出されます。次に、newSetTimestampInternalに渡されたカレンダーがNULLの場合、日付オブジェクトはデータベースのタイムゾーンでフォーマットされます。

this.tsdf = new SimpleDateFormat("''yyyy-MM-dd HH:mm:ss", Locale.US);
this.tsdf.setTimeZone(this.connection.getServerTimezoneTZ());
timestampString = this.tsdf.format(x);

Calendarがnullであることは非常に重要です-使用していることを確認してください:

setTimestamp(int,Timestamp).

... setTimestamp(int、Timestamp、Calendar)ではありません。

これがどのように機能するかは明らかです。日付を構築する場合:Java.util.Calendarを使用して、America/Los_Angeles(または任意のタイムゾーン)で2011年1月5日午前3:00にsetTimestamp(1、myDate)を呼び出し、日付を取得します。SimpleDateFormatを使用します。 データベースタイムゾーンでフォーマットします。そのため、DBがAmerica/New_Yorkにある場合、挿入される文字列 '2011-01-05 6:00:00'が構築されます(NYはLAより3時間進んでいるため)。

日付を取得するには、getTimestamp(int)(カレンダーなし)を使用します。もう一度、データベースのタイムゾーンを使用して日付を作成します。

注:Webサーバーのタイムゾーンは現在完全に無関係です! useLegacyDatetimecodeをfalseに設定しない場合、Webサーバーのタイムゾーンがフォーマットに使用され、多くの混乱が生じます。


注意:

MySQLがサーバーのタイムゾーンがあいまいであると不平を言う可能性があります。たとえば、データベースがESTを使用するように設定されている場合、Javaには複数のESTタイムゾーンが存在する可能性があるため、データベースのタイムゾーンを正確に伝えることでmysql-connectorのこれを明確にできます。

String url =
 "jdbc:mysql://localhost/mydb?useLegacyDatetimeCode=false&serverTimezone=America/New_York";

文句を言う場合にのみこれを行う必要があります。

76
nogridbag

JDBCはいわゆる「接続URL」を使用するため、「+」を「%2B」でエスケープできます。

useTimezone=true&serverTimezone=GMT%2B8
1
Jay