読み込み中...

JavaでマスターするDateTimeFormatterの日付操作たった7つの方法

JavaでDateTimeFormatterを使った日付と時刻の扱い方 Java
この記事は約31分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Javaで日付と時刻を扱うなら、文字列へのフォーマットと文字列からの解析を同じ設計で扱えるDateTimeFormatterを押さえると、ログ、CSV、APIレスポンス、画面表示の実装が整理しやすくなります。ただし、yyyyYYYYの違い、Localeの有無、ZoneIdの扱いを曖昧にすると、日付のずれや解析エラーにつながります。

そのため、基本のLocalDateLocalTimeLocalDateTimeから入り、時刻帯、ロケール、例外処理、DateTimeFormatterBuilderまで順に確認する構成にしているのが基本です。関連するJavaの基礎はJava List型完全ガイドJavaでうるう年を判定する解説も合わせて参照できます。

動作確認環境
  • Java 21 LTS
  • 標準ライブラリ java.time / java.util.Locale
  • 外部ライブラリ例のみ Joda-Time 2.12系
📖 この記事で学べること
  • DateTimeFormatterで日付と時刻を文字列へ整形する方法
  • LocalDateTime.parseで文字列を解析するときの考え方
  • LocaleZoneIdを使った表示の切り替え
  • DateTimeParseExceptionへの対処法
  • DateTimeFormatterBuilderによるカスタマイズ方法

DateTimeFormatterとは

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class Main {
  public static void main(String[] args) {
    LocalDate date = LocalDate.of(2026, 6, 21);
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    System.out.println(date.format(formatter));
  }
}

結果: 期待される出力は2026-06-21です。

これがDateTimeFormatterの最小構成です。Javaのjava.timeでは、日付を持つLocalDate、時刻を持つLocalTime、両方を持つLocalDateTimeに対して、同じ考え方でフォーマットを適用できます。

その設計は、公式ドキュメントでも確認できます。詳しい仕様はOracle公式 DateTimeFormatter APIOracle公式 java.time パッケージ概要が一次情報になるのが目安です。

Javaでの日付と時刻の重要性

Javaアプリケーションでは、ログのタイムスタンプ、予約日時、決済期限、ファイル名、画面表示などに日付と時刻が含まれます。そのため、内部処理では型として安全に扱い、外部へ出す直前に文字列へ変換する流れが一般的です。

このとき、Stringだけで日付を持ち回ると、並び替え、比較、時刻帯変換、入力チェックが複雑になります。JavaのLocalDateZonedDateTimeを使い、表示や通信の境界でDateTimeFormatterを使う方法にすると、処理の責務を分けられますし、ここがポイントです。

一方、フォーマット文字列を間違えると、年や月の意味が変わります。たとえばMMは月、mmは分なので、日付と時刻を同時に扱うコードでは大文字と小文字の違いを確認する必要があります。

DateTimeFormatterの基本

DateTimeFormatterは、Java 8以降の日時APIで使われるフォーマッタです。主な役割は、日時オブジェクトから文字列を作るフォーマットと、文字列から日時オブジェクトを作る解析になるのがポイントです。

具体的には、ofPatternyyyy-MM-ddのようなパターンを作り、formatで文字列へ変換します。逆方向ではparseを使い、入力文字列が指定したパターンに合わない場合はDateTimeParseExceptionで扱います。

分類主な要素用途注意点
日付LocalDate年月日だけを扱う時刻情報は持たない
時刻LocalTime時分秒だけを扱う日付情報は持たない
日時LocalDateTime日付と時刻をまとめる時刻帯は持たない
時刻帯ZonedDateTime地域の時刻を扱うZoneIdが必要
パターンyyyy暦年を表すYYYYと混同しない
パターンMM月を表すmmは分
パターンdd日を表す存在しない日付は解析で失敗し得る
パターンHH24時間制の時を表すhhは12時間制
ロケールLocale曜日や月名の言語を決める省略時は環境依存になる場合がある
例外DateTimeParseException解析失敗を扱う入力値の検証と組み合わせる

