概要

帳票の日付欄、ログのタイムスタンプ、CSV の日付カラムなど、日付を特定の文字列形式に変換する処理は業務コードの至るところにあります。Java 8 以降は DateTimeFormatter がスレッドセーフなフォーマッタとして使えるため、従来の SimpleDateFormat で起きていたマルチスレッドの事故を回避できます。この記事では、DateTimeFormatter によるフォーマットの基本から、日本語ロケールでの曜日表示、ISO 8601 形式の出力、そして SimpleDateFormat からの移行指針までを整理します。

使いどころ

帳票の日付欄を「2025年03月27日(木)」のような日本語形式で出力する

ログファイルのタイムスタンプを「yyyy-MM-dd HH:mm:ss」で統一する

CSV 出力時の日付カラムを「yyyy/MM/dd」形式に揃える

コード例

DateTimeFormatter で日付を文字列に変換する
import java.time.LocalDate;

public class DateFormatting {

    private static final DateTimeFormatter YMD =
        DateTimeFormatter.ofPattern("yyyy/MM/dd");

    private static final DateTimeFormatter FULL_JP =
        DateTimeFormatter.ofPattern(
            "yyyy年MM月dd日(EEE) HH:mm", Locale.JAPANESE);

    public static void main(String[] args) {

        var today = LocalDate.of(2025, 3, 27);
        System.out.println("スラッシュ: " + today.format(YMD));

        var now = LocalDateTime.now();
        System.out.println("日本語: " + now.format(FULL_JP));

        System.out.println("ISO: " +
            today.format(DateTimeFormatter.ISO_LOCAL_DATE));

        var parsed = LocalDate.parse("2025/03/27", YMD);
        System.out.println("パース結果: " + parsed);
    }
}

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

Version Coverage

テキストブロック(Java 15+)でフォーマットパターン文字列を読みやすく定義できる。DateTimeFormatter 自体の API に変化はない。

Java 17
// Java 17: DateTimeFormatter(スレッドセーフ)
private static final DateTimeFormatter DTF =
    DateTimeFormatter.ofPattern("yyyy/MM/dd");
String formatted = LocalDate.now().format(DTF);

Library Comparison

Pure Java (DateTimeFormatter)日付フォーマットだけなら標準 API で十分。スレッドセーフで性能も良い。パターン文字の仕様を覚える必要がある。
Apache Commons Lang (DateFormatUtils)旧来コードとの互換で SimpleDateFormat ベースのユーティリティが欲しい場合。Java 8 以降は DateTimeFormatter で代替可能。
ICU4J多言語の日付フォーマットや暦体系を細かく制御したい場合。依存が大きく、日本語フォーマットだけなら標準 API で十分。

注意点

SimpleDateFormat はスレッドアンセーフ。マルチスレッド環境で共有するとフォーマット結果が壊れる。DateTimeFormatter へ移行するのが安全

DateTimeFormatter.ofPattern の月は MM(2桁ゼロ埋め)と M(ゼロ埋めなし)で異なる。帳票仕様に合わせて使い分けること

曜日を日本語で表示するには Locale.JAPANESE を明示する。指定しないと JVM のデフォルトロケールに依存する

DateTimeFormatter は不変オブジェクトのため、static final フィールドで定義して使い回すのが定石

FAQ

SimpleDateFormat から DateTimeFormatter への移行は一括でやるべきですか?

新規コードは DateTimeFormatter に統一し、既存コードは影響範囲を見て段階的に置き換えるのが現実的です。

フォーマットパターンの大文字と小文字の違いは?

M は月、m は分、H は24時間制の時、h は12時間制の時です。混同するとパース時に例外になります。

DateTimeFormatter を static final で定義して問題ないですか?

DateTimeFormatter は不変でスレッドセーフなので、static final で共有するのが推奨パターンです。

関連書籍

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

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