2008-02-29 (Fri) [長年日記]

_ Javaのうるう年のバグ? はてなブックマークに追加 del.icio.usに追加 MM/Memoに追加

会社で commons ftpclient を使っているシステムがありまして、 こいつが今日動かなくなってたんです。

で、調べたら、commons ftpclient のバグらしく、 こんなパッチを見つけました。

<URL:http://svn.apache.org/viewvc?view=rev&revision=631284>

FTP でファイルのリストを取得したときに、

Feb 29

みたいなタイムスタンプ文字列が返ってくる訳ですが、 こいつをうまくパースできずにエラーしていたらしい。

Feb 28

はパースできるのに

Feb 29

がパースできないってどういうことだ?と不思議になり、 ちょっと追試してみましたが、結局のところこれは SimpleDateFormat のバグ(仕様?)ってことに なるのかなぁ?

SimpleDateFormat sdf = new SimpleDateFormat("M d");
sdf.setLenient(false);
Date date = sdf.parse("2 28");
System.out.println(date.toString());

このコードだと、

// => Sat Feb 28 00:00:00 JST 1970

という文字列が返って来て(1970年ってのはどうなんだ?という のはさておき)問題ありません。

しかし、うるう日である 2/29 をパースしようと 以下のようなコードに変えた途端に、

SimpleDateFormat sdf = new SimpleDateFormat("M d");
sdf.setLenient(false);
Date date = sdf.parse("2 29");
System.out.println(date.toString());

ParseException ですよ。

ちなみに、Format を "y M d" などにして、

parse("2008 2 29")

だと、例外は上がってこないみたいです。

1970年2月29日って日付を作ろうとして、1970年は 閏年じゃないから、この日付は間違いだねー、ってことで 例外をあげてるんじゃないかと思いますが、、、

これを使って、日付を作ろうとすると、いちいち自分で 「今日の日付を求めてー、年の部分だけ取り出してー、 パースしたい文字列に年をくっつけてー」というお膳立てを してあげないと、意図通りの日付を作ってくれないわけです。

非常に使いにくすぎですね。

Java をお使いの方は気をつけてください。

ちなみに、Ruby だと、「今年の」2/29 としてオブジェクトを 作ってくれるので、こんな問題は起きません。 しかも、フォーマットの指定とかしなくても空気を読んで、 なんとなくパースしてくれますし。

Rubyのtime.rbは、ものすごく空気の読める子。

$ irb
>> require 'time'
=> true
>> Time.parse("Feb 29")
=> Fri Feb 29 00:00:00 +0900 2008

と、いうわけで(?)。

JavaからRubyへ JavaからRubyへ

関連記事

Permalink | このエントリを含むはてなブックマーク | このエントリをはてなブックマークに追加 | このエントリを含むMM/Memo | このエントリをMM/Memoに追加 | このエントリを含むdel.icio.us | このエントリをdel.icio.usに追加 | Tags: java
[]