概要

海外拠点との連携やクラウドサービスとの通信で、タイムゾーンの扱いは避けて通れません。Java 8 以降の ZonedDateTime と ZoneId を使えば、JST / UTC / EST などの時差変換を安全に行えます。ただし、サマータイムの切り替わりタイミングや、DB への保存形式の選び方を間違えると、1 時間のズレや日付の食い違いが本番で発生します。この記事では、タイムゾーン変換の基本操作から、サマータイムが絡むエッジケースの扱い、UTC で統一して保存する設計パターンまでを整理します。

使いどころ

海外拠点のシステムとデータ連携する際に UTC で統一して保存する

ユーザーのタイムゾーンに合わせて表示時刻を変換する

ログのタイムスタンプを複数のタイムゾーンで比較する

コード例

複数タイムゾーンの時刻を比較する
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class TimezoneCompare {

    public static void main(String[] args) {
        var now = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
        var zones = java.util.List.of(
            "Asia/Tokyo", "UTC", "America/New_York",
            "Europe/London", "Asia/Shanghai"
        );
        var fmt = DateTimeFormatter.ofPattern(
            "yyyy-MM-dd HH:mm:ss z");

        for (var zone : zones) {
            var converted = now.withZoneSameInstant(
                ZoneId.of(zone));
            System.out.printf("%-20s %s%n",
                zone, converted.format(fmt));
        }
    }
}

Java 8 / 17 / 21 の完全なサンプルコードは GitHub リポジトリ で確認できます。

Version Coverage

基本的な使い方は Java 8 と同じ。switch 式で出力フォーマットの切り替えが簡潔に書ける。

Java 17
// Java 17: switch 式で税率切り替えと同様の書き方
var now = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
// DB保存は UTC、表示は JST パターン
String dbValue = now.withZoneSameInstant(ZoneId.of("UTC"))
    .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
// 取得時に表示用へ変換
var fromDb = ZonedDateTime.parse(dbValue);
String display = fromDb
    .withZoneSameInstant(ZoneId.of("Asia/Tokyo"))
    .format(DateTimeFormatter
        .ofPattern("yyyy/MM/dd HH:mm"));

Library Comparison

Joda-TimeJava 7 以前の保守案件。Java 8 以降は標準 API で十分。
ThreeTen-Extra追加の時間量型や Interval が必要な場合。標準の ZonedDateTime で大半のケースは十分。

注意点

DB には UTC で保存し、表示時にユーザーのタイムゾーンに変換するのが安全。

サマータイムの切り替え時に時刻が重複・欠落する場合がある。

ZoneId.of() に不正な文字列を渡すと DateTimeException が発生する。

FAQ

タイムゾーンの一覧はどうやって取得しますか?

ZoneId.getAvailableZoneIds() で全タイムゾーンIDを取得できます。600以上のIDが返るため、実用上はリージョン形式(Asia/Tokyo等)に絞ると扱いやすくなります。

サマータイムの影響を避けるにはどうしますか?

内部的には UTC で処理し、表示時のみローカルタイムに変換するのが安全です。UTC基準なら時刻の重複や欠落が発生しないためです。

ZonedDateTime と OffsetDateTime の違いは?

ZonedDateTime はタイムゾーンルール(サマータイム等)を含み、OffsetDateTime は固定オフセットのみです。

関連書籍

この記事のテーマをさらに深く学びたい方へ。

※ Amazon アソシエイトリンクを含みます