広告

Java : ZoneIdとZoneOffsetの違い

タイムゾーンを扱うクラスには ZoneId と ZoneOffset があります。
なぜ2つもあるのだろう…どちらかひとつだけでよいのでは? と疑問に思ったかたもいるかもしれません。

本記事では、そんな ZoneId と ZoneOffset の違いをざっくりと解説していきます。


クラス関係

クラス構成

クラス 概要
ZoneId 地理的な地域ごとのタイムゾーンを定義します。
例えば日本標準時は"Asia/Tokyo"として定義されています。時差(オフセット)は+9時間です。
ZoneOffset UTCからの単純な時差(オフセット)を定義します。

UTC(協定世界時)とは

  • 世界で基準となる時刻です。
    世界各地の標準時はUTCを基準としています。例えば日本標準時(JST)はUTCより9時間進めた時間です。

ZoneId

ZoneId は地域と時差のルールを定義します。

日本標準時では、UTC との時差は(季節によらずいつでも)+9時間です。これはご存じのかたも多いかもしれません。

final var zoneId = ZoneId.of("Asia/Tokyo");
System.out.println(zoneId); // Asia/Tokyo

final var zonedDateTime = ZonedDateTime.of(2020, 1, 1, 0, 0, 0, 0, zoneId);
System.out.println(zonedDateTime); // 2020-01-01T00:00+09:00[Asia/Tokyo]

日本ではあまりなじみがないかもしれませんが、夏時間・冬時間がある地域もあります。(サマータイムとも呼ばれています)
例えばヨーロッパのパリでは、

  • 夏時間は時差が+2時間
  • 冬時間は時差が+1時間

と、季節によって時差が変わります。

final var zoneId = ZoneId.of("Europe/Paris");
System.out.println(zoneId);

final var zonedDateTime = ZonedDateTime.of(2020, 10, 25, 3, 30, 0, 0, zoneId);
System.out.println(zonedDateTime); // 2020-10-25T03:30+01:00[Europe/Paris]

// 時間によって時差(オフセット)が変わります。
System.out.println(zonedDateTime.minusHours(1)); // 2020-10-25T02:30+01:00[Europe/Paris]
System.out.println(zonedDateTime.minusHours(2)); // 2020-10-25T02:30+02:00[Europe/Paris]
System.out.println(zonedDateTime.minusHours(3)); // 2020-10-25T01:30+02:00[Europe/Paris]
  • 03:30から-1時間すると、02:30(時差+01:00)
  • 03:30から-2時間すると、02:30(時差 +02:00 )
  • 03:30から-3時間すると、01:30(時差+02:00)

となります。
夏時間に慣れていないと、ちょっと奇妙に感じるかもしれません。

このように、ZoneId では各地域がどの季節にどれだけ時差が出るかというルールが定義されています。

ZoneOffset

ZoneOffset は、単純な UTC からの時差を定義します。
夏時間や冬時間といった概念はありません。

日本標準時の ZoneOffset は+09:00です。
以下は、あえて ZoneId ではなく ZoneOffset を使った例です。

final var zoneOffset = ZoneOffset.ofHours(9);
System.out.println(zoneOffset); // +09:00

final var offsetDateTime = OffsetDateTime.of(2020, 1, 1, 0, 0, 0, 0, zoneOffset);
System.out.println(offsetDateTime); // 2020-01-01T00:00+09:00

UTC

よく使う ZoneOffset として ZoneOffset.UTC があります。

System.out.println(ZoneOffset.UTC); // Z

final var offsetDateTime = OffsetDateTime.of(2020, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC);
System.out.println(offsetDateTime); // 2020-01-01T00:00Z

UTC(協定世界時) は ZoneOffset に定数として定義されています。
UTC は夏時間・冬時間といったルールはなく、固定で0時間の時差です。

よって、ZoneId ではなく ZoneOffset に定義されているわけですね。

TIPS

ZoneId.systemDefault()

システムのデフォルトのタイムゾーンを取得します。

final var zoneId = ZoneId.systemDefault();
System.out.println(zoneId); // Asia/Tokyo

一般的な日本語環境であれば、デフォルトとして"Asia/Tokyo"が取得されます。

実は ZoneOffset は ZoneId のサブクラスなので、ZoneOffset.systemDefault() とも書けます。
しかし、戻り値はあくまで ZoneId なので、ZoneId.systemDefault() と書く方が可読性も高くおすすめです。

final ZoneId zoneId1 = ZoneId.systemDefault(); // おすすめ
final ZoneId zoneId2 = ZoneOffset.systemDefault(); // 間違いではないけどあまりおすすめはしません

まとめ

クラス 時差の定義 夏時間・冬時間といった季節ごとの時差のルール
ZoneId
ZoneOffset ×

大きな違いは上の表のようになります。

基本的には ZoneId を使うことをおすすめします。
ややこしい夏時間・冬時間をちゃんと考慮してくれるためです。

ZoneOffset を使うのは UTC くらいなのかな、と思います。


関連記事

ページの先頭へ