Java ZonedDateTime クラス

ZonedDateTime は Java 8 で導入された日時 API (java.time パッケージ) の重要なクラスで、タイムゾーン付きの日付と時刻を表します。このクラスは LocalDateTime と ZoneId を組み合わせ、特定のタイムゾーンにおける時点を正確に表すことができます。

主な特徴

  • 日付(年、月、日)を含む
  • 時刻(時、分、秒、ナノ秒)を含む
  • タイムゾーン情報を含む
  • 不変でスレッドセーフなクラスです
  • タイムゾーン変換と夏時間の自動調整をサポートします

ZonedDateTime の作成方法

1. 現在時刻を使用して作成

例

// 現在のシステム既定タイムゾーンの日時を取得
ZonedDateTime now = ZonedDateTime.now();

// 指定したタイムゾーンの現在日時を取得
ZonedDateTime nowInTokyo = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));

2. 構成要素から作成

例

// 年、月、日、時、分、秒、タイムゾーンを指定
ZonedDateTime customDateTime = ZonedDateTime.of(
    2023, 12, 25, 15, 30, 0, 0,
    ZoneId.of("America/New_York")
);

3. LocalDateTime と ZoneId の組み合わせから作成

例

LocalDateTime localDateTime = LocalDateTime.of(2023, 6, 15, 10, 30);
ZoneId zoneId = ZoneId.of("Europe/Paris");
ZonedDateTime parisTime = ZonedDateTime.of(localDateTime, zoneId);

よく使う操作メソッド

1. 時刻情報の取得

例

ZonedDateTime zdt = ZonedDateTime.now();

int year = zdt.getYear();          // 年
Month month = zdt.getMonth();      // 月
int day = zdt.getDayOfMonth();     // 日
int hour = zdt.getHour();          // 時
int minute = zdt.getMinute();      // 分
int second = zdt.getSecond();      // 秒
ZoneId zone = zdt.getZone();       // タイムゾーン

2. 時刻の加算・減算操作

例

ZonedDateTime zdt = ZonedDateTime.now();

// 1日加算
ZonedDateTime tomorrow = zdt.plusDays(1);

// 2時間減算
ZonedDateTime twoHoursEarlier = zdt.minusHours(2);

// 3週間加算
ZonedDateTime threeWeeksLater = zdt.plusWeeks(3);

3. タイムゾーン変換

例

ZonedDateTime tokyoTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));

// ニューヨーク時刻に変換
ZonedDateTime newYorkTime = tokyoTime.withZoneSameInstant(ZoneId.of("America/New_York"));

// UTC時刻に変換
ZonedDateTime utcTime = tokyoTime.withZoneSameInstant(ZoneOffset.UTC);

実践的な使用例

1. 2つのタイムゾーンの時差を計算

例

ZonedDateTime londonTime = ZonedDateTime.now(ZoneId.of("Europe/London"));
ZonedDateTime sydneyTime = ZonedDateTime.now(ZoneId.of("Australia/Sydney"));

// 時差(時間)を計算
long hoursBetween = ChronoUnit.HOURS.between(londonTime, sydneyTime);
System.out.println("ロンドンとシドニーの現在の時差: " + hoursBetween + "時間");

2. タイムゾーンをまたぐ会議時刻の処理

例

// ニューヨークの会議時刻は午後3時
ZonedDateTime meetingTimeNY = ZonedDateTime.of(
    LocalDate.now(),
    LocalTime.of(15, 0),
    ZoneId.of("America/New_York")
);

// 東京時刻に変換
ZonedDateTime meetingTimeTokyo = meetingTimeNY.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
System.out.println("東京の参加者は現地時刻: " + meetingTimeTokyo);

3. 夏時間の処理

例

// ニューヨークの夏時間切替前後の時刻
ZonedDateTime beforeDST = ZonedDateTime.of(
    LocalDateTime.of(2023, 3, 11, 1, 30),
    ZoneId.of("America/New_York")
);

ZonedDateTime afterDST = beforeDST.plusHours(1);
System.out.println("実際の時差: " +
    Duration.between(beforeDST, afterDST).toHours() + "時間");

ZonedDateTime と他の日時クラスとの変換

1. Instant への変換

例

ZonedDateTime zdt = ZonedDateTime.now();
Instant instant = zdt.toInstant();  // UTCタイムスタンプに変換

