web-dev-qa-db-ja.com

(Oracle)Java JVMはうるう秒が発生していることをどのようにして知るのですか?

A うるう秒が発生します 2015年6月30日。オペレーティングシステムが異なれば、この状況の扱いも異なります。私の特定のケースでは、時間に大きく依存するカスタムJava(JDK 1.7)ソフトウェアを使用してRed Hat 6.4システムを実行しています。一部の 最近のRed Hatリリース情報)によると 見つかりました。システムのNTPデーモンは、23:59:59を2回繰り返すことにより、OSがうるう秒を自動的に処理するようにします。

私の質問は、JDK 1.7プロセスを長時間実行している場合、うるう秒が発生していることをどのようにして知るのですか?つまり、Javaは最終的に [〜#〜] iers [〜#〜] 人々がうるう秒を挿入することを決定したことをどのように知るのですか?- Date ドキュメントはうるう秒を認識しているように見えますが、役に立たないように見えます。適切なDateオブジェクトが作成されるか、Calendar.getInstance()が呼び出されると、JDKを想定できますか?これは、適切な「実際の」時間値を取得するための、基盤となるOSの日時処理へのパススルーですか?(私の場合、2番目の23:59:59を繰り返すように聞こえます。これは、OSがそれを処理する方法だからです。 )。

38
Ogre Psalm33

Jdkのバージョンによって異なります。たとえば、更新80を実行している場合は、 リリースノート を確認できます。

JDK 7u80には、IANAタイムゾーンデータバージョン2015aが含まれています。詳細については、JREソフトウェアのタイムゾーンデータバージョンを参照してください。

次に timezone data versions へのリンクをたどり、2015aを見つけます。次に TZアップデータバージョン1.4.11へのリンク に従います。

新しいうるう秒2015-06-30 23:59:60 UTC(IERS Bulletin C 49による)(Tim Parentiに感謝)

以前は含まれていないようですので、古いバージョンのJDK 7を実行している場合は、おそらく調整できません。内部でどのように機能するかについての詳細は、 ここ を参照してください。

正直なところ、実際にどのように機能するかを確認するためにテストしたことがありません。

13
assylias

答えassylias が正しいです。この回答は、その回答へのコメントによって引き起こされるいくつかの考えを追加します。コメントは、うるう秒が予定されている真夜中の経過時間の計算に言及しています。

この回答は、実際の使用では、うるう秒の問題は議論の余地があり、日時フレームワークでは無視されることを指摘して、元の質問にも対処します。

うるう秒は無視されます

すべての一般的なJava日時フレームワークは、うるう秒を無視します。私が理解しているとおりです。これらには以下が含まれます:

  • Java.time
  • ジョーダ時間
  • Java.util.Date/.Calendar(現在はJava.timeとJoda-Timeに時代遅れ)

ドク

以下は、うるう秒を効果的に無視することを示す、各フレームワークのドキュメントからの抜粋です。太字で強調されているのは私のものです。

Instant クラスのJava.timeドキュメント:

…上記の正確なタイムキーピングの複雑さを考えると、このJava APIは独自のタイムスケールを定義しますJavaタイムスケール。

Java Time-Scaleは、各暦日を秒と呼ばれる正確に86400のサブディビジョンに分割します。これらの秒はSI秒とは異なる場合があります。これは、事実上の国際的な市民時間スケール、時々変化します。

Javaタイムスケールは、タイムラインの異なるセグメントに対してわずかに異なる定義を持っています。それぞれの定義は、常用時の基準として使用されるコンセンサス国際タイムスケールに基づいています。国際的に合意された場合はいつでも時間スケールが変更または置換された場合、Java時間スケールの新しいセグメントを定義する必要があります。各セグメントは次の要件を満たす必要があります。

  • Javaタイムスケールは、基礎となる国際市民タイムスケールと厳密に一致するものとします。
  • Javaタイムスケールは、毎日正午の国際市民タイムスケールと正確に一致するものとします。
  • Javaタイムスケールは、国際市民タイムスケールと正確に定義された関係を持っているものとします。

現在、2013年現在、Javaタイムスケールには2つのセグメントがあります。

1972-11-03のセグメント(以下で説明する正確な境界)については、さらに通知があるまで、コンセンサス国際時間スケールはUTC(うるう秒あり)です。このセグメントでは、Java Time-ScaleはUTC-SLSと同じです。うるう秒のない日のUTCと同じです。うるう秒のある日のうるう秒は、1日の最後の1000秒に均等に広がり、1日あたり正確に86400秒の外観を維持します

1972-11-03より前のセグメントの場合、任意にさかのぼって、コンセンサス国際時間スケールはUT1として定義され、前向きに適用されます。これは、本初子午線(グリニッジ)の(平均)太陽時間に相当します。このセグメントでは、Java Time-Scaleはコンセンサス国際時間スケールと同じです。2つのセグメント間の正確な境界は、1971-11-03T00:00とUT1 = UTCの間の瞬間です。 1972-11-04T12:00。

JSR-310 APIを使用したJavaタイムスケールの実装は、1秒未満の精度のクロック、または単調またはスムーズに進行するクロックを提供する必要はありません。したがって、実際に実装する必要はありません。 UTC-SLSスルーを実行するか、うるう秒に注意する必要があります。ただし、JSR-310では、現在の瞬間を表すクロックを定義するときに使用するアプローチを文書化する必要があります。使用可能なクロックの詳細については、「クロック」を参照してください。

Javaタイムスケールは、すべての日時クラスに使用されます。これには、Instant、LocalDate、LocalTime、OffsetDateTime、ZonedDateTime、Durationが含まれます。

ジョーダ時間FAQ

Joda-Timeうるう秒をサポートしていません。うるう秒は、新しい特別な年表を作成するか、既存のZonedChronologyクラスにいくつかの拡張を行うことでサポートできます。どちらの場合でも、Joda-Timeの将来のバージョンでは、うるう秒はデフォルトで有効になりません。ほとんどのアプリケーションはそれを必要とせず、追加のパフォーマンスコストがかかる可能性があります。

Java.util.Dateクラスドキュメント

秒は0〜61の整数で表されます。値60と61はうるう秒でのみ発生し、さらにJava実際にうるう秒を正しく追跡する実装でのみ)が発生します。

