DateTimeFormatter は、java.time の日付・日時(LocalDate、LocalDateTime、ZonedDateTime など)と文字列を相互に変換するクラスです。 DateTimeFormatter.ofPattern("uuuu/MM/dd") のようにパターン文字で形式を指定し、format で文字列へ、parse で日付へ変換します。不変でスレッドセーフなので、定数にして共有できます。

この記事では、パターン文字を一覧にして、同じ日時を整形した実際の出力を横に並べました。あわせて、DateTimeParseException を原因別に再現したメッセージ全文と直し方、定義済みフォーマッタの出力、Locale データ(CLDR)による表記の違いも載せています。

確認環境:Ubuntu 24.04 / OpenJDK 21.0.10。出力はすべて java ファイル名.java で実行した結果です。

よく使うパターンの早見表

2026年3月7日(土)14時5分9秒・日本時間を整形した出力です。

ほしい形 パターン/定数 出力
年月日(スラッシュ) uuuu/MM/dd 2026/03/07
年月日+時分秒 uuuu/MM/dd HH:mm:ss 2026/03/07 14:05:09
日本語+曜日 uuuu年M月d日(E) H時m分(Locale.JAPAN) 2026年3月7日(土) 14時5分
ISO 8601(T 区切り) uuuu-MM-dd'T'HH:mm:ss 2026-03-07T14:05:09
ISO 8601+オフセット uuuu-MM-dd'T'HH:mm:ssXXX 2026-03-07T14:05:09+09:00
ハイフン区切りの日付 DateTimeFormatter.ISO_LOCAL_DATE 2026-03-07
区切りなし8桁 DateTimeFormatter.BASIC_ISO_DATE(LocalDate) 20260307
和暦 GGGGy年M月d日(JapaneseDate) 令和8年3月7日
1桁の月日も読む uuuu/M/d 2026/3/7 と 2026/03/07 の両方を解析
時刻を省略できる uuuu/MM/dd[ HH:mm] 2026/03/07 14:05

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Java DateTimeFormatterパターン一覧|日付と文字列の変換」

日付と文字列を変換する基本コード

整形(format)と解析(parse)の完成形です。parse は「受け取りたい型」のメソッドを使うのが基本で、日付だけなら LocalDate.parse、日時なら LocalDateTime.parse を選びます。

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.Locale;

public class Usage {
    // 不変でスレッドセーフなので、定数として共有できる
    static final DateTimeFormatter YMD = DateTimeFormatter.ofPattern("uuuu/MM/dd");
    static final DateTimeFormatter YMD_HMS = DateTimeFormatter.ofPattern("uuuu/MM/dd HH:mm:ss");
    static final DateTimeFormatter JP = DateTimeFormatter.ofPattern("uuuu年M月d日(E) H時m分", Locale.JAPAN);

