Javaの新元号対応を試す。そして実用には問題がある。

元号対応はNewEraという仮の元号で対応が進んでいるので、試してみました。
おそらく、実用では使えない場面がある仕様になっています。
なので、元号対応が必要そうな人は、早めに試して声をあげる必要があると思います。

ビルドする

※ 2018/6/16追記 ea18が出ているのでそのまま試せます
Masterブランチに取り込まれているので、明日あたりにでてくるea18で使えるようになると思いますが、いまは自分でビルドする必要があります。
ビルドについては、こちらを参考にしてください。ここに書いてるのとは違って、リポジトリhttp://hg.openjdk.java.net/jdk/jdkです。
http://d.hatena.ne.jp/nowokay/20171104#1509753358

使ってみる

JShellで使ってみます。

jdk $build/macosx-x86_64-normal-server-release/images/jdk/bin/jshell 
|  JShellへようこそ -- バージョン11-internal
|  概要については、次を入力してください: /help intro

jshell> import java.time.chrono.*

jshell> JapaneseDate.of(2018, 6, 14)
$2 ==> Japanese Heisei 30-06-14

jshell> JapaneseDate.of(2020, 6, 14)
$3 ==> Japanese NewEra 2-06-14


2020年の元号はNewEraになりました!
いまのところJapaneseEra.NEWERAは現時点ではprivateなので、直接使うことはできません。

問題点

たとえばぼくの免許の有効期限は平成32年3月までです。
これを扱おうとするとどうなるでしょうか?

jshell> JapaneseDate.of(JapaneseEra.HEISEI, 32, 3, 10)
|  Exception java.time.DateTimeException: year, month, and day not valid for Era
|        at JapaneseDate.of (JapaneseDate.java:231)
|        at (#8:1)


例外が発生します。これでは、ぼくの免許の有効期限はJavaでは扱えないことになりますね。現状で平成が続くことを前提とした2019年以降を対象とする文書はたくさんあります。こういった文書に記載されている年月が扱えないのは、問題になることもあると思います。
政府は2019年5月1日以降も一定期間 平成を使い続けるシステムが残る方向で調整を進めていますが、このようなシステムでJavaが使えなくなります。
改元後も「平成」利用へ 納税や年金システム、混乱回避:朝日新聞デジタル
また、JDK10までは問題なく扱えていてもJDK11以降で扱えなくなるということもあります。


もうひとつ、保険証券など長期の期限をもつものを扱うサイトで、「来年2040年は平成52年が期限と記載されているお客様は満期となります」のような表示をしようと思ったとき、JapaneseDateではこの処理ができません。
from(JapaneseEra, LocalDate)のようなメソッドを追加して、元号を指定して変換ができる必要もあるのではないかと思います。


元号に関わる処理は日本向けシステムを作っている人にしか影響がないので、日本で声をあげないと改善はされません。元号を扱う可能性があるなら、動作を確認して声をあげていかないといけないと思います。


※ 7/4 追記
パースに関してはLENIENTをResolverStyleに設定することでHeisei 32をパースできます。
下部のコードは次のような出力になります。

java.time.format.DateTimeParseException:
  Text '平成 32-1-1' could not be parsed:
  Invalid YearOfEra for Era: Heisei 32
2020-01-01
import java.time.LocalDate;
import java.time.chrono.JapaneseChronology;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.ResolverStyle;
import java.util.Locale;

public class LenientEra {
    public static void main(String[] args) {
        var dtf = new DateTimeFormatterBuilder()
                .appendPattern("GGGG y-M-d")
                .toFormatter(Locale.JAPANESE)
                .withChronology(JapaneseChronology.INSTANCE);
        try {
            System.out.println(LocalDate.parse("平成 32-1-1", dtf));
            System.out.println("Wrong behavior");
        } catch (Exception ex) {
            System.out.println(ex);
        }
        System.out.println(LocalDate.parse("平成 32-1-1",
          dtf.withResolverStyle(ResolverStyle.LENIENT)));
    }
}