Java Tips | 日付・時間:ISO変換

Java Java
スポンサーリンク

「ISO変換」とは何をするものか

「API は ISO 形式で日時を返してくる」「ログを ISO 形式で出したい」「他言語ともやり取りしたい」
そんなときに出てくるキーワードが ISO-8601 です。

ISO-8601 は、日時を
2025-03-26T10:05:30
2025-03-26T10:05:30+09:00
2025-03-26T01:05:30Z
のように、世界中で共通に解釈できる形で表現するルールです。

Java の日付・時間APIは、この ISO-8601 を“ど真ん中”に据えて設計されています。
だから「ISO変換」は、Java にとって一番得意な領域だと思って大丈夫です。


Java の ISO フォーマッタの基本

ISO_LOCAL_DATE / ISO_LOCAL_DATE_TIME / ISO_OFFSET_DATE_TIME

DateTimeFormatter には、ISO-8601 用の定義済みフォーマッタがいくつも用意されています。

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

public class IsoFormatterBasic {

    public static void main(String[] args) {
        LocalDate date = LocalDate.of(2025, 3, 26);
        LocalDateTime dateTime = LocalDateTime.of(2025, 3, 26, 10, 5, 30);
        OffsetDateTime offsetDateTime =
                OffsetDateTime.of(2025, 3, 26, 10, 5, 30, 0, ZoneOffset.ofHours(9));

        String d  = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
        String dt = dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
        String odt = offsetDateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);

        System.out.println("ISO_LOCAL_DATE       : " + d);   // 2025-03-26
        System.out.println("ISO_LOCAL_DATE_TIME  : " + dt);  // 2025-03-26T10:05:30
        System.out.println("ISO_OFFSET_DATE_TIME : " + odt); // 2025-03-26T10:05:30+09:00
    }
}
Java

ここで押さえておきたいのは、
「タイムゾーンやオフセットを含めたいかどうか」で使う型とフォーマッタが変わる、ということです。

日付だけなら LocalDateISO_LOCAL_DATE
タイムゾーンなしの日時なら LocalDateTimeISO_LOCAL_DATE_TIME
オフセット付き(+09:00 や Z)なら OffsetDateTimeISO_OFFSET_DATE_TIME


Instant と ISO 形式(Z付き)との変換

Instant → ISO(UTC表現)

Instant は「UTC 上の瞬間」です。
これを ISO 文字列にするときは、toString() でも ISO-8601 形式になります。

import java.time.Instant;

public class InstantIso {

    public static void main(String[] args) {
        Instant instant = Instant.parse("2025-03-26T01:05:30Z");

        String iso = instant.toString();

        System.out.println("Instant      : " + instant); // 2025-03-26T01:05:30Z
        System.out.println("ISO文字列    : " + iso);     // 2025-03-26T01:05:30Z
    }
}
Java

Z は「UTC(ゼロオフセット)」を意味します。
ログや外部連携で「UTC で統一したい」ときは、この形をそのまま使うのが一番素直です。

ISO(Z付き文字列)→ Instant

逆に、ISO 文字列から Instant に変換するときは Instant.parse を使います。

import java.time.Instant;

public class InstantParseIso {

    public static void main(String[] args) {
        String text = "2025-03-26T01:05:30Z";

        Instant instant = Instant.parse(text);

        System.out.println("元文字列: " + text);
        System.out.println("Instant: " + instant);
    }
}
Java

ここでのポイントは、
「UTC の ISO 文字列は、Instant とほぼ 1 対 1 で対応している」
という感覚です。


JST(Asia/Tokyo)と ISO オフセット形式の変換

JST の日時 → ISO_OFFSET_DATE_TIME

日本時間(JST)を ISO 形式(+09:00 付き)で出したいケースです。

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

public class JstToIsoOffset {

    public static void main(String[] args) {
        ZoneId jst = ZoneId.of("Asia/Tokyo");

        ZonedDateTime jstTime =
                ZonedDateTime.of(2025, 3, 26, 10, 5, 30, 0, jst);

        String iso = jstTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);

        System.out.println("JST ZonedDateTime: " + jstTime);
        System.out.println("ISOオフセット形式: " + iso); // 2025-03-26T10:05:30+09:00
    }
}
Java

ここで深掘りしたいのは、
「タイムゾーン付きの日時は、ISO 形式にすると“オフセット付き文字列”になる」
ということです。

+09:00 が付いていることで、「これは日本時間だ」と他システムにも明確に伝えられます。

ISO_OFFSET_DATE_TIME → ZonedDateTime

ISO 文字列から ZonedDateTime に戻すこともできます。

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

public class IsoOffsetToZoned {