これらの要素を分けて考えると、DateTimeFormatterの方法は単なる文字列置換ではないと理解できます。Javaの型が日時の意味を持ち、フォーマットだけが表示形式を担当する構造になります。

DateTimeFormatterの使い方

基本の使い方は、対象の日時型を決め、パターンを作り、formatまたはparseを呼ぶ流れです。Javaの日時処理では、内部データと表示文字列を混ぜないことが保守性につながりますが、これは押さえたい点です。

そのため、画面やファイルに出す日付はStringへ変換し、計算や比較を行う日付はLocalDateなどの型で持つ方法が扱いやすくなります。Javaエスケープ処理の解説で扱う文字列処理と組み合わせる場面もあります。

サンプルコード1:基本的な日付のフォーマット

日付だけを表示する場合はLocalDateを使いるのが一般的です。この型は時刻を含まないため、年月日だけを扱うフォーム入力や期限表示に向いています。

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class Main {
  public static void main(String[] args) {
    // 現在の日付を取得
    LocalDate date = LocalDate.now();
    // フォーマッターを作成
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    // 日付をフォーマット
    String formattedDate = date.format(formatter);
    // 出力
    System.out.println("フォーマット後の日付:" + formattedDate);
  }
}

結果: 期待される出力はフォーマット後の日付:2026-06-21のような形式です。実際の日付部分は実行日によって変わります。

このコードではLocalDate.now()で現在日付を取得し、DateTimeFormatter.ofPattern("yyyy-MM-dd")で表示形式を決めています。date.format(formatter)の戻り値はStringなので、以降は画面表示やログ出力へ渡せますし、これが一つの目安です。

サンプルコード2:基本的な時刻のフォーマット

時刻だけを扱う場合はLocalTimeを使います。日付を含まないため、毎日の開始時刻、締切時刻、バッチ起動時刻のような値に合います。

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class Main {
  public static void main(String[] args) {
    // 現在の時刻を取得
    LocalTime time = LocalTime.now();
    // フォーマッターを作成
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
    // 時刻をフォーマット
    String formattedTime = time.format(formatter);
    // 出力
    System.out.println("フォーマット後の時刻:" + formattedTime);
  }
}

結果: 期待される出力はフォーマット後の時刻:14:30:15のような形式です。時刻部分は実行した瞬間により変わります。

このときHHは24時間制の時、mmは分、ssは秒を表します。特にMMmmの混同は初心者がつまずきやすい箇所なので、日付の月と時刻の分を分けて覚えると安全です。

サンプルコード3:カスタムフォーマットを作成

日付と時刻をまとめて扱う場合はLocalDateTimeが使えるのが現実的です。曜日や午前午後を加えたい場合も、パターンを組み合わせればひとつの文字列にできます。

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

public class Main {
  public static void main(String[] args) {
    // 現在の日付と時刻を取得
    LocalDateTime dateTime = LocalDateTime.now();
    // カスタムフォーマッターを作成
    DateTimeFormatter customFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy hh:mm a E");
    // 日付と時刻をカスタムフォーマットで整形
    String customFormattedDateTime = dateTime.format(customFormatter);
    // 出力
    System.out.println("カスタムフォーマット後の日付と時刻:" + customFormattedDateTime);
  }
}

結果: 期待される出力はカスタムフォーマット後の日付と時刻:21/06/2026 03:15 PM Sunのような形式です。曜日や午前午後の表記はロケールの影響を受けます。

そのパターンでは、dd/MM/yyyyが日月年、hh:mmが12時間制の時刻、aが午前午後、Eが曜日を表します。日本語表記にしたい場合は、後続のロケール指定と合わせて考える必要があると整理できます。

サンプルコード4:ロケールによるフォーマットの変更

曜日名や月名を含むフォーマットでは、Localeが表示言語に関わります。Javaの実行環境に任せると想定と異なる言語になる場合があるため、外部向け表示では明示する方法が安定します。

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

