Java | Java 標準ライブラリ:DateTimeFormatter

Java Java
スポンサーリンク

DateTimeFormatter をざっくり一言でいうと

DateTimeFormatter は、

LocalDate / LocalTime / LocalDateTime / ZonedDateTime などを
“文字列 ⇔ 日付時刻オブジェクト”に変換するための道具」

です。

画面に表示するときや、文字列から日時を読み込むときに必ず出てきます。

古い SimpleDateFormat と違って、

スレッドセーフ(マルチスレッドで共有しても壊れない)
不変(immutable)で安全
java.time 系と綺麗に一体になっている

という、かなり頼れる存在です。


基本イメージ:format(→文字列)と parse(←文字列)

「日時 → 文字列」にする(format)

例えば、LocalDateTime"2025/01/10 09:30:15" のように表示したいとします。

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

public class FormatterBasicFormat {
    public static void main(String[] args) {
        LocalDateTime dt = LocalDateTime.of(2025, 1, 10, 9, 30, 15);

        DateTimeFormatter fmt =
                DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");

        String text = dt.format(fmt);

        System.out.println(text); // 2025/01/10 09:30:15
    }
}
Java

ofPattern("パターン文字列") で「どういう形で表示するか」を決め、
dt.format(fmt) で、そのパターンに沿った文字列を作ります。

「日時オブジェクトが、自分に渡されたフォーマッタを使って文字列に変換している」とイメージすると分かりやすいです。

「文字列 → 日時」にする(parse)

逆に、文字列から LocalDateTime を作りたい場合。

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

public class FormatterBasicParse {
    public static void main(String[] args) {
        String text = "2025/01/10 09:30";

        DateTimeFormatter fmt =
                DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm");

        LocalDateTime dt = LocalDateTime.parse(text, fmt);

        System.out.println(dt); // 2025-01-10T09:30
    }
}
Java

LocalDateTime.parse(文字列, フォーマッタ) の形です。

format と parse は「逆方向」の操作ですが、
どちらも DateTimeFormatter を挟んでいるイメージを持ってください。


よく使う書式パターン(最低限これだけは覚えておく)

年・月・日(date 部分)

yyyy は西暦 4 桁です。
MM は 2 桁の月(01〜12)、dd は 2 桁の日(01〜31)です。

代表例として:

"yyyy-MM-dd"2025-01-10
"yyyy/MM/dd"2025/01/10

Md を一桁にすると、「先頭ゼロなし」になります。

"yyyy-M-d"2025-1-2(1 月 2 日)

ブラウザや他システムとのやりとりでは、
"yyyy-MM-dd" のような ISO 風の書式を使うことが多いです。

時・分・秒(time 部分)

HH は 0〜23 時の 2 桁
mm は分
ss は秒

代表的な例:

"HH:mm"09:30
"HH:mm:ss"09:30:15

H にすると先頭ゼロなしで 9:5:3 のような表現も可能ですが、
人間向け表示なら "HH:mm" で良いことが多いです。

日付+時刻

組み合わせるだけです。

"yyyy-MM-dd HH:mm:ss"2025-01-10 09:30:15
"yyyy/MM/dd HH:mm"2025/01/10 09:30

LocalDateTimeZonedDateTime を扱うときは、この形が一番よく出てきます。


DateTimeFormatter の「スレッドセーフ」「不変」がなぜ大事か

SimpleDateFormat との違い

昔の SimpleDateFormat は、

インスタンスを複数スレッドで共有すると内部状態が壊れる
static で 1 個だけ作って全体で使う、が実は危険

という欠点がありました。

そのため、Web アプリや並列処理で日時のフォーマット/パースをするとき、
「たまにだけ変な日付になる」ようなバグを生みやすかったのです。

DateTimeFormatter は、

不変(immutable)
スレッドセーフ

なので、「static な定数として共有」して構いません。

public class FormatterHolder {
    public static final DateTimeFormatter ISO_DATE_TIME =
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
}
Java

こうしておいて、どこからでも

String s = dt.format(FormatterHolder.ISO_DATE_TIME);
Java

と安心して呼べます。

「フォーマット用オブジェクトをどこに持つか?」で悩まなくてよくなるのは、想像以上にストレスを減らしてくれます。


LocalDate / LocalTime / LocalDateTime / ZonedDateTime との組み合わせ

LocalDate と DateTimeFormatter

日付だけのフォーマット/パース。

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

LocalDate date = LocalDate.of(2025, 1, 10);

DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
String text = date.format(fmt);

System.out.println(text); // 2025年01月10日
Java

パースも同様です。