    public static void main(String[] args) {
        String text = "2025-03-26T10:05:30+09:00";

        ZonedDateTime zdt =
                ZonedDateTime.parse(text, DateTimeFormatter.ISO_OFFSET_DATE_TIME);

        System.out.println("元文字列      : " + text);
        System.out.println("ZonedDateTime : " + zdt);
    }
}
Java

ISO 形式を使うメリットは、
「文字列だけ見ても、タイムゾーン情報まで含めて正しく復元できる」
という点にあります。


ISO 形式と LocalDateTime の注意点

タイムゾーンなしの ISO と “瞬間”のギャップ

ISO_LOCAL_DATE_TIME は、タイムゾーン情報を含みません。

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class LocalIso {

    public static void main(String[] args) {
        LocalDateTime dt = LocalDateTime.of(2025, 3, 26, 10, 5, 30);

        String text = dt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);

        LocalDateTime parsed =
                LocalDateTime.parse(text, DateTimeFormatter.ISO_LOCAL_DATE_TIME);

        System.out.println("元 LocalDateTime: " + dt);
        System.out.println("ISO文字列       : " + text);
        System.out.println("パース結果      : " + parsed);
    }
}
Java

これは「カレンダー上の日時」を表すには十分ですが、
「世界のどの瞬間か」は決まりません。

“瞬間”として扱いたい場合は、
ZonedDateTimeOffsetDateTime と組み合わせて、
ISO_OFFSET_DATE_TIME などを使う方が安全です。


ISO変換ユーティリティとしてまとめる

「ISOで出す・ISOから読む」を一か所に集約する

ISO 形式との変換も、あちこちでバラバラに書くのではなく、
ユーティリティクラスにまとめておくと実務でかなり楽になります。

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

public class IsoUtils {

    // UTC Instant ⇔ ISO文字列(Z付き)
    public static String instantToIso(Instant instant) {
        return instant.toString(); // ISO-8601
    }

    public static Instant isoToInstant(String isoText) {
        return Instant.parse(isoText);
    }

    // JST LocalDateTime ⇔ ISOオフセット文字列(+09:00)
    private static final ZoneId JST = ZoneId.of("Asia/Tokyo");

    public static String jstLocalToIsoOffset(LocalDateTime localJst) {
        OffsetDateTime odt = localJst.atZone(JST).toOffsetDateTime();
        return odt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
    }

    public static LocalDateTime isoOffsetToJstLocal(String isoText) {
        OffsetDateTime odt =
                OffsetDateTime.parse(isoText, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
        return odt.atZoneSameInstant(JST).toLocalDateTime();
    }
}
Java

こうしておけば、呼び出し側は

String iso = IsoUtils.instantToIso(Instant.now());
Java

のように、「ISO で出す」という意図をコードで明示できます。


セキュリティ・外部連携から見た ISO変換

異なるシステム・言語間で“誤解されない時間”を渡す

ISO-8601 は、Java だけでなく、ほとんどの言語・プラットフォームがサポートしています。
だから、外部APIやマイクロサービス間の連携では、
「日時は ISO-8601 でやり取りする」がほぼデファクトスタンダードです。

特に、2025-03-26T01:05:30Z2025-03-26T10:05:30+09:00 のように、
オフセット付きの ISO 形式を使うと、

どのタイムゾーンの時間かが明確
サマータイムの有無に関わらず、正しい“瞬間”に復元できる

というメリットがあります。

セキュリティインシデント調査や監査でも、
「ログは ISO-8601(オフセット付き)で統一」「内部は Instant(UTC)」
という設計にしておくと、後からの解析が圧倒的にやりやすくなります。


まとめ:ISO変換で絶対に覚えてほしいこと

ISO変換は、「Java の日時オブジェクト」と「ISO-8601 文字列」を行き来することです。

Instant は toString() / Instant.parse でそのまま ISO(Z付き)と相互変換できる。
LocalDate / LocalDateTimeISO_LOCAL_DATE / ISO_LOCAL_DATE_TIME でタイムゾーンなしの ISO と変換できる。
タイムゾーン・オフセットを含めたいときは、OffsetDateTimeZonedDateTimeISO_OFFSET_DATE_TIME を使う。
外部連携・ログ・監査では、オフセット付き ISO 形式で統一すると、誤解されない“時間の証拠”になる。

もしあなたのコードのどこかに、
独自フォーマットで日時を文字列化している箇所があれば、
「そこ、本当に ISO-8601 にできないか?」と一度立ち止まって眺めてみてください。

それを ISO に寄せていくことが、
“時間にもセキュリティにも強いエンジニア”への、かなり実務的な一歩になります。

タイトルとURLをコピーしました