1概要


https://en.wikipedia.org/wiki/Daylight


saving

time[Daylight Saving Time]、またはDSTは、夏時間の間に追加の1時間の自然光を利用するために時計を進める方法です(暖房、照明の電力を節約するため)。気分を高めるなど。

これはhttps://en.wikipedia.org/wiki/Daylight

saving

time

by

country[複数の国]で使用されており、日付とタイムスタンプを扱うときには考慮する必要があります。

このチュートリアルでは、場所に応じてJavaでDSTを正しく処理する方法を説明します。


2 JREとDSTの可変性

まず、世界的なDSTゾーンhttp://www.oracle.com/technetwork/java/javase/dst-faq-138158.html#change[頻繁に変更する]とそれを調整する中央機関がないことを理解することは非常に重要です。

国、場合によっては市でさえも、適用または取り消すかどうか、またその方法を決定できます。

それが起こるたびに、変更はhttp://www.iana.org/time-zones[IANAタイムゾーンデータベース]に記録され、アップデートは将来http://www.oracle.com/で公開されるでしょう。 technetwork/java/javase/tzdata-versions-138805.html[JREのリリース]。

  • 待つことが不可能な場合は、http://www.oracle.com/technetwork/java/javase/documentation/という公式のOracleツールを使用して、新しいDST設定を含む変更されたタイムゾーンデータをJRE ** に強制的に送信できます。 timezones-137583.html[Javaタイムゾーンアップデータツール]。http://www.oracle.com/technetwork/java/javase/downloads/index.html[Java SEダウンロードページ]から入手できます。

** 3間違った方法:3文字のタイムゾーンID

**

JDK 1.1日には、APIは3文字のタイムゾーンIDを許可していましたが、これはいくつかの問題を引き起こしました。

まず、これは、同じ3文字のIDが複数のタイムゾーンを参照する可能性があるためです。たとえば、

CST

は米国の「中央標準時」だけでなく、「中国の標準時」でも構いません。その場合、Javaプラットフォームはそのうちの1つしか認識できませんでした。

もう1つの問題は、標準タイムゾーンでは夏時間がアカウントに取り込まれないことです。複数の地域/地域/都市で同じ標準時ゾーン内にローカルDSTを設定できるため、標準時ではそれが守られていません。

下位互換性のため、



java.util.Timezone


を3文字でインスタンス化することも可能です。 IDただし、この方法は推奨されておらず、今後は使用しないでください。


4正しい方法:TZDBタイムゾーンID

JavaでDSTを処理する正しい方法は、特定のTZDBタイムゾーンIDを使って

Timezone

をインスタンス化することです。 __「ヨーロッパ/ローマ」。

次に、これを

java.util.Calendar

などの時間固有のクラスと組み合わせて使用​​して、(GMTタイムゾーンへの)__TimeZoneのrawオフセットの適切な設定、および自動DSTシフト調整を取得します。

正しい

TimeZoneを使用すると、

GMT 1

から

GMT 2__(2018年3月25日の午前2時にイタリアで発生)へのシフトが自動的にどのように処理されるかを見てみましょう。

TimeZone tz = TimeZone.getTimeZone("Europe/Rome");
TimeZone.setDefault(tz);
Calendar cal = Calendar.getInstance(tz, Locale.ITALIAN);
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.ITALIAN);
Date dateBeforeDST = df.parse("2018-03-25 01:55");
cal.setTime(dateBeforeDST);

assertThat(cal.get(Calendar.ZONE__OFFSET)).isEqualTo(3600000);
assertThat(cal.get(Calendar.DST__OFFSET)).isEqualTo(0);

ご覧のとおり、当時の

ZONE

OFFSET

は60分(イタリアは

GMT 1

であるため)ですが、

DST

OFFSET

は0です。


Calendar

に10分を追加しましょう。

cal.add(Calendar.MINUTE, 10);

これで、

DST

OFFSET

も60分になり、国は現地時間を

CET