    public static void main(String[] args) {
        LocalDateTime dt = LocalDateTime.of(2026, 3, 7, 14, 5, 9);

        // 日付・日時 → 文字列
        System.out.println(dt.format(YMD_HMS));
        System.out.println(YMD.format(dt));              // formatter.format(日時) でも同じ
        System.out.println(dt.format(JP));
        System.out.println(dt.atZone(ZoneId.of("Asia/Tokyo"))
                .format(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXXX")));

        System.out.println(dt.toLocalDate().format(DateTimeFormatter.BASIC_ISO_DATE)
                + " | " + dt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));

        // 文字列 → 日付・日時(型に合った parse を使う)
        LocalDate d = LocalDate.parse("2026/03/07", YMD);
        LocalDateTime ldt = LocalDateTime.parse("2026/03/07 14:05:09", YMD_HMS);
        LocalTime time = LocalTime.parse("14:05", DateTimeFormatter.ofPattern("HH:mm"));
        OffsetDateTime odt = OffsetDateTime.parse("2026-03-07T14:05:09+09:00");
        ZonedDateTime zdt = ZonedDateTime.parse("2026/03/07 14:05:09 Asia/Tokyo",
                DateTimeFormatter.ofPattern("uuuu/MM/dd HH:mm:ss VV"));
        System.out.println(d + " | " + ldt + " | " + time);
        System.out.println(odt + " | " + zdt);

        // 1桁と2桁の両方を受け付ける:M/d と書く
        DateTimeFormatter loose = DateTimeFormatter.ofPattern("uuuu/M/d");
        System.out.println(LocalDate.parse("2026/3/7", loose) + " | " + LocalDate.parse("2026/03/07", loose));

        // 時刻が省略できる入力:[ ] と parseDefaulting
        DateTimeFormatter optional = new DateTimeFormatterBuilder()
                .appendPattern("uuuu/MM/dd[ HH:mm[:ss]]")
                .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
                .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
                .toFormatter();
        for (String s : new String[] {"2026/03/07", "2026/03/07 14:05", "2026/03/07 14:05:09"}) {
            System.out.println(s + " → " + LocalDateTime.parse(s, optional));
        }

        // 大文字・小文字を区別しない月名
        DateTimeFormatter ci = new DateTimeFormatterBuilder()
                .parseCaseInsensitive().appendPattern("d MMM uuuu").toFormatter(Locale.US);
        System.out.println(LocalDate.parse("7 MAR 2026", ci));
    }
}

実行結果:

2026/03/07 14:05:09
2026/03/07
2026年3月7日(土) 14時5分
2026-03-07T14:05:09+09:00
20260307 | 2026-03-07T14:05:09
2026-03-07 | 2026-03-07T14:05:09 | 14:05
  • M や d のように1文字で書くと、1桁と2桁の両方を解析できます。 MM は必ず2桁を求めます。
  • [ ] で囲んだ部分は、入力に無くても解析できます。 無かった項目の値は parseDefaulting で補います。
  • 引数なしの LocalDate.parse("2026-03-07") や OffsetDateTime.parse(...) は、ISO 8601 形式を読みます。

パターン文字の一覧と出力

2026-03-07T14:05:09.123456789+09:00[Asia/Tokyo] を、各パターンで整形した結果です。表は次のコードの出力そのままです。

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

public class Patterns {
    public static void main(String[] args) {
        // 2026年3月7日(土) 14:05:09.123456789 日本時間
        ZonedDateTime t = ZonedDateTime.of(2026, 3, 7, 14, 5, 9, 123_456_789, ZoneId.of("Asia/Tokyo"));
        String[][] rows = {
            {"uuuu", "年"}, {"uu", "年(下2桁)"}, {"yyyy", "紀元内の年"}, {"yy", "紀元内の年(下2桁)"},
            {"y", "紀元内の年(桁そろえなし)"}, {"YYYY", "週の年(暦の年とは別)"},
            {"G", "紀元(短い)"}, {"GGGG", "紀元(長い)"}, {"GGGGG", "紀元(1文字)"},
            {"M", "月"}, {"MM", "月(2桁)"}, {"MMM", "月(短い名前)"}, {"MMMM", "月(長い名前)"},
            {"MMMMM", "月(1文字)"}, {"LLLL", "月(単独で使う形)"},
            {"d", "日"}, {"dd", "日(2桁)"}, {"D", "年内の通算日"}, {"DDD", "年内の通算日(3桁)"},
            {"Q", "四半期"}, {"QQQ", "四半期(短い)"}, {"QQQQ", "四半期(長い)"},
            {"w", "週の年の第何週"}, {"W", "月の第何週"},
            {"E", "曜日(短い)"}, {"EEEE", "曜日(長い)"}, {"EEEEE", "曜日(1文字)"}, {"e", "曜日の番号(Locale依存)"},
            {"a", "午前/午後"}, {"B", "時間帯の呼び名"},
            {"H", "時(0〜23)"}, {"HH", "時(0〜23、2桁)"}, {"h", "時(1〜12)"}, {"hh", "時(1〜12、2桁)"},
            {"k", "時(1〜24)"}, {"K", "時(0〜11)"},
            {"m", "分"}, {"mm", "分(2桁)"}, {"s", "秒"}, {"ss", "秒(2桁)"},
            {"S", "秒の小数部1桁"}, {"SSS", "秒の小数部3桁(ミリ秒)"}, {"SSSSSS", "秒の小数部6桁(マイクロ秒)"},
            {"SSSSSSSSS", "秒の小数部9桁(ナノ秒)"}, {"n", "ナノ秒(数値)"}, {"A", "その日の通算ミリ秒"},
            {"VV", "タイムゾーンID"}, {"z", "ゾーン名(短い)"}, {"zzzz", "ゾーン名(長い)"},
            {"v", "ゾーン名(夏時間を区別しない、短い)"}, {"vvvv", "ゾーン名(同、長い)"},
            {"O", "GMTからの差(短い)"}, {"OOOO", "GMTからの差(長い)"},
            {"X", "オフセット(時のみ)"}, {"XX", "オフセット(コロンなし)"}, {"XXX", "オフセット(コロンあり)"},
            {"x", "オフセット(時のみ)"}, {"xxx", "オフセット(コロンあり)"},
            {"Z", "オフセット(コロンなし)"}, {"ZZZZ", "GMTからの差(長い)"}, {"ZZZZZ", "オフセット(コロンあり)"},
            {"uuuu-MM-dd'T'HH:mm:ss", "引用符:文字をそのまま出す"}, {"''yy", "'' でシングルクォート1個"},
            {"ppd", "p:次の項目を空白で桁そろえ"}, {"uuuu/MM/dd[ HH:mm]", "[ ]:省略できる部分"},
        };
        System.out.println("| パターン | 意味 | Locale.JAPAN | Locale.US |");
        System.out.println("|---|---|---|---|");
        for (String[] r : rows) {
            String jp = DateTimeFormatter.ofPattern(r[0], Locale.JAPAN).format(t);
            String us = DateTimeFormatter.ofPattern(r[0], Locale.US).format(t);
            System.out.println("| `" + r[0] + "` | " + r[1] + " | " + jp + " | " + us + " |");
        }
    }
}

実行結果:

パターン 意味 Locale.JAPAN Locale.US
uuuu 年 2026 2026
uu 年(下2桁) 26 26
yyyy 紀元内の年 2026 2026
yy 紀元内の年(下2桁) 26 26
y 紀元内の年(桁そろえなし) 2026 2026
YYYY 週の年(暦の年とは別) 2026 2026
G 紀元(短い) 西暦 AD
GGGG 紀元(長い) 西暦 Anno Domini
GGGGG 紀元(1文字) AD A
M 月 3 3
MM 月(2桁) 03 03
MMM 月(短い名前) 3月 Mar
MMMM 月(長い名前) 3月 March
MMMMM 月(1文字) 3 M
LLLL 月(単独で使う形) 3月 March
d 日 7 7
dd 日(2桁) 07 07
D 年内の通算日 66 66
DDD 年内の通算日(3桁) 066 066
Q 四半期 1 1
QQQ 四半期(短い) Q1 Q1
QQQQ 四半期(長い) 第1四半期 1st quarter
w 週の年の第何週 10 10
W 月の第何週 1 1
E 曜日(短い) 土 Sat
EEEE 曜日(長い) 土曜日 Saturday
EEEEE 曜日(1文字) 土 S
e 曜日の番号(Locale依存) 7 7
a 午前/午後 午後 PM
B 時間帯の呼び名 昼 in the afternoon
H 時(0〜23) 14 14
HH 時(0〜23、2桁) 14 14
h 時(1〜12) 2 2
hh 時(1〜12、2桁) 02 02
k 時(1〜24) 14 14
K 時(0〜11) 2 2
m 分 5 5
mm 分(2桁) 05 05
s 秒 9 9
ss 秒(2桁) 09 09
S 秒の小数部1桁 1 1
SSS 秒の小数部3桁(ミリ秒) 123 123
SSSSSS 秒の小数部6桁(マイクロ秒) 123456 123456
SSSSSSSSS 秒の小数部9桁(ナノ秒) 123456789 123456789
n ナノ秒(数値) 123456789 123456789
A その日の通算ミリ秒 50709123 50709123
VV タイムゾーンID Asia/Tokyo Asia/Tokyo
z ゾーン名(短い) JST JST
zzzz ゾーン名(長い) 日本標準時 Japan Standard Time
v ゾーン名(夏時間を区別しない、短い) GMT+09:00 JT
vvvv ゾーン名(同、長い) 日本時間 Japan Time
O GMTからの差(短い) GMT+9 GMT+9
OOOO GMTからの差(長い) GMT+09:00 GMT+09:00
X オフセット(時のみ) +09 +09
XX オフセット(コロンなし) +0900 +0900
XXX オフセット(コロンあり) +09:00 +09:00
x オフセット(時のみ) +09 +09
xxx オフセット(コロンあり) +09:00 +09:00
Z オフセット(コロンなし) +0900 +0900
ZZZZ GMTからの差(長い) GMT+09:00 GMT+09:00
ZZZZZ オフセット(コロンあり) +09:00 +09:00
uuuu-MM-dd'T'HH:mm:ss 引用符:文字をそのまま出す 2026-03-07T14:05:09 2026-03-07T14:05:09
''yy '' でシングルクォート1個 '26 '26
ppd p:次の項目を空白で桁そろえ 7 7
uuuu/MM/dd[ HH:mm] [ ]:省略できる部分 2026/03/07 14:05 2026/03/07 14:05

文字数で変わるルール

公式Javadoc では、文字の種類ごとに「文字数」の意味が決められています。

種類 対象の文字 文字数の意味
数値 d H h m s など 1文字は桁そろえなし、2文字以上はその桁数まで 0 で埋める
テキスト E a G など 3文字以下は短い形、4文字は長い形、5文字は1文字の形
数値/テキスト M L Q e 2文字以下は数値、3文字以上はテキスト
年 u y Y 2文字は下2桁(解析時は 2000〜2099 と解釈)。それ以外は最小の桁数
小数部 S 1〜9文字。足りない桁は切り捨て

似た文字の使い分け

組み合わせ 違い 選び方
u と y u は年、y は紀元内の年(紀元 G と組で意味が決まる) 西暦だけなら uuuu。和暦は G と y
y と Y Y は週の年。年末年始に暦の年とずれる 暦の年は小文字
M と L L は月名を単独で使う形。日本語・英語では同じ出力 ふつうは M
H h k K 0〜23/1〜12/1〜24/0〜11 24時間制は HH、12時間制は a と hh
S と n S は小数部(左から何桁)、n はナノ秒の数値 ミリ秒は SSS
m と M、d と D 分と月、日と年内の通算日 大文字・小文字を出力で確認
X と x オフセット 0 のとき X は Z、x は +00 ISO 8601 は XXX

ゾーンとオフセットの文字は UTC と夏時間で差が出る

日本時間では X と x、z と v の違いが見えにくいため、UTC と、夏時間のあるニューヨークで出力を比べます。同じコードで和暦の整形と解析も確認します。

import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.chrono.JapaneseChronology;
import java.time.chrono.JapaneseDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Zones {
    public static void main(String[] args) {
        // 1. オフセットが 0 のとき(UTC)と、夏時間のあるゾーンでの違い
        ZonedDateTime utc = ZonedDateTime.of(2026, 3, 7, 5, 5, 9, 0, ZoneOffset.UTC);
        ZonedDateTime nyWinter = utc.withZoneSameInstant(ZoneId.of("America/New_York"));
        ZonedDateTime nySummer = nyWinter.plusMonths(4);
        System.out.println("| パターン | UTC | New_York(3月) | New_York(7月) |");
        System.out.println("|---|---|---|---|");
        for (String p : new String[] {"X", "XXX", "x", "xxx", "Z", "ZZZZZ", "O", "VV", "z", "zzzz", "v"}) {
            DateTimeFormatter f = DateTimeFormatter.ofPattern(p, Locale.US);
            System.out.println("| `" + p + "` | " + f.format(utc) + " | " + f.format(nyWinter) + " | " + f.format(nySummer) + " |");
        }

        // 2. 和暦:JapaneseDate を整形する/フォーマッタに暦を設定する
        LocalDate d = LocalDate.of(2026, 3, 7);
        DateTimeFormatter wareki = DateTimeFormatter.ofPattern("GGGGy年M月d日", Locale.JAPAN);
        System.out.println(wareki.format(JapaneseDate.from(d)));
        System.out.println(wareki.withChronology(JapaneseChronology.INSTANCE).format(d));
        System.out.println(DateTimeFormatter.ofPattern("Gy.MM.dd", Locale.JAPAN).format(JapaneseDate.from(d)));
        System.out.println(DateTimeFormatter.ofPattern("GGGGGyy.MM.dd", Locale.JAPAN).format(JapaneseDate.from(d)));
        System.out.println(wareki.format(JapaneseDate.of(2019, 5, 1)));
        System.out.println(wareki.format(d) + "  ← 暦を指定しないと西暦");
        // 和暦の文字列を解析して LocalDate に戻す
        LocalDate back = LocalDate.parse("令和8年3月7日", wareki.withChronology(JapaneseChronology.INSTANCE));
        System.out.println(back);
    }
}

実行結果:

パターン UTC New_York(3月) New_York(7月)
X Z -05 -04
XXX Z -05:00 -04:00
x +00 -05 -04
xxx +00:00 -05:00 -04:00
Z +0000 -0500 -0400
ZZZZZ Z -05:00 -04:00
O GMT GMT-5 GMT-4
VV Z America/New_York America/New_York
z Z EST EDT
zzzz Z Eastern Standard Time Eastern Daylight Time
v Z ET ET
令和8年3月7日
令和8年3月7日
令和8.03.07
R08.03.07
令和1年5月1日
西暦2026年3月7日  ← 暦を指定しないと西暦
2026-03-07

z は時期によって EST/EDT と変わり、v は ET のままです。和暦は、JapaneseDate を渡すか、フォーマッタに withChronology(JapaneseChronology.INSTANCE) を設定すると出力できます。y は数値なので、2019年5月1日は「令和1年」と出力されました。暦を指定せずに LocalDate を渡すと、同じパターンでも「西暦2026年」になります。

DateTimeParseException を原因別に再現する

「直す前」で出たメッセージ全文と、「直す後」の結果を並べます。

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.ResolverStyle;
import java.util.Locale;
import java.util.function.Supplier;

public class ParseErrors {
    static int no = 1;

