java.time.format.DateTimeParseException: Text '2026/10/10' could not be parsed at index 4 は、日付の文字列が、指定した(または既定の)形式と合わないときのエラーです。 メッセージの後ろの部分で、原因の種類が分かります。

メッセージの後ろ 意味 よくある原因
could not be parsed at index N N 文字目(0 から数える)で形式と合わなくなった 区切り文字の違い、T の有無、桁数の違い、全角数字・空白
unparsed text found at index N N 文字目以降に、余計な文字が残った 時刻付きを LocalDate で読んだ、Z やオフセット付き、末尾の改行
Invalid date 'FEBRUARY 30' 形式は合っているが、存在しない日付 2月30日、4月31日
Invalid value for ClockHourOfAmPm (valid values 1 - 12): 14 値が範囲の外 HH(0〜23時)のつもりで hh(1〜12時)と書いた
Unable to obtain LocalDate from TemporalAccessor 読めた項目から日付を組み立てられない yyyy と STRICT の組み合わせ

確認環境:OpenJDK 21.0.10 と 8(確認日 2026年10月10日)。以下の結果はすべて実際に実行して確かめました。Java 8 と結果が違ったものは、表の中で示しています。

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

(記載例)出典:株式会社RJC「DateTimeParseExceptionの原因と直し方|Java日付の解析」

「at index N」の読み方

N は、0 から数えて何文字目で読めなくなったかです。

LocalDate.parse("2026/10/10")
→ ... could not be parsed at index 4

  2 0 2 6 / 1 0 / 1 0
  0 1 2 3 4
          ↑ 4文字目の「/」で止まった
            (既定の形式は「-」区切り)

DateTimeParseException の getErrorIndex() でも、同じ位置(4)が取れました。ログに出すときは、getParsedString()(元の文字列)と一緒に出すと原因が分かります。

再現:よくある失敗と直し方

既定の形式(ISO)と違う

LocalDate.parse(文字列) のように形式を指定しないと、2026-10-10(ISO の形式)しか読めません。

書き方 結果 直し方
LocalDate.parse("2026/10/10") at index 4 ofPattern("uuuu/MM/dd") を指定
LocalDate.parse("2026-1-5") at index 5(月が1桁) ofPattern("uuuu-M-d")
LocalDateTime.parse("2026-10-10 09:30:00") at index 10(T ではなく空白) ofPattern("uuuu-MM-dd HH:mm:ss")
LocalDateTime.parse("2026-10-10") at index 10(時刻が無い) LocalDate.parse(...) で読み、.atStartOfDay()
LocalDate.parse("2026-10-10T09:30:00") unparsed text found at index 10 LocalDateTime.parse(...) で読み、.toLocalDate()

ISO の日時は、日付と時刻の間が T です(2026-10-10T09:30:00)。DB や画面の 2026-10-10 09:30:00(空白区切り)は、形式を指定して読みます。

MM と M:桁数が決まっているか

パターン 2026/10/10 2026/1/5
yyyy/MM/dd 読める at index 5(2桁を期待)
yyyy/M/d 読める 読める

M・d(1文字)は、1桁でも2桁でも読めます。 入力が 1/5 と 01/05 のどちらもありうるなら、1文字で書きます。

落とし穴:2月30日が、エラーにならずに2月28日になる

DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy/MM/dd");
LocalDate.parse("2026/02/30", f);   // → 2026-02-28(エラーにならない)
LocalDate.parse("2026/02/31", f);   // → 2026-02-28
LocalDate.parse("2026/02/32", f);   // → Invalid value for DayOfMonth (valid values 1 - 28/31): 32

ofPattern で作った形式は、既定で SMART という解釈のしかたになり、「その月の最終日を超える日」は最終日に直されます(Java の公式ドキュメント)。入力チェックで使うと、存在しない日付が通ってしまいます。

一方、形式を指定しない LocalDate.parse("2026-02-30") は Invalid date 'FEBRUARY 30' でエラーになりました。