(中央ヨーロッパ時間)から

CEST

(中央ヨーロッパ夏時間)、つまり

GMT 2__に移行しました。

Date dateAfterDST = cal.getTime();

assertThat(cal.get(Calendar.DST__OFFSET))
  .isEqualTo(3600000);
assertThat(dateAfterDST)
  .isEqualTo(df.parse("2018-03-25 03:05"));

コンソールに2つの日付を表示すると、タイムゾーンも変更されます。

Before DST (00:55 UTC - 01:55 GMT+1) = Sun Mar 25 01:55:00 CET 2018
After DST (01:05 UTC - 03:05 GMT+2) = Sun Mar 25 03:05:00 CEST 2018

最後のテストとして、2つの

__Date

__の1:55と3:05の間の距離を測定します。

Long deltaBetweenDatesInMillis = dateAfterDST.getTime() - dateBeforeDST.getTime();
Long tenMinutesInMillis = (1000L **  60 **  10);

assertThat(deltaBetweenDatesInMillis)
  .isEqualTo(tenMinutesInMillis);

予想どおり、距離は70分ではなく10分です。


TimeZone



Locale

を正しく使用することで、

Date

を扱うときに発生する可能性がある共通の落とし穴に陥らないようにする方法を説明しました。


5最善の方法:Java 8 Date/Time API

これらのスレッドセーフではない、常にユーザフレンドリではない

java.util

クラスを扱うのは、特に互換性の問題により、それらが適切にリファクタリングされないため、常に困難でした。

このため、Java 8は真新しいパッケージ

java.time

とまったく新しいAPIセット、リンク:/java-8-date-time-intro[日付/時刻API]を導入しました。これは完全にISO中心です。スレッドセーフで、有名なライブラリJoda-Timeに強く影響を受けています。


java.util.Date



java.time.LocalDateTime

の後継クラスから始めて、この新しいクラスを詳しく見てみましょう。

LocalDateTime localDateTimeBeforeDST = LocalDateTime
  .of(2018, 3, 25, 1, 55);

assertThat(localDateTimeBeforeDST.toString())
  .isEqualTo("2018-03-25T01:55");


LocalDateTime

が、標準で広く採用されている日時表記である

ISO8601

プロファイルにどのように準拠しているかを観察できます。

ただし、

Zones



Offsets

はまったく認識されていません。そのため、

DST対応の

java.time.ZonedDateTime


に変換する必要があります。

ZoneId italianZoneId = ZoneId.of("Europe/Rome");
ZonedDateTime zonedDateTimeBeforeDST = localDateTimeBeforeDST
  .atZone(italianZoneId);

assertThat(zonedDateTimeBeforeDST.toString())
  .isEqualTo("2018-03-25T01:55+01:00[Europe/Rome]");

ご覧のとおり、日付には2つの基本的な末尾の情報が組み込まれています。

前の例のように、10分足してDSTをトリガーしましょう。

ZonedDateTime zonedDateTimeAfterDST = zonedDateTimeBeforeDST
  .plus(10, ChronoUnit.MINUTES);

assertThat(zonedDateTimeAfterDST.toString())
  .isEqualTo("2018-03-25T03:05+02:00[Europe/Rome]");

繰り返しになりますが、時間とゾーンオフセットの両方がどのように進んでいて、同じ距離を保っているかがわかります。

Long deltaBetweenDatesInMinutes = ChronoUnit.MINUTES
  .between(zonedDateTimeBeforeDST,zonedDateTimeAfterDST);
assertThat(deltaBetweenDatesInMinutes)
  .isEqualTo(10);


6. 結論

サマータイムとは何か、またさまざまなバージョンのJavaコアAPIの実用的な例を通してそれを処理する方法を説明しました。

Java 8以上で作業するとき、使いやすさと標準のスレッドセーフな性質のおかげで、新しい

java.time

パッケージの使用をお勧めします。

いつものように、完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/java-dates[over Github]から入手できます。