public class Main {
  public static void main(String[] args) {
    // 現在の日付と時刻を取得
    LocalDateTime dateTime = LocalDateTime.now();
    // ロケールをフランスに設定してフォーマッターを作成
    DateTimeFormatter frenchFormatter = DateTimeFormatter.ofPattern("EEEE dd MMMM yyyy", Locale.FRANCE);
    // 日付と時刻をフランスのロケールでフォーマット
    String frenchFormattedDateTime = dateTime.format(frenchFormatter);
    // 出力
    System.out.println("フランスのロケールでの日付:" + frenchFormattedDateTime);
  }
}

結果: 期待される出力はフランスのロケールでの日付:dimanche 21 juin 2026のような形式です。実行日によって曜日、日、月、年は変わります。

この例ではLocale.FRANCEを渡すことで、曜日をEEEE、月名をMMMMとしてフランス語で出力します。多言語サイトや海外向けCSVでは、DateTimeFormatterのパターンだけでなくLocaleも仕様として決める必要があると理解できます。

サンプルコード5:時刻帯の指定

時刻帯を含む表示では、ZoneIdZonedDateTimeの考え方が関係します。LocalDateTime自体は地域情報を持たないため、東京やUTCなどの基準を別に与えます。

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

public class Main {
  public static void main(String[] args) {
    // 現在の日付と時刻を取得
    LocalDateTime dateTime = LocalDateTime.now();
    // 東京の時刻帯を設定
    ZoneId tokyoZoneId = ZoneId.of("Asia/Tokyo");
    // DateTimeFormatterに時刻帯を設定
    DateTimeFormatter formatterWithZone = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss Z")
      .withZone(tokyoZoneId);
    // 日付と時刻をフォーマット
    String formattedDateTimeWithZone = formatterWithZone.format(dateTime.atZone(tokyoZoneId));
    // 出力
    System.out.println("東京の時刻帯での日付と時刻:" + formattedDateTimeWithZone);
  }
}

結果: 期待される出力は東京の時刻帯での日付と時刻:2026-06-21 17:30:45 +0900のような形式です。日時部分は実行時点により変わります。

このコードではZoneId.of("Asia/Tokyo")を作り、withZoneでフォーマッタに時刻帯を渡しています。末尾のZはUTCとの差を表し、東京の場合は通常+0900になると覚えるとよいでしょう。

💡 Tips: APIの保存値にはInstantやUTC基準の日時を使い、表示時にZoneIdで利用者向けの時刻へ変換する設計がよく使われます。

サンプルコード6:テキストから日付・時刻への変換

文字列を日時型へ変換する処理は解析と呼ばれます。入力フォーム、CSV、外部APIの値をJavaの型へ戻すときに使う方法です。

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

public class Main {
  public static void main(String[] args) {
    // フォーマッターを作成
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    // 文字列から日付と時刻を解析
    LocalDateTime parsedDateTime = LocalDateTime.parse("2023-12-25 12:34:56", formatter);
    // 出力
    System.out.println("解析された日付と時刻:" + parsedDateTime);
  }
}

結果: 期待される出力は解析された日付と時刻:2023-12-25T12:34:56です。

この例では入力文字列の2023-12-25 12:34:56と、パターンのyyyy-MM-dd HH:mm:ssが対応しています。解析後のLocalDateTimeをそのまま出力すると、標準のISO形式に近いT区切りで表示されます。

サンプルコード7:エラーハンドリング

解析では、入力の形が合わない文字列や存在しない日付が渡される可能性があると考えられます。その場合はDateTimeParseExceptionを捕捉し、利用者へ再入力を促すなどの対処を入れます。

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

public class Main {
  public static void main(String[] args) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String incorrectString = "2023-02-30 12:34:56"; // 閏年でないため、2月30日は存在しない

    try {
      LocalDateTime parsedDateTime = LocalDateTime.parse(incorrectString, formatter);
    } catch (DateTimeParseException e) {
      System.out.println("不正な日付・時刻の形式です:" + e.getMessage());
    }
  }
}

結果: 期待される出力は不正な日付・時刻の形式です:に続いて解析エラーの詳細が表示される形です。

