LoginSignup
93
100

More than 5 years have passed since last update.

Javaで新元号に対応する

Last updated at Posted at 2016-07-13

新元号に対応したjdkは今後リリースされるはずだけど、そんな簡単にアップデートできない方(自分含む)に。

前提

  • Oracle JDK 8u92
  • $JAVA_HOME設定済み
  • 諸々文字コードはutf-8

確認用コード

JapaneseEra.java
import java.text.*;
import java.util.*;

public class JapaneseEra {
  public static void main(String[] args) throws ParseException {
    DateFormat df = new SimpleDateFormat("GGGGy年M月d日", new Locale("ja", "JP", "JP"));
    System.out.println(df.format(new Date(System.currentTimeMillis())));
    System.out.println(df.parse("平成28年7月14日"));
    df.setLenient(false);
    System.out.println(df.parse("平成28年7月14日"));
  }
}

対応前に実行すると、

$ javac JapaneseEra.java; java JapaneseEra
平成28年7月14日
Thu Jul 14 00:00:00 JST 2016
Thu Jul 14 00:00:00 JST 2016

まあそうですね、と。

新元号に対応する

仮に

  • 新元号は「機板」
  • 2014/03/15 09:00:00+0900から

その1. 新元号の開始日時をエポックミリ秒にする

1394841600000。
「unix timestamp」なんかでググるか、java.util.Date#getTime()なんかでも変換できるはず。

その2. 新元号をUnicodeに変換する

$ echo "機板" | native2ascii
\u6a5f\u677f

その3. $JAVA_HOME/jre/lib/calendars.properties を編集

calendar.japanese.erasに平成までの定義があるから、そこに新元号を追加。

  • nameはその2.のUnicode
  • abbrは略称
  • sinceはその1.のエポックミリ秒 編集前後のdiffは
        name=Meiji,abbr=M,since=-3218832000000;  \
        name=Taisho,abbr=T,since=-1812153600000; \
        name=Showa,abbr=S,since=-1357603200000;  \
   -    name=Heisei,abbr=H,since=600220800000
   +    name=Heisei,abbr=H,since=600220800000; \
   +    name=\u6a5f\u677f,abbr=K,since=1394841600000

    #
    # Taiwanese calendar

その4. 確認用コードを再実行する

$ javac JapaneseEra.java; java JapaneseEra
機板3年7月14日
Thu Jul 14 00:00:00 JST 2016
Exception in thread "main" java.text.ParseException: Unparseable date: "平成28年7月14日"
    at java.text.DateFormat.parse(DateFormat.java:366)
    at JapaneseEra.main(JapaneseEra.java:10)
  • 現在のエポックミリ秒は新元号でフォーマットされる
  • 平成28年は存在しない(ことになった)から、不正な日付を厳密にチェックするとこける

その他

  • Java6でも同じ方法で大丈夫
  • Tomcat等起動中のプロセスに反映するのは再起動が必要だった気がする
  • 文字化けする場合はnative2asciiの時に-encodingつけるとか

追記

確認用コードでは元号の妥当性を確認するのにDateFormat#setLenient(false)ってしてるけど、つまり今の元号で書かれた未来の日付は改元後にパースできなくなる可能性がある。
パース対象によって厳密なチェックが必要か、あるいはDateFormat#setLenient(false)で可能かどうか要件に応じて決める必要がある。

93
100
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
93
100