- JAVA
Java DateTimeFormatterパターン一覧|日付と文字列の変換
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期連続の黒字決算。