良い子のみんなは DateFormat.getInstance().parse("2012/07/08") なんてコードは書かないようにしようね。僕との約束だ…!(吐血)
— yosio++ (@yosiopp) July 7, 2012
いやもう説明するまでもないかもしれませんが、今日はDateFormatについて。
上述のコードの何がいけないのか。
try{
Date d = DateFormat.getDateInstance().parse("2012/07/08");
System.out.println(d.toString());
}catch(Exception e){
e.printStackTrace();
}
実行すると、以下の結果が得られます。
Sun Jul 08 00:00:00 JST 2012
うん。正しく動いている気がします。
では、これではどうでしょうか。
Locale.setDefault(Locale.US);
try{
Date d = DateFormat.getDateInstance().parse("2012/07/08");
System.out.println(d.toString());
}catch(Exception e){
e.printStackTrace();
}
java.text.ParseException: Unparseable date: “2012/07/08”
at java.text.DateFormat.parse(DateFormat.java:337)
at net.yosiopp.test.DateFormatTest.main(DateFormatTest.java:39)
ただちに動かなくなってしまいました。
違いは見ての通り Locale.setDefault(Locale.US);
ですね。
何が言いたいかというと、
DateFormat.getDateInstance() で得られるDateFormatインスタンスのparseはロケールに依存するということです。
なので、意図的にロケールの変化に対応したい場合を除いて、
ロケールが変化しうる環境下では、DateFormat.getDateInstance() は使わない方が良いでしょう。
# たとえば、windows上では正しく動いたけど、サーバに置いてcronから動かしたら、動かないよ…!とかあり得る
ではどうすれば良いのか。とりあえず普通にSimpleDateFormatを使いましょう。
Locale.setDefault(Locale.US);
try{
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
Date d = dateFormat.parse("2012/07/08");
System.out.println(d.toString());
}catch(Exception e){
e.printStackTrace();
}
これならロケールに依存しないので安心です。
※ SimpleDateFormatはスレッドセーフではないので、マルチスレッド環境下で使いたい場合は synchronized するなり工夫してください。
SimpleDateFormatのスレッドセーフなにがしについての話は、ここら辺が参考になりました。