この入力には存在しない2月30日が含まれるため、解析時に例外が発生します。Javaでフォーム入力を扱う場合は、うるう年判定の考え方と合わせて、日付として成立するかを確認する設計が必要になります。

DateTimeFormatterの応用例

基本的なフォーマットと解析を押さえたら、日付計算、複数パターンの入力、既存ライブラリとの接続が応用の中心になると言えるでしょう。JavaのDateTimeFormatterは表示担当として使い、計算そのものはplusDaysminusHoursなど日時型のメソッドに任せます。

サンプルコード8:日付と時刻の計算

日付や時刻の計算では、計算後の値を人が読める形へ変換する場面が多くあります。その出力部分でDateTimeFormatterを使うと、計算ロジックと表示形式を分離できるのが基本です。

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

public class Main {
    public static void main(String[] args) {
        // 現在日時の取得
        LocalDateTime now = LocalDateTime.now();
        // 10日後と5時間前の日時を計算
        LocalDateTime futureDate = now.plusDays(10).minusHours(5);

        // DateTimeFormatterで日時を文字列に変換
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formattedFutureDate = futureDate.format(formatter);

        // 出力する
        System.out.println("計算後の日時: " + formattedFutureDate);
    }
}

結果: 期待される出力は計算後の日時: 2026-07-01 12:20:45のような形式です。現在日時を基準にするため、具体的な値は実行時点で変わります。

この例ではplusDays(10)で10日後へ進め、minusHours(5)で5時間戻しています。計算結果のLocalDateTimeに対してformatを呼ぶため、時刻計算とフォーマットの責務が混ざりません。

サンプルコード9:複数のフォーマットを扱う

外部から受け取る文字列では、日付だけ、分まで、秒までのように粒度が揺れることがあるのが目安です。その場合は、許可する入力形式を明確にして解析する必要があります。

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

public class Main {
    public static void main(String[] args) {
        String[] dateTimeStrings = {
            "2023-10-05",
            "2023-10-05 15:30",
            "2023-10-05T15:30:20"
        };

        for (String dateTimeString : dateTimeStrings) {
            try {
                LocalDateTime parsedDateTime = LocalDateTime.parse(dateTimeString,
                    DateTimeFormatter.ofPattern("[yyyy-MM-dd][yyyy-MM-dd HH:mm][yyyy-MM-dd'T'HH:mm:ss]"));
                System.out.println("解析成功: " + parsedDateTime);
            } catch (DateTimeParseException e) {
                System.out.println("解析失敗: " + e.getMessage());
            }
        }
    }
}

結果: 期待される出力は、入力ごとに解析成功または解析失敗が表示される形です。日付だけの入力はLocalDateTimeに必要な時刻が不足するため、環境や解決ルールにより失敗する可能性があります。

このコードは複数の候補を角括弧で表す方法を示しています。ただし、日付だけの文字列をLocalDateTimeへ直接解析するには時刻の既定値が必要になるため、実務ではLocalDate.parseatStartOfDayを組み合わせる方法も検討するのがポイントです。

⚠️ 注意: 複数パターンを許可しすぎると、入力ミスも正しい値として通る場合があります。受け付けるフォーマットは画面仕様やAPI仕様で絞るほうが扱いやすくなります。

サンプルコード10:外部ライブラリとの連携

Java 8より前のシステムでは、Joda-Timeが使われている場合があるのが一般的です。現在の新規実装では標準のjava.timeが選ばれますが、既存コードの移行では両者の表記差を確認する場面があります。

import org.joda.time.format.DateTimeFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        // Java 8のDateTimeFormatter
        DateTimeFormatter java8Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // Joda-TimeのDateTimeFormatter
        org.joda.time.format.DateTimeFormatter jodaFormatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");

        // Joda-TimeのDateTimeFormatterをJava 8のDateTimeFormatterに変換
        DateTimeFormatter convertedFormatter = DateTimeFormatter.ofPattern(jodaFormatter.toString());

        LocalDateTime dateTime = LocalDateTime.now();
        String formattedDate = dateTime.format(convertedFormatter);
        System.out.println("フォーマットされた日時: " + formattedDate);
    }
}