2. LocalDateTime への変換

例

ZonedDateTime zdt = ZonedDateTime.now();
LocalDateTime ldt = zdt.toLocalDateTime();  // タイムゾーン情報が失われる

3. Instant からの作成

例

Instant instant = Instant.now();
ZonedDateTime zdt = instant.atZone(ZoneId.of("Asia/Shanghai"));

総合例

例

import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

public class ZonedDateTimeDemo {
    public static void main(String[] args) {
        // 1. 現在のタイムゾーンの現在時刻を取得
        ZonedDateTime now = ZonedDateTime.now();
        System.out.println("現在のタイムゾーンの時刻: " + now);
       
        // 2. 指定したタイムゾーンの現在時刻を取得
        ZonedDateTime tokyoTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
        System.out.println("東京時刻: " + tokyoTime);
       
        // 3. 特定のタイムゾーン付き時刻を作成
        ZonedDateTime specificTime = ZonedDateTime.of(
            2023, 5, 15, 10, 30, 0, 0,
            ZoneId.of("America/New_York")
        );
        System.out.println("ニューヨークの特定時刻: " + specificTime);
       
        // 4. タイムゾーン変換
        ZonedDateTime londonTime = specificTime.withZoneSameInstant(ZoneId.of("Europe/London"));
        System.out.println("対応するロンドン時刻: " + londonTime);
       
        // 5. フォーマットして出力
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z");
        System.out.println("フォーマットされた時刻: " + now.format(formatter));
       
        // 6. 各要素の情報を取得
        System.out.println("タイムゾーン: " + now.getZone());
        System.out.println("年: " + now.getYear());
        System.out.println("月: " + now.getMonth());
        System.out.println("時: " + now.getHour());
    }
}

出力結果は次のようになります:

当前时区时间: 2025-05-01T11:29:07.411467+08:00[Asia/Shanghai]
东京时间: 2025-05-01T12:29:07.417938+09:00[Asia/Tokyo]
纽约特定时间: 2023-05-15T10:30-04:00[America/New_York]
对应的伦敦时间: 2023-05-15T15:30+01:00[Europe/London]
格式化时间: 2025-05-01 11:29:07 CST
时区: Asia/Shanghai
年份: 2025
月份: MAY
小时: 11

ベストプラクティス

  1. 保存と転送:データベース保存やネットワーク転送時は、Instant または UTC 時刻の ZonedDateTime を使用することを推奨します
  2. 表示:ユーザーインターフェースに表示するときだけローカルタイムゾーンに変換します
  3. 比較:異なるタイムゾーンの時刻を比較するときは、同じタイムゾーンまたは Instant に変換してから行います
  4. 夏時間:単純なオフセット(例:"-05:00")ではなく、常に完全なタイムゾーンID(例:"America/New_York")を使用します

ZonedDateTime はタイムゾーンに敏感なアプリケーションを扱うための強力なツールであり、正しく使用することで多くの一般的な日時問題を回避できます。

静的ファクトリメソッド

