三のオフセット
。しかし、いくつかの控除をすると、理論、3つのオフセットの理論があります。 8時間のUTCの後ろの値を持つ
スタート→2016-12-12 10:06:39.582-08
UTCに→2016-12-12 18:06:39.582Z
を調整不器用サンセリフ→2016-12-12 23:36:39.582
をオフセット報告
+05:30
→
2016-12-12 23:36:39.582+05:30
のオフセットに調整します
コアの問題を解決するためにthe Answer of Laurenz Albeに感謝します。私はちょうどここで言葉のナレーションを追加しました。
用語のカップル:
- offset-from-UTCは、たとえば
+05:00
のために、UTCから時間と分と秒数です。
- タイムゾーンは、夏時間(DST)などの異常を処理するための規則のセットであるとのオフセットです。
America/Montreal
のような適切な名前のcontinent/region
。
あなたの入力2016-12-12 10:06:39.582-08
は、北アメリカの西海岸の多くで使用されているUTCより8時間遅れた瞬間を表します。
あなたはその値をPostgresに保存しました。あなたは正確に言わないが、私はテーブルの列がタイプTIMESTAMP WITH TIME ZONE
であると仮定します。
Postgresでは、このタイプは「付随するオフセット/ゾーン情報に関して、受信値をUTCに調整する」という意味です。 Postgresは付随するオフセット/ゾーン情報を破棄します。私は繰り返すが、Postgresはではない。は日付/時刻型ではなく、オフセット/ゾーンを記憶したり覚えている。 WITH
タイプとTIMESTAMP WITHOUT TIME ZONE
の違いは、WITHOUT
タイプのオフセット/ゾーン情報がすべて無視され、調整が行われていないことです。
したがって、2016-12-12 10:06:39.582-08
をPostgresに送信したとき、その値は自動的に2016-12-12 18:06:39.582Z
に調整されました。 Z
は、Zuluの略でUTCを意味します。また、Postgresはではなく、という文字列を格納する代わりに、の代わりに、独自の内部バイナリ記憶形式を使用します。これらの文字列は、この議論の中で人間が読むためのものです。
とにかく、その調整をUTCに戻してください。 10
時間から18
時間に時間がどのように変更されたかに注意してください。これは、UTCからUTCまでの8時間から8時間の追加が8時間の追加を意味するためです。
だから、この値を保存する作業はうまくいきます。まったく同じ瞬間を記録しました。2016-12-12 10:06:39.582-08
と2016-12-12 18:06:39.582Z
の両方が非常に同じ瞬間でしたが、2つの異なるwall-clock time値のレンズを通して見ました。これまでのことはすべて適切かつ賢明です。
後でPostgresデータベースから2016-12-12 18:06:39.582Z
の値を取得しました。 JDBCを使用してデータをjava.sql.Timestamp
オブジェクトに抽出したようです。そこに問題があります。このクラスは、Javaの初期バージョンにバンドルされている古い日時クラスの1つです。業界標準の日時処理の試みとして賞賛される一方で、これらのクラスは混乱し、面倒で、欠陥があることが証明されています。可能な限り避けてください。それらは今やlegacyであり、java.timeクラスに置き換えられています。
これらのレガシー日時クラスの多くの問題の中には、toString
メソッドの実装があります。 Thee toString
のメソッドは、JVMの現在のタイムゾーンを暗黙的に適用することに熱心です。非常に多くのJavaプログラマーに混乱が生じることはありません。この混乱の別の例として、この質問を追加してください。
まず、この暗黙的なタイムゾーンの適用について説明します。まず、現在の瞬間をUTCで、Instant
として取得します。
Instant instant = Instant.now();
JVMの現在のデフォルトタイムゾーンとそのオフセットを確認するには、チェックしてください。
ZoneId z = ZoneId.systemDefault(); // Get current default time zone of this JVM.
String offset = z.getRules().getOffset (instant).toString(); // Extract the offset-from-UTC from our default time zone.
最後には、そのtoString
メソッドの動作を確認するためにjava.sql.Timestamp
を作ります。
java.sql.Timestamp ts = new java.sql.Timestamp (instant.toEpochMilli());
コンソールにダンプします。
System.out.println ("instant.toString(): " + instant);
System.out.println ("z.toString(): " + z);
System.out.println ("offset.toString(): " + offset);
System.out.println ("ts.toString(): " + ts);
instant.toString():2016-12-13T23:06:22.635Z
z.toString():アメリカ/ Los_Angeles
offset.toString():-08:00
ts.toString():2016年12月13日15:06:22.635
この出力から、我々はTimestamp
が実際にUTCで内部値にオフセット-08:00
の私自身の現在のデフォルトを適用していることがわかります。さらに悪いことに、このメソッドの出力ではオフセットの表示が省略され、実際にはそうでない場合はUTCとみなされます。さらにフラストレーション:this ‘feature’ is entirely undocumented!
このアンチフィーチャの動作が実際に動作していることを確認したので、質問のサンプルデータに戻ることができます。明らかに、得られたデータは2016-12-12 23:36:39.582
であり、上記のようにオフセットの兆候がないことは明らかです。しかし、今日の時刻である23:36:39.582
と、UTCとして期待されていたかもしれないもの、18:06:39.582
を見てください。予期しない値は、予想されるUTC値よりも5時間半、すなわち+05:30
です。 +05:30
のオフセットはAsia/Kolkata
のようなゾーン内でused in Indiaとスリランカになります。そこで、この質問の著者は、Asia/Colombo
またはAsia/Kolkata
のような現在のデフォルトタイムゾーンが+05:30
のJVM上に自分のコードを実行していると推測できます。
ソリューション
レガシーの日時クラスは使用しないでください。
代わりにjava.timeクラスを使用してください。 java.timeクラスはすべて、標準のISO 8601のテキスト形式を使用して予期しないボーナス動作を起こさずに簡単にtoString
メソッドを持っています。
JDBC 4.2準拠driverは、PreparedStatement::setObject
とResultSet::getObject
を呼び出すことによって、java.time型に直接的に対処することができます。
myPreparedStatement.setObject(… , instant) ;
...と...
Instant instant = myResultSet.getObject(…) ;
ない場合は、できるだけ簡単にjava.sqlのタイプを使用するようにフォールバックし、しかし。古いクラスに追加された新しい変換メソッドを使用します。
myPreparedStatement.setTimestamp(… , java.sql.Timestamp.from(instant)) ;
...と...
Instant instant = myResultSet.getTimestamp(…).toInstant() ;
java.timeについて
java.timeフレームワークは、Java 8に組み込まれており、後にされています。これらのクラスは、java.util.Date
、Calendar
、& SimpleDateFormat
など、面倒な古いlegacy日時クラスに取って代わります。
maintenance modeにあるJoda-Timeプロジェクトは、java.timeクラスへの移行を推奨しています。
Oracle Tutorialを参照して、詳細をご覧ください。そして、多くの例と説明のためにStack Overflowを検索してください。仕様はJSR 310です。
ここで、java.timeクラスを取得するには?
ThreeTen-Extraプロジェクトでは、追加のクラスでjava.timeを拡張します。このプロジェクトは、将来のjava.timeへの追加の可能性を証明する土台です。ここでは、Interval
、YearWeek
、YearQuarter
、moreなどの便利なクラスがあります。
「2016-12-12 23:36:39.582」は真夜中に近いです。>時間帯 –
データベースに保存されているタイムゾーンと、タイムゾーンアプリケーションコードが実行されている時間を教えてください。データベースに保存されているタイムゾーン情報は、正しい形式の日時変換を行うのに役立ちます。私はそれがアプリケーションタイムゾーンに変換されると仮定しています。 – Nagaraddi
データベースにタイムゾーンが保存されていないことは恐れています - 常にUTCです –