私の知る限り、OpenJDKおよびOracle提供の実装では、うるう秒は追跡されません。見つかった場合は、そのようなドキュメントを投稿してください。

経過時間を計算する際のうるう秒なし

したがって、これらのフレームワークは経過時間を計算するときに余分なうるう秒を報告しません。

うるう秒 がスケジュールされている2015年6月30日から7月1日までの午前0時の前の分から後の分までの経過時間を計算するコードの例を次に示します。このコードは、Java version "1.8.0_45"でJoda-Time 2.8.1およびJava-timeをテストします。 Java.util.Date/.Calendarは、可能な限りこれらのクラスを避けるため、無視しました。必要に応じて、この場合のコードをここに追加してください。

最初 Joda-Time

// Joda-Time 2.8.1
DateTime startJoda = new DateTime( 2015, 06, 30, 23, 59, 00, DateTimeZone.UTC );
DateTime stopJoda = new DateTime( 2015, 07, 01, 00, 01, 00, DateTimeZone.UTC );
long elapsedMillisJoda = ( stopJoda.getMillis( ) - startJoda.getMillis( ) );

System.out.println( "startJoda: " + startJoda + " stopJoda: " + stopJoda + " = elapsedMillisJoda: " + elapsedMillisJoda );

…および Java.time

// Java.time
ZonedDateTime startZdt = ZonedDateTime.of( 2015, 06, 30, 23, 59, 00, 00, ZoneOffset.UTC );
ZonedDateTime stopZdt = ZonedDateTime.of( 2015, 07, 01, 00, 01, 00, 00, ZoneOffset.UTC );
long elapsedMillisZdt = startZdt.until( stopZdt, ChronoUnit.MILLIS );