STRICT にすると、yyyy で読めなくなる

厳密にしようとして .withResolverStyle(ResolverStyle.STRICT) を付けると、今度は正しい日付まで読めなくなりました。

ofPattern("yyyy/MM/dd").withResolverStyle(STRICT)  "2026/10/10"
→ Unable to obtain LocalDate from TemporalAccessor: {DayOfMonth=10, MonthOfYear=10, YearOfEra=2026},ISO ...

y は「紀元の中の年(year-of-era)」、u は「年」です。STRICT では、紀元(西暦か紀元前か)が無いと y から年を決められません。STRICT と組み合わせるときは uuuu を使います。

パターン 解釈 2026/10/10 2026/02/30 2028/02/29
yyyy/MM/dd SMART(既定) 読める 2026-02-28 になる 読める
yyyy/MM/dd STRICT エラー(TemporalAccessor) エラー エラー
uuuu/MM/dd STRICT 読める Invalid date 'FEBRUARY 30' 読める(うるう年)

入力チェックに使うなら uuuu + STRICT です。

static final DateTimeFormatter YMD =
        DateTimeFormatter.ofPattern("uuuu/M/d").withResolverStyle(ResolverStyle.STRICT);

hh と HH

ofPattern("uuuu-MM-dd hh:mm")  "2026-10-10 14:30"
→ Invalid value for ClockHourOfAmPm (valid values 1 - 12): 14

hh は午前・午後の12時間制(1〜12)、HH は24時間制(0〜23)です。HH にすると 2026-10-10T14:30 と読めました。

Z・オフセット付きの文字列(API の日時)

書き方 Java 21 Java 8
LocalDateTime.parse("2026-10-10T09:30:00Z") unparsed text found at index 19 同じ
OffsetDateTime.parse("2026-10-10T09:30:00Z") 読める(2026-10-10T09:30Z) 同じ
OffsetDateTime.parse("2026-10-10T09:30:00+0900")(コロンなし) unparsed text found at index 22 at index 19
Instant.parse("2026-10-10T09:30:00+09:00") 読める(2026-10-10T00:30:00Z) at index 19

Z や +09:00 が付いた文字列は OffsetDateTime(または Instant)で読みます。 コロンの無い +0900 は、パターンで XX を指定すると読めました。