結果: 期待される出力はフォーマットされた日時: 2026-06-21 16:45:30のような形式です。日時部分は実行時点で変わります。

この例は移行時の発想を示すためのコードです。ただし、jodaFormatter.toString()が常にJava標準のパターンとして安全に再利用できるとは限らないため、実際の移行ではJoda-Time側のパターン文字列を棚卸しし、JavaのDateTimeFormatterへ明示的に置き換える方法が現実的です。

注意点と対処法

DateTimeFormatterを使うときに気をつけたい点は、存在しない日付、ロケール差、スレッドセーフ性、パターン文字の意味です。Javaの標準APIは多くのケースを支えますが、入力値や表示要件を曖昧にすると解析エラーや表示ずれが起きます。

そのため、対処法はエラーを握りつぶすことではなく、許可するフォーマット、対象のLocale、対象のZoneIdをコード上で明示することになるのが現実的です。アノテーションで入力検証を整理する場合はJavaアノテーションの解説も関連します。

年月日の範囲とバリデーション

入力された日付がカレンダー上で成立するかは、解析時に確認されます。特に2月29日、2月30日、月末日、うるう年は、単純な文字数チェックだけでは判断できません。

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

public class Main {
    public static void main(String[] args) {
        String input = "2023-02-30";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        try {
            LocalDate date = LocalDate.parse(input, formatter);
            System.out.println("成功: " + date);
        } catch (DateTimeParseException e) {
            System.out.println("失敗: " + e.getMessage());
        }
    }
}

結果: 期待される出力は失敗:に続いて、2023-02-30を解析できない理由が表示される形です。

この例では、文字列の形はyyyy-MM-ddに合っていますが、値としての2月30日が成立しません。日付の解析では、見た目のフォーマットとカレンダー上の妥当性を分けて考える必要があります。

ロケールに依存する問題

月名や曜日名を含む文字列は、ロケールに依存します。日本語、英語、フランス語などで表記が変わるため、解析とフォーマットの両方で同じLocaleを使う方法が安定すると整理できます。

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM dd, yyyy", Locale.US);
        System.out.println(formatter.format(LocalDate.now()));
    }
}

結果: 期待される出力はJune 21, 2026のような米国英語の月名を含む形式です。実行日によって日付は変わります。

このコードではLocale.USを渡すため、MMMMが英語の月名になります。逆に日本語表示にしたい場合はLocale.JAPANを検討し、外部仕様で言語を固定するのが基本になると理解できます。

スレッドセーフ性

DateTimeFormatterはイミュータブルに設計されており、複数スレッドで共有できます。この性質により、従来のSimpleDateFormatで問題になりやすかった共有時の状態破壊を避けやすくなります。

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

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        Runnable formatTask = () -> {
            LocalDateTime dateTime = LocalDateTime.now();
            String result = dateTime.format(formatter);
            System.out.println("スレッドセーフ: " + result);
        };

        Thread t1 = new Thread(formatTask);
        Thread t2 = new Thread(formatTask);

        t1.start();
        t2.start();
    }
}

結果: 期待される出力はスレッドセーフ: 2026-06-21 12:00:00のような行が複数表示される形です。各行の時刻はスレッドの実行タイミングで変わります。

この例では同じformatterRunnable内で共有しています。DateTimeFormatter自体は安全に共有できますが、周辺で扱う可変オブジェクトや出力先の制御は別の問題として確認すると覚えるとよいでしょう。

ℹ️ 補足: SimpleDateFormatを既存コードで使っている場合、新規追加部分からjava.timeへ寄せると、日付処理の設計を段階的に整理できます。

カスタマイズ方法

JavaのDateTimeFormatterは、単純なパターン文字列だけでなく、組み立て式のDateTimeFormatterBuilderでも作成できます。表示仕様が固定であればofPatternで足りることが多く、任意項目や細かい制御が必要ならビルダーを検討すると考えられます。

具体的には、yyyyMMddHHmmssSSSEaZXXXなどを組み合わせます。日時の仕様が複雑になるほど、パターンの意味をコメントや定数名で補う方法が読みやすくなります。

