初めに
2021年現在でも「Java 日付 文字列」などで検索するといまだにDate
とSimpleDateFormat
が上位に出てくるので、java.time
時代の参照すべきドキュメントと概要を備忘録として残す。
検証はOpenJDK11を使用していており、Oracleドキュメントのリンク先はJava17になっているが、基本的にはJava8から使えるはず。
日時オブジェクト
本記事ではJava8から導入されたjava.time
パッケージのオブジェクトで日時を保持する。
LocalDateTime now = LocalDateTime.now(); // 現在日時
LocalDateTime ldt = LocalDateTime.of(2021, 12, 10, 20, 30, 0); // 指定した日時
文字列に変換
toString
日時オブジェクトのtoString
メソッドを使用するとISO-8601暦体系になる。
LocalDateTime ldt1 = LocalDateTime.of(1999, 1, 1, 0, 0, 0);
System.out.println(ldt1); // -> "1999-01-01T00:00" ※秒が0の場合は省略される
LocalDateTime ldt2 = LocalDateTime.of(2021, 12, 31, 23, 59, 59);
System.out.println(ldt2); // -> "2021-12-31T23:59:59"
LocalDateTime ldt3 = LocalDateTime.of(2021, 12, 31, 23, 59, 59, 1200);
// 7つ目の引数はナノ秒
System.out.println(ldt3); // -> "2021-12-31T23:59:59.000001200"
DateTimeFormatter
または、Java11の日本語ドキュメント/Java8の日本語ドキュメント
従来のSimpleDateFormat
ライクな指定をしたい場合はDateTimeFormatter
を使用する。
SimpleDateFormat
同様シンボル文字を表示桁数分重ねる形式をとる。
DateTimeFormatter year2fmtr = DateTimeFormatter.ofPattern("yy");
System.out.println(ldt1.format(year2fmtr)); // -> "99"
System.out.println(ldt2.format(year2fmtr)); // -> "21"
DateTimeFormatter year4fmtr = DateTimeFormatter.ofPattern("yyyy");
System.out.println(ldt1.format(year4fmtr)); // -> "1999"
System.out.println(ldt2.format(year4fmtr)); // -> "2021"
// DateTimeFormatterでは月は大文字でM
DateTimeFormatter month1fmtr = DateTimeFormatter.ofPattern("M");
System.out.println(ldt1.format(month1fmtr)); // -> "1"
System.out.println(ldt2.format(month1fmtr)); // -> "12"
DateTimeFormatter month2fmtr = DateTimeFormatter.ofPattern("MM");
System.out.println(ldt1.format(month2fmtr)); // -> "01"
System.out.println(ldt2.format(month2fmtr)); // -> "12"
// ※実行環境のロケールは日本
DateTimeFormatter month3fmtr = DateTimeFormatter.ofPattern("MMM");
System.out.println(ldt1.format(month3fmtr)); // -> "1月"
System.out.println(ldt2.format(month3fmtr)); // -> "12月"
事前定義されているフォーマッタを使用することも可能。
System.out.println(ldt2.format(DateTimeFormatter.ISO_DATE)); // -> "2021-12-31"
String.format
または、Java11の日本語ドキュメント/Java8の日本語ドキュメント
String.format
の日付にはTemporalAccessor
に適用することが可能。
// Formatterでは月は小文字でm
// "m","d"一文字で2桁表示を示す
System.out.println(String.format("test_%1$tY-%1$tm-%1$td.log", ldt2)); // -> "test_2021-12-31.log"
書式はDateTimeFormatterより複雑で%<インデックス>$t<パターン>
で1セット。
オブジェクトと値をはめ込む位置が1:1の場合はとインデックス部分(<インデックス>$
)は不要だが、大抵は1つの日時オブジェクトに対して年・月など2つ以上の位置にはめ込むので実質的にほぼ必須。
// OK
System.out.println(String.format("test_%tY.log", ldt2)); // -> "test_2021.log"
// NG
System.out.println(String.format("test_%tY-%tm-%td.log", ldt2));
// -> java.util.MissingFormatArgumentException: Format specifier '%tm'
注意点
String.format
は一般的に計算コストが高いので性能にシビアな環境や大量にループする中で使う場合は要注意。
※Java17で幾分改善されたらしい。