OffsetDateTime.parse("2026-10-10T09:30:00+0900",
        DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXX"));   // 2026-10-10T09:30+09:00

Z を無視して読むと、9時間ずれる

LocalDateTime.parse("2026-10-10T09:30:00Z", DateTimeFormatter.ISO_DATE_TIME) は、エラーにならずに 2026-10-10T09:30 になりました。Z(UTC)の情報が捨てられ、日本時間なら 18:30 のはずが 09:30 のままです。

OffsetDateTime.parse("2026-10-10T09:30:00Z")
        .atZoneSameInstant(ZoneId.of("Asia/Tokyo"))
        .toLocalDateTime();                       // 2026-10-10T18:30

英語の月名とロケール

DateTimeFormatter f = DateTimeFormatter.ofPattern("dd MMM uuuu");
LocalDate.parse("10 Oct 2026", f);
実行環境のロケール 結果
英語(en_US) 読める
日本語(ja_JP) at index 3(Oct を月名として読めない)

MMM(月名)や E(曜日)は、実行環境の言語で読みます。 開発のパソコン(英語)では動き、日本語の環境で失敗する、ということが起きます。英語の文字列を読むなら、ロケールを固定します。

DateTimeFormatter.ofPattern("dd MMM uuuu", Locale.US)

HTTP のヘッダーなどの Sat, 10 Oct 2026 09:30:00 GMT は、用意されている DateTimeFormatter.RFC_1123_DATE_TIME で読めました。

和暦(令和8年10月10日)

static final DateTimeFormatter WAREKI = DateTimeFormatter.ofPattern("GGGGy年M月d日", Locale.JAPAN)
        .withChronology(JapaneseChronology.INSTANCE)
        .withResolverStyle(ResolverStyle.STRICT);

LocalDate.parse("令和8年10月10日", WAREKI);                     // 2026-10-10
LocalDate.parse("令和元年5月1日", WAREKI);                      // at index 2
LocalDate.parse("令和元年5月1日".replace("元年", "1年"), WAREKI); // 2019-05-01

「元年」はそのままでは読めません。 読む前に 1年 に置き換えます。和暦では G(元号)と組み合わせるので y を使います。

全角・空白・改行

入力 結果
"2026-10-10"(全角数字) at index 0
" 2026-10-10"(先頭に空白) at index 0
"2026-10-10\r"(末尾に改行) unparsed text found at index 10

画面の入力や CSV から読むときは、先にそろえます。

String norm = Normalizer.normalize(input, Normalizer.Form.NFKC).strip();   // 全角→半角、前後の空白・改行を除く
LocalDate.parse(norm, YMD);    // " 2026/10/10\r\n" → 2026-10-10

at index 0 で、見た目は正しいなら、全角・空白・目に見えない文字(BOM など)を疑います。

入力チェックの書き方

static Optional<LocalDate> parseDate(String input) {
    if (input == null) return Optional.empty();
    String s = Normalizer.normalize(input, Normalizer.Form.NFKC).strip();
    try {
        return Optional.of(LocalDate.parse(s, YMD));     // uuuu/M/d + STRICT
    } catch (DateTimeParseException e) {
        return Optional.empty();                         // 画面には「日付が正しくありません」
    }
}
入力 結果
2026/2/28 2026-02-28
2026/02/30 エラー(Invalid date 'FEBRUARY 30')
2026/13/1 エラー(Invalid value for MonthOfYear (valid values 1 - 12): 13)

確認の手順(チェックリスト)

順番 確認すること 方法
1 何文字目で止まったか at index N(0 から数える)
2 形式を指定しているか 指定なしは ISO(2026-10-10、T 区切り)だけ
3 型が合っているか 時刻付きは LocalDateTime、Z・+09:00 付きは OffsetDateTime
4 yyyy か uuuu か STRICT なら uuuu
5 2月30日が通ってしまわないか SMART(既定)は最終日に直す。入力チェックは STRICT
6 ロケール 月名・曜日は Locale.US などを指定
7 全角・空白・改行 NFKC と strip()

よくある質問

Q. SimpleDateFormat から移行したら、エラーが出るようになりました。 A. java.time は、形式と合わない文字列を厳しくエラーにします。上の表で、区切り・桁数・T・Z の違いを確認し、形式を指定します。

Q. yyyy と uuuu は、どちらを使えばよいですか。 A. 西暦の日付なら uuuu を使うと、STRICT と組み合わせても問題が起きません。和暦(元号の G と組み合わせる)では y を使います。

まとめ

  • at index N は、0 から数えた N 文字目で止まったという意味
  • 形式を指定しないと ISO だけ。空白区切りの日時は形式を指定する
  • ofPattern は既定で SMART。2月30日が2月28日になる。入力チェックは uuuu + STRICT
  • Z・オフセット付きは OffsetDateTime。LocalDateTime で読むと時差が捨てられる
  • 月名・曜日はロケールで変わる。Locale.US を指定する
  • 和暦の「元年」は 1年 に置き換える。全角・空白は NFKC と strip() でそろえる

参考・出典

確認日はいずれも 2026年10月10日です。

  • Java SE 21 API「DateTimeFormatter」:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/time/format/DateTimeFormatter.html
  • Java SE 21 API「ResolverStyle」:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/time/format/ResolverStyle.html

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

(記載例)出典:株式会社RJC「DateTimeParseExceptionの原因と直し方|Java日付の解析」

株式会社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で一緒に開発しながら、 成長を楽しみませんか?