String input = "2025/01/10";
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy/MM/dd");

LocalDate date = LocalDate.parse(input, fmt);
System.out.println(date); // 2025-01-10
Java

LocalTime と DateTimeFormatter

時刻だけ。

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

LocalTime time = LocalTime.of(9, 5, 3);

DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm:ss");
System.out.println(time.format(fmt)); // 09:05:03
Java

LocalDateTime / ZonedDateTime と DateTimeFormatter

日付+時刻(+タイムゾーン)も同様に扱えます。

import java.time.*;
import java.time.format.DateTimeFormatter;

LocalDateTime ldt = LocalDateTime.of(2025, 1, 10, 9, 30, 15);
ZonedDateTime  zdt = ldt.atZone(ZoneId.of("Asia/Tokyo"));

DateTimeFormatter fmt1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
DateTimeFormatter fmt2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss O (VV)");

System.out.println(ldt.format(fmt1)); // 2025-01-10 09:30:15
System.out.println(zdt.format(fmt2)); // 2025-01-10 09:30:15 GMT+9 (Asia/Tokyo)
Java

O はオフセット(GMT+9 など)、VV はゾーン ID を表します。


よく使う「定義済みフォーマッタ」も覚えておくと楽になる

ISO 系の定義済みフォーマッタ

DateTimeFormatter には、よく使うフォーマットがあらかじめ定義されています。

代表的なものを挙げると:

DateTimeFormatter.ISO_LOCAL_DATE
例: 2025-01-10

DateTimeFormatter.ISO_LOCAL_TIME
例: 09:30:15.123

DateTimeFormatter.ISO_LOCAL_DATE_TIME
例: 2025-01-10T09:30:15.123

DateTimeFormatter.ISO_OFFSET_DATE_TIME
例: 2025-01-10T09:30:15+09:00

などがあります。

例えば、

LocalDateTime dt = LocalDateTime.of(2025, 1, 10, 9, 30);
String s = dt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);

System.out.println(s); // 2025-01-10T09:30:00
Java

ブラウザや他言語と連携するときは、
こうした ISO 形式をそのまま使うことが多いので、覚えておくと便利です。


ありがちなハマりポイントと、安全な使い方のコツ

パターンと入力・出力の「形」を必ず一致させる

よくあるのが、

"2025-1-2" な文字列に対して
"yyyy-MM-dd" のフォーマットで parse しようとして失敗する

というパターンです。

"yyyy-MM-dd" は「必ず 2 桁の月・日」を期待しているので、
"2025-01-02" でなければ parse できません。

一方 "yyyy-M-d" なら "2025-1-2""2025-01-02" も parse できます。

「入力文字列の実際の形」と
「フォーマットパターンが期待している形」を
頭の中できっちり合わせるクセをつけてください。

ロケール(日本語の曜日・月名など)を使う場合

曜日や月名をロケールに応じて出したい場合は、withLocale を使います。

import java.time.*;
import java.time.format.*;
import java.util.Locale;

LocalDate date = LocalDate.of(2025, 1, 10);

DateTimeFormatter fmt =
        DateTimeFormatter.ofPattern("uuuu年M月d日(E)", Locale.JAPANESE);

System.out.println(date.format(fmt)); // 2025年1月10日(金)
Java

フォーマットパターンに E(曜日)や MMM(短い月名)などを使うときは、
どのロケールで解釈するかを意識する必要があります。

共通フォーマッタを定数化する

同じフォーマットを何度も書いていると、
タイプミスやパターン変更忘れの温床になります。

ヘッダ部分や別クラスにまとめておくのがおすすめです。

public final class Formats {
    private Formats() {}

    public static final DateTimeFormatter DATE =
            DateTimeFormatter.ofPattern("yyyy-MM-dd");

    public static final DateTimeFormatter DATE_TIME =
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
}
Java

使う側は、

String s = dt.format(Formats.DATE_TIME);
Java

と書くだけです。


まとめ:DateTimeFormatter を自分の中でどう位置づけるか

DateTimeFormatter を初心者向けに一言でまとめると、

java.time の日付・時刻オブジェクトを、
人間や他システムとやり取りするための“文字列表現”に変換する、
スレッドセーフで信頼できるフォーマット/パース用クラス」

です。

特に意識しておきたいのは、

  • format で日時 → 文字列、parse で文字列 → 日時
  • ofPattern で、自分の好きな表示形式/入力形式を定義できる
  • SimpleDateFormat と違って、不変でスレッドセーフなので、定数として共有してよい
  • LocalDate / LocalTime / LocalDateTime / ZonedDateTime と自然に組み合わせて使える

という点です。

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