System.out.println( "startZdt: " + startZdt + " stopZdt: " + stopZdt + " = elapsedMillisZdt: " + elapsedMillisZdt );

実行すると、ちょうど2分、120秒、または120,000ミリ秒の偶数の結果が表示されます。

startJoda: 2015-06-30T23:59:00.000Z stopJoda: 2015-07-01T00:01:00.000Z = elapsedMillisJoda: 120000
startZdt: 2015-06-30T23:59Z stopZdt: 2015-07-01T00:01Z = elapsedMillisZdt: 120000

Java.timeについて

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

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

詳細については、 Oracleチュートリアル を参照してください。スタックオーバーフローで多くの例と説明を検索してください。仕様は JSR 310 です。

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

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

  • Java SE 8Java SE 9 以降
    • 内蔵。
    • 標準の一部Java実装がバンドルされたAPI。
    • Java 9では、いくつかのマイナーな機能と修正が追加されています。
  • Java SE 6 および Java SE 7
  • Android
    • 以降のバージョンのAndroidには、Java.timeクラスの実装がバンドルされています。
    • 以前のAndroidでは、 ThreeTenABP プロジェクトが適応しますThreeTen-Backport (上記の通り)。 ThreeTenABPの使用方法… を参照してください。

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

30
Basil Bourque

これらは、Oracle Java JDK 1.7.0_55-b13(Ie:古いJDK)で、RHEL 6.3でリアルタイムシステムを実行している私の実際の観測です。デバッグコードを追加しました。 2015年6月30日23:59 UTCのうるう秒の1分前に毎分0.5秒ごとに新しいDateTime()を記録し、うるう秒の終了後にキックオフしました。ログは次のとおりです(奇妙なことに、ダブル表示される数値は J2000エポック )からの秒数です。

2015-06-30 23:59:59.316 18349217 [main] INFO  - Leaper's time is 488980799.316000 (Tue Jun 30 23:59:59 GMT-00:00 2015)
2015-06-30 23:59:59.817 18349718 [main] INFO  - Leaper's time is 488980799.816000 (Tue Jun 30 23:59:59 GMT-00:00 2015)
2015-07-01 00:00:00.317 18350218 [main] INFO  - Leaper's time is 488980800.317000 (Wed Jul 01 00:00:00 GMT-00:00 2015)
2015-07-01 00:00:00.817 18350718 [main] INFO  - Leaper's time is 488980800.817000 (Wed Jul 01 00:00:00 GMT-00:00 2015)
2015-07-01 00:00:01.318 18351219 [main] INFO  - Leaper's time is 488980801.318000 (Wed Jul 01 00:00:01 GMT-00:00 2015)

残念ながら、23:59:60に標準のうるう秒が挿入されなかったことを除いて、それは私にはあまりわかりません(assyliasとBasil Bourqueの回答の両方が起こると示されているため)。私の希望は、 'new Date()'が根本的なOS(うるう秒を適切に考慮していると思われるRHEL 6.3)に到達して現在時刻を尋ねることでした。それはそうではなかったようです。

JDKバージョンとRHELバージョンのその他の組み合わせを実行して効果をテストするためのリソースがありませんでした。私の現在の最良の推測は、1日の最後の1000秒間にうるう秒を拡散することについて見つけたバジルブルクのドキュメントがJDK 1.8以降に適用されることです(これは Instant ドキュメントの一部であるため、 Java 8機能)。私の特定のケースでは、私の古いJDK 1.7.0_55には2015年のうるう秒調整がなかったため、assyliasの観察が当てはまると思います。現在、うるう秒に気付かずに1秒進んでいます。

ここで学んだ教訓は?今後のうるう秒を考慮に入れたい場合は、リアルタイムシステムに最新の更新プログラムが完全に適用されていることを確認してください。観察とログ分析を行う必要がありますが、特定のシステムはリアルタイムより1秒早く実行されている可能性が高く、サービスを再起動してフォールバックする必要があります。

5
Ogre Psalm33