メソッド 説明 例
static ZonedDateTime now() 現在のタイムゾーンの現在日時を取得 ZonedDateTime.now()
static ZonedDateTime now(ZoneId zone) 指定したタイムゾーンの現在日時を取得 ZonedDateTime.now(ZoneId.of("Asia/Shanghai"))
static ZonedDateTime of(int year, int month, int day, int hour, int minute, int second, int nano, ZoneId zone) パラメータを指定して作成 ZonedDateTime.of(2023, 6, 15, 14, 30, 0, 0, ZoneId.of("GMT+8"))
static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone) LocalDate、LocalTime、タイムゾーンを組み合わせて作成 ZonedDateTime.of(LocalDate.now(), LocalTime.now(), ZoneId.systemDefault())
static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone) LocalDateTime とタイムゾーンから作成 ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("America/New_York"))
static ZonedDateTime ofInstant(Instant instant, ZoneId zone) Instant とタイムゾーンから作成 ZonedDateTime.ofInstant(Instant.now(), ZoneId.of("UTC"))
static ZonedDateTime parse(CharSequence text) 文字列から解析 ZonedDateTime.parse("2023-06-15T14:30:45+08:00[Asia/Shanghai]")
static ZonedDateTime parse(CharSequence text, DateTimeFormatter formatter) 指定したフォーマットで解析 ZonedDateTime.parse("2023-06-15 14:30 CST", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm z"))

日時情報の取得

メソッド 説明 例
int getYear() 年を取得 2023
Month getMonth() 月(Month 列挙型)を取得 Month.JUNE
int getMonthValue() 月の値(1-12)を取得 6
int getDayOfMonth() 月内の日数を取得 15
int getDayOfYear() 年内の日数を取得 166
DayOfWeek getDayOfWeek() 曜日(DayOfWeek 列挙型)を取得 DayOfWeek.THURSDAY
int getHour() 時(0-23)を取得 14
int getMinute() 分(0-59)を取得 30
int getSecond() 秒(0-59)を取得 45
int getNano() ナノ秒を取得 0
ZoneId getZone() タイムゾーンを取得 Asia/Shanghai
ZoneOffset getOffset() タイムゾーンオフセットを取得 +08:00

日時操作

メソッド 説明 例
ZonedDateTime plusDays(long days) 日数を加算 zdt.plusDays(5)
ZonedDateTime plusHours(long hours) 時間を加算 zdt.plusHours(2)
ZonedDateTime plusMinutes(long minutes) 分を加算 zdt.plusMinutes(30)
ZonedDateTime plusSeconds(long seconds) 秒を加算 zdt.plusSeconds(45)
ZonedDateTime plusNanos(long nanos) ナノ秒を加算 zdt.plusNanos(1000000)
ZonedDateTime minusDays(long days) 日数を減算 zdt.minusDays(5)
ZonedDateTime minusHours(long hours) 時間を減算 zdt.minusHours(2)
ZonedDateTime minusMinutes(long minutes) 分を減算 zdt.minusMinutes(30)
ZonedDateTime minusSeconds(long seconds) 秒を減算 zdt.minusSeconds(45)
ZonedDateTime minusNanos(long nanos) ナノ秒を減算 zdt.minusNanos(1000000)
ZonedDateTime withYear(int year) 年を変更 zdt.withYear(2024)
ZonedDateTime withMonth(int month) 月を変更 zdt.withMonth(12)
ZonedDateTime withDayOfMonth(int day) 月内の日数を変更 zdt.withDayOfMonth(1)
ZonedDateTime withHour(int hour) 時を変更 zdt.withHour(0)
ZonedDateTime withMinute(int minute) 分を変更 zdt.withMinute(0)
ZonedDateTime withSecond(int second) 秒を変更 zdt.withSecond(0)
ZonedDateTime withNano(int nano) ナノ秒を変更 zdt.withNano(0)
ZonedDateTime withZoneSameInstant(ZoneId zone) タイムゾーンを変換(同じ瞬間を保持) zdt.withZoneSameInstant(ZoneId.of("UTC"))
ZonedDateTime withZoneSameLocal(ZoneId zone) タイムゾーンを変換(ローカル時刻を保持) zdt.withZoneSameLocal(ZoneId.of("UTC"))

変換メソッド

メソッド 説明 例
LocalDate toLocalDate() LocalDate に変換 zdt.toLocalDate()
LocalTime toLocalTime() LocalTime に変換 zdt.toLocalTime()
LocalDateTime toLocalDateTime() LocalDateTime に変換 zdt.toLocalDateTime()
OffsetDateTime toOffsetDateTime() OffsetDateTime に変換 zdt.toOffsetDateTime()
Instant toInstant() Instant に変換 zdt.toInstant()

比較メソッド

メソッド 説明 例
boolean isAfter(ChronoZonedDateTime<?> other) 指定された日時の後かどうか zdt1.isAfter(zdt2)
boolean isBefore(ChronoZonedDateTime<?> other) 指定された日時の前かどうか zdt1.isBefore(zdt2)
boolean isEqual(ChronoZonedDateTime<?> other) 指定された日時と等しいかどうか zdt1.isEqual(zdt2)
int compareTo(ChronoZonedDateTime<?> other) 2つの日時を比較する zdt1.compareTo(zdt2)

フォーマットと文字列変換

メソッド 説明 例
String format(DateTimeFormatter formatter) 文字列にフォーマットする zdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME)
String toString() ISO形式の文字列に変換する "2023-06-15T14:30:45+08:00[Asia/Shanghai]"
その他の拡張