0

次の SQL を発行すると、PL/SQL、ODBC、および JDBC を介して異なる結果が生成されます。

select sysdate from dual

PL/SQL または ODBC で実行すると、日付と時刻が正しくなります。JDBC では、1 時間短縮されます。サマータイムは考慮していないようです。

たとえば、PL/SQL では結果は2012-11-05 16:53:53.0であり、JDBC では です2012-11-05 15:53:53.0

一部のデータベースでのみ発生します。データベースのタイムゾーン ( select dbtimezone from dual) を変更しても、結果には影響しないようです。

コマンドはブラジルで実行中です。生の GMT オフセットは -03:00 で、現在のオフセットは夏時間のため -02:00 です。

クライアント JVM のタイムゾーン データベースは最新です。

データベースからの「間違った」結果を診断するには、結果を出力するだけです。

((OracleResultSet) statement.executeQuery("select sysdate from dual")).getTIMESTAMP(1).toString();

Oracle のTIMESTAMP toString方法は、タイムゾーン情報に依存しません。JVM のタイムゾーンは、 の作成前TIMESTAMP、つまりネットワークから読み取り、それを Java での表現に変換するときにのみ結果に影響を与える可能性があります。

クライアントとデータベース サーバーの両方の時間構成を変更するテスト:

  • SYSDATE常にデータベース サーバーで解決された日付/時刻を返します。クライアント JVM のuser.timezoneオプションとクライアントのマシン時間構成は問題ではありません。
  • 一方、取得SYSTIMESTAMPは両方のタイムゾーン情報を使用して解決されます。UTC でサーバーから日付と時刻を取得し、クライアントでタイムゾーンを適用してローカルの日付と時刻を取得するように見えます。

クライアントは Windows を実行しており、サーバーは Linux を実行しています。

さらに奇妙なことに、発行するTO_CHARと間違った結果が得られます。

select TO_CHAR(SYSDATE, 'DD/MM/YYYY HH24:MI:SS') from dual
  • Oracle で直接:06/11/2012, 10:38:49
  • Java の場合:06/11/2012 09:38:49

Oracle サーバー:

[root@oracle1 ~]# cat /etc/sysconfig/clock
ZONE="America/Sao_Paulo"
UTC=false
ARC=false
[root@oracle1 ~]# echo $TZ

[root@oracle1 ~]# date
Tue Nov 13 14:58:38 BRST 2012
[root@oracle1 ~]#


[root@oracle2 ~]# cat /etc/sysconfig/clock
ZONE="America/Sao_Paulo"
UTC=false
ARC=false
[root@oracle2 ~]# echo $TZ

[root@oracle2 ~]#  date
Tue Nov 13 14:59:58 BRST 2012
[root@oracle2 ~]#

何かご意見は?この問題を診断して解決するには、データベースからどの情報または構成を収集する必要がありますか?

4

4 に答える 4

2

簡単に言えば、オラクルDATEを Javaに選択することDateは本質的に問題があります。根本的に違うからです。オラクルDATEは、年、月、日、時、分、秒の組み合わせであり、タイムゾーン情報はありません。したがって、夏時間の有無にかかわらず、任意のタイムゾーンである可能性があります-その情報は含まれていないため、オラクルは知りませんDATE。_

一方、Java Date は基本的に、1970 年 1 月 1 日 00:00:00 UTC からのミリ秒数です。

OracleDATEが Javaに入るDateと、JDBC ドライバーは適用するタイムゾーンを推測することしかできません。特にデータベース内のデータがユーザーとは別のタイムゾーンを使用している場合、結果はかなり予測できません。

于 2012-11-06T13:08:34.213 に答える
0

Java Dates には、フォーマットするまでタイムゾーンがありません。

Java の日付は、1970 年 1 月 1 日午前 0 時 (UTC) から経過したミリ秒数である long として内部的に格納されます。

Java Date の時刻と、報告されたタイム ゾーン (フォーマットは問わない) を確認すると、おそらくデータベースの時刻と同じであることがわかります。

日付のフォーマットに問題がある可能性が最も高いです - 期待していないタイムゾーンを使用しています。フォーマット時にタイムゾーンを指定していないか(デフォルトのものを使用)、または単に Date の toString() メソッドを使用していると思います。

カレンダー (calendar.setTime(date)) を使用する場合、「エポック タイム」を特定のタイム ゾーンと組み合わせることができます。それが機能する場合は、デフォルトのタイム ゾーンを使用します。Calendar のタイムゾーンを照会することもできます。デフォルトのタイムゾーンが正しくない場合は、コンピューター自体が間違ったタイムゾーンに設定されているかどうか、またはそのコンピューターの Java タイムゾーン データベースに問題があるかどうかを実際に調査する必要があります。 .

于 2012-11-05T19:45:51.877 に答える
0

「Java Dates には、フォーマットするまでタイムゾーンがありません。」間違っています。UTC として定義されています。ammoQ による元の回答は正しいです。データベースの日付列にはタイムゾーンがありませんが、1970 年 1 月 1 日午前 0 時からのミリ秒単位で保存される場合があります。UTC として定義されていません。任意のタイムゾーンです (つまり、タイムゾーンに関係なく同じ現地時間)。

特に、JDBC は UTC で Java Date に変換するときに JVM のデフォルトのタイムゾーンを使用します。したがって、データベースに 1/1/2014 02:00 が格納され、JVM が「America/Chicago」である場合、Java Date は 1/1/2014 02:00 CST に相当します。JVM が「America/New_York」の場合、Java Date は 2014 年 1 月 1 日 02:00 EST に相当します。これは非常に異なる瞬間であり、1 時間 (3600000 ミリ秒) 違います。これはたまたま 2014 年 1 月 1 日 01:00 CST に相当し、02:00 CST ではありません。

ただし、JVM のタイムゾーンを使用する際の最大の問題は、そのタイムゾーンが夏時間を尊重している場合、毎年「オーバーラップアワー」の間に発生します。データベースは、フォールバック日曜日 (米国タイムゾーン) の 01:30 と表示しますが、夏時間の最初の 01:30 と、標準時間に戻った後の 2 番目の 01:30 はどちらでしょうか? JDBC/JVM は、これら 2 つの時点のいずれかを任意に選択する必要があります。私が思い出したように、ほとんどの JVM は常に標準時 (2 番目の 01:30) を使用すると思います。春から夏時間への移行中は、技術的には 02:30 という時間は存在しませんが、ほとんどの JVM は春から夏時間への移行後に 03:30 を想定すると思います。

于 2014-07-13T16:43:58.917 に答える