web-dev-qa-db-ja.com

Java8でデフォルトのZoneOffsetを取得する方法は?

Java8では、ZoneId.default()を使用するとシステムのデフォルトZoneIdを取得できますが、デフォルトのZoneOffsetを取得するにはどうすればよいですか?

ZoneIdにはいくつかの「ルール」があり、各ルールにはZoneOffsetがあります。つまり、ZoneIdには複数のZoneOffsetがあります

37
FredSuvn

tl; dr

OffsetDateTime.now().getOffset()

ただし、UTCからの単なるオフセットではなく、タイムゾーンを使用する必要があります。

ZoneId.systemDefault() 

オフセットとタイムゾーン

offset-from-UTC は単なる時間、分、秒の数であり、それ以上ではありません。

タイムゾーン は、特定の地域の人々が使用するオフセットの過去、現在、および将来の変更の履歴です。タイムゾーンには、 サマータイム(DST) などの異常を処理する一連のルールがあり、特定の期間にオフセットがシフトします。

タイムゾーン=(オフセット履歴+異常の規則)

したがって、ゾーンを使用する方がよい既知の場合。

リージョンのオフセットは時間とともに変化します。たとえば、 米国のDST は、約半年間オフセットを1時間シフトし、その年の後半にその時間をオフセットに戻します。タイムゾーンの全体的な目的は、これらのシフトをオフセットで文書化することです。

したがって、実際には、日時なしでオフセットを要求しても意味がありませんAmerica/Los_Angeles では、たとえば今年の一部ではオフセットは-08:00ですが、年の別の部分ではDST中の-07:00です。

OffsetDateTime

OffsetDateTime として瞬間を指定して、 ZoneOffset を抽出しましょう。

OffsetDateTime odt = OffsetDateTime.now ();
ZoneOffset zoneOffset = odt.getOffset ();

odt.toString():2017-01-02T15:19:47.162-08:00

zoneOffset.toString():-08:00

そのnowメソッドは、実際にはJVMの現在のデフォルトタイムゾーンを暗黙的に適用しています。希望する/予想されるタイムゾーンを指定して、常に明示的にすることをお勧めします。現在のデフォルトゾーンが必要な場合でも、意図を明確にするために明示的に言ってください。プログラマーでよく発生するように、デフォルトを意図したのか、タイムゾーンを考慮しなかったのかについてのあいまいさを排除します。 ZoneId.systemDefault を呼び出します。

OffsetDateTime odt = OffsetDateTime.now ( ZoneId.systemDefault () );
ZoneOffset zoneOffset = odt.getOffset ();

ZoneId.systemDefault()。toString():America/Los_Angeles

odt:2017-01-02T15:19:47.162-08:00

zoneOffsetOfOdt:-08:00

デフォルトゾーンに依存する場合の注意:このデフォルトは、JVM内の任意のスレッドのコードによっていつでも変更できます。重要な場合は、ユーザーに目的のタイムゾーンを尋ねます。

合計秒数として、その時間をオフセットに求めることができます。

int offsetSeconds = zoneOffset.getTotalSeconds ();

offsetSeconds:-28800

ZonedDateTime

別の例:おそらく、ケベックでの今年のクリスマスにオフセットがどうなるか知りたいと思うでしょう。タイムゾーンAmerica/Montrealを指定し、 ZonedDateTime を取得し、そのオフセットをZoneOffsetオブジェクトとして要求します。

ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate ld = LocalDate.of( 2017 , 12 , 25 );
ZonedDateTime zdtXmas = ld.atStartOfDay( z );
ZoneOffset zoneOffsetXmas = zdtXmas.getOffset();

zdtXmas.toString():2017-12-25T00:00-05:00 [アメリカ/モントリオール]

zoneOffsetXmas.toString():-05:00

zoneOffsetXmas.getTotalSeconds():-18000

Table of date-time types in Java, both modern and legacy.

ZoneId

Yanysのコメントで示唆されているように、ZoneIdとして瞬間を渡すことにより、特定のZoneOffsetInstant を調べることができます。 Instant クラスは、 UTC のタイムライン上の瞬間を、 ナノ秒 (小数部の最大9桁)の解像度で表します。

これは、同じ目的地への単なる別のルートです。前述のOffsetDateTimeおよびZonedDateTimeと同様に、(a)タイムゾーンと(b)瞬間を指定しています。

Instant instant = zdtXmas.toInstant();
ZoneOffset zo = z.getRules().getOffset( instant );

ZoneId:America/Montreal at instant:2017-12-25T05:00:00Z ZoneOffsetは:-05:00

これらすべての例の IdeOne.comでのライブコード をご覧ください。

ZoneOffset.systemDefault –バグまたは機能?

ZoneOffsetのサブクラスであるZoneIdクラスは、 systemDefault メソッドを継承するものとして文書化されています。ただし、これは実際には機能しません。

ZoneOffset zoneOffset = ZoneOffset.systemDefault() ;  // Fails to compile.

エラー:互換性のないタイプ:ZoneIdはZoneOffsetに変換できません

このコンパイルの失敗がバグなのか機能なのかはわかりません。上で説明したように、日付と時刻のデフォルトオフセットを要求することは私には意味がないようです。したがって、おそらくZoneOffset.systemDefaultは実際に失敗するはずです。しかし、ドキュメントには説明が必要です。

この問題に対処するためにドキュメントの失敗に関するバグを報告しようとしましたが、あきらめて、そのようなバグレポートをどこでどのように提出するかを判断できませんでした。


Java.timeについて

Java.time フレームワークは、Java 8以降に組み込まれています。これらのクラスは、 Java.util.DateCalendar 、& SimpleDateFormat などの厄介な古い legacy date-timeクラスに取って代わります。

Joda-Time プロジェクトは、現在 メンテナンスモード にあり、 Java.time クラスへの移行を推奨しています。

詳細については、 Oracle Tutorial を参照してください。また、Stack Overflowで多くの例と説明を検索してください。指定は JSR 31 です。

Java.timeオブジェクトをデータベースと直接交換できます。 JDBC 4.2 以降に準拠する JDBCドライバー を使用します。文字列やJava.sql.*クラスは必要ありません。

Java.timeクラスはどこで入手できますか?

ThreeTen-Extra プロジェクトは、追加のクラスでJava.timeを拡張します。このプロジェクトは、Java.timeに将来追加される可能性のある証明の場です。 IntervalYearWeekYearQuarter 、および more などの便利なクラスがあります。

116
Basil Bourque