    static void run(String title, Supplier<Object> before, Supplier<Object> after) {
        System.out.println("[" + no++ + "] " + title);
        try {
            System.out.println("  直す前: " + before.get());
        } catch (RuntimeException e) {
            System.out.println("  直す前: " + e.getClass().getName() + ": " + e.getMessage());
        }
        System.out.println("  直す後: " + after.get());
    }

    static DateTimeFormatter p(String pattern) {
        return DateTimeFormatter.ofPattern(pattern);
    }

    public static void main(String[] args) {
        run("桁不足:MM/dd に 1桁の月日",
            () -> LocalDate.parse("2026/3/7", p("uuuu/MM/dd")),
            () -> LocalDate.parse("2026/3/7", p("uuuu/M/d")));
        run("区切り文字の違い:- と /",
            () -> LocalDate.parse("2026-03-07", p("uuuu/MM/dd")),
            () -> LocalDate.parse("2026-03-07", p("uuuu-MM-dd")));
        run("hh(1〜12)で 14時を読む",
            () -> LocalDateTime.parse("2026/03/07 14:05", p("uuuu/MM/dd hh:mm")),
            () -> LocalDateTime.parse("2026/03/07 14:05", p("uuuu/MM/dd HH:mm")));
        run("hh に午前/午後が無い",
            () -> LocalDateTime.parse("2026/03/07 02:05", p("uuuu/MM/dd hh:mm")),
            () -> LocalDateTime.parse("2026/03/07 午後 02:05", DateTimeFormatter.ofPattern("uuuu/MM/dd a hh:mm", Locale.JAPAN)));
        run("yyyy と STRICT の組み合わせ",
            () -> LocalDate.parse("2026/03/07", p("yyyy/MM/dd").withResolverStyle(ResolverStyle.STRICT)),
            () -> LocalDate.parse("2026/03/07", p("uuuu/MM/dd").withResolverStyle(ResolverStyle.STRICT)));
        run("STRICT で存在しない日付(2月30日)",
            () -> LocalDate.parse("2026/02/30", p("uuuu/MM/dd").withResolverStyle(ResolverStyle.STRICT)),
            () -> LocalDate.parse("2026/02/28", p("uuuu/MM/dd").withResolverStyle(ResolverStyle.STRICT)));
        run("LocalDate.parse に時刻つきの文字列(パターンは日付だけ)",
            () -> LocalDate.parse("2026/03/07 14:05", p("uuuu/MM/dd")),
            () -> LocalDate.parse("2026/03/07 14:05", p("uuuu/MM/dd HH:mm")));
        run("LocalDateTime.parse に日付だけの文字列",
            () -> LocalDateTime.parse("2026/03/07", p("uuuu/MM/dd")),
            () -> LocalDate.parse("2026/03/07", p("uuuu/MM/dd")).atStartOfDay());
        run("Locale 違いの月名:英語の月名を Locale.JAPAN で読む",
            () -> LocalDate.parse("Mar 7, 2026", DateTimeFormatter.ofPattern("MMM d, uuuu", Locale.JAPAN)),
            () -> LocalDate.parse("Mar 7, 2026", DateTimeFormatter.ofPattern("MMM d, uuuu", Locale.US)));
        run("引数なしの parse に ISO 形式以外の文字列",
            () -> LocalDate.parse("2026/03/07"),
            () -> LocalDate.parse("2026-03-07"));
        run("format 側:LocalDate を時刻つきパターンで整形",
            () -> LocalDate.of(2026, 3, 7).format(p("uuuu/MM/dd HH:mm")),
            () -> LocalDate.of(2026, 3, 7).atStartOfDay().format(p("uuuu/MM/dd HH:mm")));
        run("パターン文字として使えない文字(T を引用符で囲んでいない)",
            () -> p("uuuu-MM-ddTHH:mm"),
            () -> LocalDateTime.of(2026, 3, 7, 14, 5).format(p("uuuu-MM-dd'T'HH:mm")));
    }
}

実行結果:

[1] 桁不足:MM/dd に 1桁の月日
  直す前: java.time.format.DateTimeParseException: Text '2026/3/7' could not be parsed at index 5
  直す後: 2026-03-07
[2] 区切り文字の違い:- と /
  直す前: java.time.format.DateTimeParseException: Text '2026-03-07' could not be parsed at index 4
  直す後: 2026-03-07
[3] hh(1〜12)で 14時を読む
  直す前: java.time.format.DateTimeParseException: Text '2026/03/07 14:05' could not be parsed: Invalid value for ClockHourOfAmPm (valid values 1 - 12): 14
  直す後: 2026-03-07T14:05
[4] hh に午前/午後が無い
  直す前: java.time.format.DateTimeParseException: Text '2026/03/07 02:05' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {MinuteOfHour=5, HourOfAmPm=2},ISO resolved to 2026-03-07 of type java.time.format.Parsed
  直す後: 2026-03-07T14:05
[5] yyyy と STRICT の組み合わせ
  直す前: java.time.format.DateTimeParseException: Text '2026/03/07' could not be parsed: Unable to obtain LocalDate from TemporalAccessor: {YearOfEra=2026, MonthOfYear=3, DayOfMonth=7},ISO of type java.time.format.Parsed
  直す後: 2026-03-07
[6] STRICT で存在しない日付(2月30日)
  直す前: java.time.format.DateTimeParseException: Text '2026/02/30' could not be parsed: Invalid date 'FEBRUARY 30'
  直す後: 2026-02-28
[7] LocalDate.parse に時刻つきの文字列(パターンは日付だけ)
  直す前: java.time.format.DateTimeParseException: Text '2026/03/07 14:05' could not be parsed, unparsed text found at index 10
  直す後: 2026-03-07
[8] LocalDateTime.parse に日付だけの文字列
  直す前: java.time.format.DateTimeParseException: Text '2026/03/07' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {},ISO resolved to 2026-03-07 of type java.time.format.Parsed
  直す後: 2026-03-07T00:00
[9] Locale 違いの月名:英語の月名を Locale.JAPAN で読む
  直す前: java.time.format.DateTimeParseException: Text 'Mar 7, 2026' could not be parsed at index 0
  直す後: 2026-03-07
[10] 引数なしの parse に ISO 形式以外の文字列
  直す前: java.time.format.DateTimeParseException: Text '2026/03/07' could not be parsed at index 4
  直す後: 2026-03-07
[11] format 側:LocalDate を時刻つきパターンで整形
  直す前: java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: HourOfDay
  直す後: 2026/03/07 00:00
[12] パターン文字として使えない文字(T を引用符で囲んでいない)
  直す前: java.lang.IllegalArgumentException: Unknown pattern letter: T
  直す後: 2026-03-07T14:05

メッセージの読み方

メッセージの形 意味 直し方
could not be parsed at index N N 文字目(0始まり)でパターンと文字列が合わなかった N 文字目の桁数・区切り文字・月名の言語(Locale)を確認(1・2・9・10番)
Invalid value for ... (valid values 1 - 12): 14 読めたが値が範囲外 hh を HH に(3番)
Unable to obtain LocalDateTime from TemporalAccessor: {...} 読めたが、その型を作るための項目が足りない 波かっこの中に残った項目を見る。HourOfAmPm なら午前/午後、YearOfEra なら紀元が足りない(4・5・8番)
Invalid date 'FEBRUARY 30' STRICT で存在しない日付 入力を確認する(6番)
unparsed text found at index N N 文字目以降が読み残された パターンを入力に合わせる(7番)
Unsupported field: HourOfDay 整形する値がその項目を持たない 型を合わせる。UnsupportedTemporalTypeException(11番)
Unknown pattern letter: T パターンに使えない文字 'T' と引用符で囲む。IllegalArgumentException(12番)

5番は見落としやすい組み合わせです。yyyy は「紀元内の年」なので、STRICT では紀元(G)が無いと日付を確定できません。STRICT を使うときは uuuu と書きます。

ResolverStyle で「存在しない日付」の扱いを決める

ofPattern で作ったフォーマッタの既定は SMART です。withResolverStyle で切り替えた結果を、5つの入力で比べました(パターンは uuuu/MM/dd)。

入力 SMART(既定) STRICT LENIENT
2026/02/28 2026-02-28 2026-02-28 2026-02-28
2026/02/29 2026-02-28 例外 2026-03-01
2026/02/31 2026-02-28 例外 2026-03-03
2026/02/32 例外 例外 2026-03-04
2026/13/01 例外 例外 2027-01-01

SMART は 2月31日を月末の 2月28日に丸め、STRICT は例外、LENIENT は翌月へ繰り越します。 入力チェックとして使うなら STRICT が向いています。

定義済みフォーマッタの出力早見表

DateTimeFormatter.ISO_LOCAL_DATE などの定数は、パターンを書かずに使えます。2026-03-07T14:05:09.123+09:00[Asia/Tokyo] の ZonedDateTime を 定数.format(t) で整形した出力です。

定数 出力
ISO_LOCAL_DATE 2026-03-07
ISO_OFFSET_DATE 2026-03-07+09:00
ISO_DATE 2026-03-07+09:00
ISO_LOCAL_TIME 14:05:09.123
ISO_OFFSET_TIME 14:05:09.123+09:00
ISO_LOCAL_DATE_TIME 2026-03-07T14:05:09.123
ISO_OFFSET_DATE_TIME 2026-03-07T14:05:09.123+09:00
ISO_ZONED_DATE_TIME 2026-03-07T14:05:09.123+09:00[Asia/Tokyo]
ISO_DATE_TIME 2026-03-07T14:05:09.123+09:00[Asia/Tokyo]
ISO_INSTANT 2026-03-07T05:05:09.123Z
ISO_ORDINAL_DATE 2026-066+09:00
ISO_WEEK_DATE 2026-W10-6+09:00
BASIC_ISO_DATE 20260307+0900
RFC_1123_DATE_TIME Sat, 7 Mar 2026 14:05:09 +0900

オフセットを持つ値を渡すと、ISO_DATE や BASIC_ISO_DATE にもオフセットが付きます。日付だけがほしいときは、LocalDate に変換してから整形するか、ISO_LOCAL_DATE を使います。

Locale に合わせた形式は ofLocalizedDate(FormatStyle)/ofLocalizedTime(FormatStyle) で作り、withLocale で言語を指定します。

FormatStyle ofLocalizedDate(JAPAN) ofLocalizedDate(US) ofLocalizedTime(JAPAN)
FULL 2026年3月7日土曜日 Saturday, March 7, 2026 14時05分09秒 日本標準時
LONG 2026年3月7日 March 7, 2026 14:05:09 JST
MEDIUM 2026/03/07 Mar 7, 2026 14:05:09
SHORT 2026/03/07 3/7/26 14:05

CLDR による曜日・午前午後・月名の表記の違い

JDK 9 から、Locale データの既定が CLDR(Unicode の共通ロケールデータ)になりました(JEP 252)。JEP 252 には、従来のロケールデータを優先するにはシステムプロパティ java.locale.providers に COMPAT(JRE の別名)を指定する、と書かれています。OpenJDK 21 で、既定のままと COMPAT 指定の両方を実行して比べました。

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

public class Cldr {
    public static void main(String[] args) {
        System.out.println("java.locale.providers = " + System.getProperty("java.locale.providers"));
        LocalDateTime t = LocalDateTime.of(2026, 9, 5, 14, 5, 9);   // 2026年9月5日(土)
        Locale[] locales = {Locale.JAPAN, Locale.US, Locale.UK, Locale.GERMANY};
        for (Locale l : locales) {
            String pattern = DateTimeFormatter.ofPattern("E / EEEE / a / MMM", l).format(t);
            String medium = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(l).format(t);
            // 見えない空白(U+202F、U+00A0)を見えるように置き換えて表示
            medium = medium.replace(" ", "<U+202F>").replace(" ", "<U+00A0>");
            System.out.println(l + " : " + pattern + " : " + medium);
        }
    }
}

既定(CLDR)での実行結果:

java.locale.providers = null
ja_JP : 土 / 土曜日 / 午後 / 9月 : 2026/09/05 14:05:09
en_US : Sat / Saturday / PM / Sep : Sep 5, 2026, 2:05:09<U+202F>PM
en_GB : Sat / Saturday / pm / Sept : 5 Sept 2026, 14:05:09
de_DE : Sa. / Samstag / PM / Sept. : 05.09.2026, 14:05:09

java -Djava.locale.providers=COMPAT,CLDR Cldr.java での実行結果:

java.locale.providers = COMPAT,CLDR
Oct 03, 2026 11:48:34 PM sun.util.locale.provider.LocaleProviderAdapter <clinit>
WARNING: COMPAT locale provider will be removed in a future release
ja_JP : 土 / 土曜日 / 午後 / 9 : 2026/09/05 14:05:09
en_US : Sat / Saturday / PM / Sep : Sep 5, 2026 2:05:09 PM
en_GB : Sat / Saturday / PM / Sep : 05-Sep-2026 14:05:09
de_DE : Sa / Samstag / PM / Sep : 05.09.2026 14:05:09
Locale 項目 CLDR(既定) COMPAT
ja_JP MMM 9月 9
en_GB a pm PM
en_GB MMM Sept Sep
de_DE E / MMM Sa. / Sept. Sa / Sep
en_US MEDIUM の日時 Sep 5, 2026, 2:05:09+U+202F+PM Sep 5, 2026 2:05:09 PM

日本語の曜日(土/土曜日)と午前午後(午後)は、どちらでも同じ出力でした。差が出やすいのは英語圏・ドイツ語圏の省略形と、ofLocalized... の形式です。en_US の時刻と PM の間は、CLDR では通常の空白ではなく U+202F(幅の狭い改行しない空白)でした。この出力を別の環境で解析したり、文字列として比較したりするときは、Locale に依存しない ofPattern か ISO の定数で受け渡すと、データの版による差の影響を受けません。COMPAT を指定した実行では「COMPAT locale provider will be removed in a future release」という警告も表示されています。

よくある質問

Q. yyyy と uuuu はどちらを使えばよいですか? A. 西暦だけを扱うなら uuuu が扱いやすいです。yyyy でも既定(SMART)では同じ結果になりますが、STRICT と組み合わせると紀元が必要になり、今回の5番のように DateTimeParseException になります。

Q. DateTimeFormatter は static で共有してよいですか? A. 共有できます。公式Javadoc に「This class is immutable and thread-safe.」と書かれています。withLocale や withResolverStyle は、元を変えずに新しいフォーマッタを返します。

Q. ミリ秒まで出すにはどう書きますか? A. HH:mm:ss.SSS と書きます(14:05:09.123 と出力されます)。S は秒の小数部で、SSSSSS でマイクロ秒、SSSSSSSSS でナノ秒まで出せます。

Q. 曜日が英語で出ます。日本語にするには? A. DateTimeFormatter.ofPattern("E", Locale.JAPAN) のように Locale を指定します。指定しない場合は実行環境の既定の Locale が使われるため、環境によって出力が変わります。

まとめ

  • format で文字列へ、型に合った parse で日付へ。フォーマッタは不変なので定数で共有できる
  • 年は uuuu、月は MM、日は dd、24時間制は HH、分は mm、秒は ss、ミリ秒は SSS
  • 文字数で桁そろえ・短い形・長い形が決まる。1桁も2桁も読むなら M/d
  • オフセットは XXX(+09:00)、ゾーンIDは VV、和暦は G と JapaneseDate
  • DateTimeParseException は「at index N」「Unable to obtain」「Invalid value」「unparsed text」の4つの形で原因を切り分けられる
  • 存在しない日付を止めたいときは uuuu と ResolverStyle.STRICT
  • 曜日・月名・午前午後は Locale とロケールデータ(CLDR)で変わるので、受け渡しには ISO 形式を使う

参考・出典

  • Java SE 21 API ドキュメント「DateTimeFormatter」(パターン文字、文字数のルール、定義済みフォーマッタ、ResolverStyle の既定) https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/time/format/DateTimeFormatter.html
  • JEP 252: Use CLDR Locale Data by Default https://openjdk.org/jeps/252

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Java DateTimeFormatterパターン一覧|日付と文字列の変換」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?