Date and Time APIでの和暦の扱いをちゃんと調べていなかったので、調べた。
なお、以下で用いるコードにおいては次のフォーマッタおよび、タイムゾーンを使った。
final ZoneId tokyo = ZoneId.of("Asia/Tokyo"); final DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendText(ChronoField.ERA) .appendText(ChronoField.YEAR_OF_ERA) .appendLiteral("年") .appendText(ChronoField.MONTH_OF_YEAR) .appendText(ChronoField.DAY_OF_MONTH) .appendLiteral("日") .toFormatter(Locale.JAPAN); final DateTimeFormatter iso = DateTimeFormatter.ISO_DATE;
1.和暦を扱う場合は以下のクラスを使う。
java.time.chrono.JapaneseDate
java.time.chrono.JapaneseEra
2.日付インスタンスの作り方
- 日付を指定する場合は
JapaneseDate#of(JapaneseEra, int, int, int)
あるいはJapaneseDate#of(int, int, int)
を使う。 - 現在時刻が欲しい場合は
JapaneseDate#now
またはJapaneseDate#now(ZoneId)
またはJapaneseDate#now(Clock)
を使う。 - 他の日付型から変換したい場合は
JapaneseDate#from(TemporalAccessor)
を使う。
というわけで、試してみましょう。まず、東京の今の日付が欲しい場合は次のようになります。
final JapaneseDate now = JapaneseDate.now(tokyo);
System.out.println(now.format(formatter));
結果
平成29年3月23日
昭和最後の日付近辺
final JapaneseDate showa = JapaneseDate.of(1989, 1, 7); System.out.println(showa.format(formatter)); final JapaneseDate heisei = JapaneseDate.of(1989, 1, 8); System.out.println(heisei.format(formatter));
結果
昭和64年1月7日 平成1年1月8日
明治は6年以前というのがないそうです
try { final JapaneseDate meiji = JapaneseDate.of(1872, 12, 31); System.out.println(meiji.format(formatter)); } catch (Exception e) { System.out.println(e.getClass().getCanonicalName()); System.out.println(e.getMessage()); System.out.println("1872/12/31"); }
結果
java.time.DateTimeException JapaneseDate before Meiji 6 is not supported 1872/12/31
というわけで、明治6年以前は出力されないので、 厳密 にJIS X 0301に対応している模様です。
同様に和暦を変換していきます。
final JapaneseDate h = JapaneseDate.of(平成, 29, 1, 1); System.out.println(h.format(iso)); final JapaneseDate m = JapaneseDate.of(明治, 6, 1, 1); System.out.println(m.format(iso)); try { JapaneseDate.of(明治, 5, 12, 31); } catch (Exception e) { System.out.println(e.getClass().getCanonicalName()); System.out.println(e.getMessage()); System.out.println("明治5年12月31日"); }
結果
2017-01-01 1873-01-01 java.time.DateTimeException JapaneseDate before Meiji 6 is not supported 明治5年12月31日
こちらも難しいことは特に必要なさそうです。
最後に別の型からの変換
final LocalDate ldm = LocalDate.of(1873, 1, 1); System.out.println(JapaneseDate.from(ldm).format(formatter)); try { final LocalDate ldk = LocalDate.of(1872, 12, 31); System.out.println(JapaneseDate.from(ldk).format(formatter)); } catch (Exception e) { System.out.println(e.getClass().getCanonicalName()); System.out.println(e.getMessage()); System.out.println("明治5年12月31日"); }
結果
明治6年1月1日 java.time.DateTimeException JapaneseDate before Meiji 6 is not supported 明治5年12月31日
最後に古の java.util.Date
からの変換ですが、かなり面倒です。もう java.util.Date
使うなと言いたくなるくらいです。
final Date date = new Date(); final Instant instant = date.toInstant(); final ZonedDateTime zonedDateTime = instant.atZone(tokyo); final JapaneseDate japaneseDate = JapaneseDate.from(zonedDateTime); System.out.println(japaneseDate.format(formatter));
結果
平成29年3月23日
API的には JapaneseDate.from(instant)
とやりたくなりますが、ゾーン情報を持たない Instant
は変換できません(。逆もまた然り)。まあ、日付の計算も面倒ですし、 java.util.Date
使うのやめましょう。
「java.util.Date
使うのやめましょう」と書くと、「これだからJava8の使えるサーバーの人間は…」と言われるので、紹介しておくと、これと同じAPIがAndroidでも使えます。threetenbpというプロジェクトがあって、そちらがターゲットバージョン1.6で同じAPI(パッケージは異なる)のものを提供しています。したがってJava8が使えない環境の方はそちらを使うとよいです。
また、ThreeTenABP(Three Ten Android Back Port)というプロジェクトもあるようですが、ソースを見たところクラスの数が異様に少ないので同じAPIが使えるかどうかわかりません。どうやらメモリおよび速さの関係からバイナリファイルの中にゾーンの情報をすべて入れているようなのですが、JapaneseEraとかどうやってるんだろうという印象を持ったりします。
(追記:2017/03/24 1:03)教えてもらいました。ThreeTenABPはThreeTenに依存しているので同じAPIを使えるようです。
おわり