フォーマットパターンの詳細

パターン文字は、見た目が似ていても意味が異なると言えるでしょう。たとえばyyyyは暦年、MMは月、ddは日、HHは24時間制の時、mmは分、ssは秒です。

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

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        LocalDateTime now = LocalDateTime.now();
        String formattedDate = now.format(formatter);
        System.out.println(formattedDate);
    }
}

結果: 期待される出力は2026/06/21 15:45:30のような形式です。現在日時を使うため、具体的な値は実行時点で変わります。

このパターンは、スラッシュ区切りの日付とコロン区切りの時刻をひとつの文字列にします。Web画面ではこの表示が読みやすい場合がありますが、API連携ではISO形式のISO_LOCAL_DATE_TIMEなどを使うほうが仕様を合わせやすいこともあるのが基本です。

DateTimeFormatterBuilderを使った高度なカスタマイズ

DateTimeFormatterBuilderは、日時の部品を順番に追加してフォーマッタを作るクラスです。固定文字、特定フィールド、既存フォーマッタを組み合わせられるため、細かい仕様をコードとして表現できます。

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;

public class Main {
    public static void main(String[] args) {
        DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
        builder.append(DateTimeFormatter.ISO_LOCAL_DATE)
               .appendLiteral(" ")
               .appendValue(ChronoField.HOUR_OF_DAY, 2)
               .appendLiteral(":")
               .appendValue(ChronoField.MINUTE_OF_HOUR, 2);

        DateTimeFormatter formatter = builder.toFormatter();
        LocalDateTime now = LocalDateTime.now();
        String formattedDate = now.format(formatter);
        System.out.println(formattedDate);
    }
}

結果: 期待される出力は2026-06-21 15:45のような形式です。分までを表示し、秒は含みません。

このコードではappendappendLiteralappendValueを使い、ChronoField.HOUR_OF_DAYChronoField.MINUTE_OF_HOURを2桁で出しています。ビルダーの詳細はOracle公式 DateTimeFormatterBuilder APIで確認できます。

💡 Tips: 画面表示用、ログ用、API用でDateTimeFormatterを分けると、後から表示形式を変えるときの影響範囲を追いやすくなるのが目安です。

同様に、フォーマッタを定数として共有する場合は、用途が分かる名前を付けます。たとえばDISPLAY_DATE_FORMATTERLOG_DATE_TIME_FORMATTERCSV_DATE_FORMATTERのように分けると、Javaコード上で意図が読み取りやすくなります。

まとめ

Javaで日付と時刻を扱うときは、内部ではLocalDateLocalTimeLocalDateTimeZonedDateTimeなどの型を使い、外部表示や入力解析の境界でDateTimeFormatterを使う構成が分かりやすくなるのがポイントです。フォーマットと解析の方法を分けて理解すると、画面表示、ログ、CSV、API連携の実装に応用できます。

その中でも特に押さえたいのは、ofPatternの文字の意味、Localeによる月名や曜日名の違い、ZoneIdによる時刻帯の扱い、DateTimeParseExceptionによる解析失敗の制御です。これらをコード上で明示すると、環境差や入力値の揺れに強いJava実装になります。

一方、複雑なフォーマットをひとつのパターン文字列へ詰め込むと、後から読む人が意図を追いにくくなるのが一般的です。DateTimeFormatterBuilder、用途別の定数、入力値ごとの解析分岐を使い分ける方法を取ると、日付と時刻の処理を保守しやすくできます。

Javaの周辺知識を広げるなら、コレクション処理はList型の使い方、入力検証の設計はアノテーションの活用、継承を含む設計はオーバーライドの解説も関連します。日時処理は単独の知識ではなく、文字列、例外、型設計と組み合わせて使う技術です。

関連記事

著者: Japanシーモア編集部

Japanシーモアは、Web/IoT/APP/SYS 分野のプログラミング情報を体系的に提供するメディアです。本記事は編集部による執筆とAI支援を組み合わせて制作し、公開前に編集部が校正しています。誤りや改善案がございましたらお問い合わせよりご連絡ください。

※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。