※当サイトはアフィリエイト広告を利用しています

DateTimeFormatterを使用して日付文字列をLocalDateTimeに変換する方法

2021年7月9日IT

ケース1:失敗例("20200229T0925″のような日付文字列を変換したい)

// ISO 8601フォーマットから区切り文字を削除した日付文字列
String dateStr1  = "20200229T0925";
// LocalDateTimeのparseでLocalDateTimeに変換できるのでは?
LocalDateTime date = LocalDateTime.parse(dateStr1);
System.out.println(date);

上記コードの実行結果は
「java.time.format.DateTimeParseException: Text '20200229T0925’ could not be parsed at index 0」
という例外がスローされます。
LocalDateTime.parseメソッドの中で使用されているDateTimeFormatterは「ISO_LOCAL_DATE_TIME」なので「yyyy-MM-ddThh:mm:ss」形式以外の日付文字列は LocalDateTime に変換できません。

ケース1:成功例("20200229T0925″のような日付文字列を変換したい)

// ISO 8601フォーマットから区切り文字を削除した日付文字列
String dateStr1  = "20200229T0925";
// DateTimeFormatter.ofPatternでカスタムパターンを設定
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmm[ss]");
// parseする時のフォーマッターを上記で作成したDateTimeFormatter にする
LocalDateTime date = LocalDateTime.parse(dateStr1,formatter);
System.out.println(date);

上記コードの動作結果は「2020-02-29T09:25」
日付 文字列がLocalDateTimeに変換され、出力されます。

DateTimeFormatter.ofPatternの引数について解説しておきます。
yyyyは西暦
MMは月
ddは日
'T’はただの文字。パターン内に特殊な意味を持たない文字を埋め込むためにはシングルクォーテーションで囲えばよさそう
HHは時間
mmは分。
[ss]は秒。 []で囲うとあってもなくても動作する。 日付文字列に秒まで記載されているケースにも対応するために付けている。

今回作成したformatterでは
「20200229T0925」のような【年月日T時分】日付文字列
「20200229T092513」のような【年月日T時分秒】日付文字列を変換できます。

ケース2:失敗例(日付文字列に複数パターンあり)

変換したい日付文字列に複数のパターンがある場合を想定します。
【年月日T時分】「yyyyMMddThhmm」
【年月日t時分秒】 「yyyyMMddthhmmss」
【年月日T時】 「yyyyMMddThh」
先程のformatterで変換できる実験します。

String dateStr1 = "20200229T0925";
String dateStr2 = "20200229t092512";
String dateStr3 = "20200229T09";

// DateTimeFormatter.ofPatternでカスタムパターンを設定
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmm[ss]");

/ parseする時のフォーマッターを上記で作成したDateTimeFormatter にする
LocalDateTime date1 = LocalDateTime.parse(dateStr1, formatter);
LocalDateTime date2 = LocalDateTime.parse(dateStr2, formatter);
LocalDateTime date3 = LocalDateTime.parse(dateStr3, formatter);
System.out.println(date1);
System.out.println(date2);
System.out.println(date3);

日付文字列に含まれる小文字のtなどには対応していないため、
例外がスローされます。

ケース2:成功例(日付文字列に複数パターンあり)

String dateStr1 = "20200229T0925";
String dateStr2 = "20200229t092512";
String dateStr3 = "20200229T09";

// DateTimeFormatterBuilderでフォーマッターを作成する
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
        .appendOptional(DateTimeFormatter.ofPattern("yyyyMMdd'T'HH[mm][ss]"))
        .appendOptional(DateTimeFormatter.ofPattern("yyyyMMdd't'HH[mm][ss]"))
        .toFormatter();
// parseする時のフォーマッターを上記で作成したDateTimeFormatter にする
LocalDateTime date1 = LocalDateTime.parse(dateStr1, formatter);
LocalDateTime date2 = LocalDateTime.parse(dateStr2, formatter);
LocalDateTime date3 = LocalDateTime.parse(dateStr3, formatter);
System.out.println(date1);
System.out.println(date2);
System.out.println(date3);

上記コードで変換できます。

DateTimeFormatterBuilderについて解説していきます。
名前の通り DateTimeFormatter を作成するクラスです。
.appendOptional(DateTimeFormatter hoge))
で複数のパターンをフォーマッターに追加できます。
似たようなメソッドに.append( DateTimeFormatter hoge )がありますが、
これだと機能しません。
appendOptionalは登録パターンのいずれかに合致すれば変換します。
appendは登録パターン全てに合致しないと変換しません。
appendOptional を使用しましょう。
appendOptional を使用して複数パターンを登録したら
.toFormatter()でフォーマッターに変換します。

ケース3:25時のような特殊日時の対応

TV番組表で見かける25時みたいな表記があります。
日付文字列「2011-12-03T25:15:30」を日付に変更する場合、
2011/12/04 01:15:30」という日付に変換したいわけです。

String dateStr1 = "2011-12-03T25:15:30";
// DateTimeFormatterBuilderでフォーマッターを作成する
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME
        .withResolverStyle(ResolverStyle.LENIENT);
// parseする時のフォーマッターを上記で作成したDateTimeFormatter にする
LocalDateTime date1 = LocalDateTime.parse(dateStr1, formatter);
System.out.println(date1);

上記コードの動作結果は「2011-12-04T01:15:30」です。
無事、特殊日時を変更できました。

DateTimeFormatterの作成時に
.withResolverStyle(ResolverStyle.LENIENT);
ResolverStyle を変更しています。
ResolverStyle を LENIENT に変更することで、
32日や25時などの特殊日時をいい感じに変更してくれるようになります。
デフォルトだと ResolverStyle.SMART になるみたいです。
特殊日時 に対応したい場合、
ResolverStyle.LENIENT を使用してください。

2021年7月9日IT

Posted by raishin