今日もプログラミング

IT技術とかプログラミングのこととか特にJavaを中心に書いていきます

Excelの1900/2/29をPOIで取得してみる

1900年は閏年ではない。

しかし、Excelのバグで1900/2/29という日付を設定できてしまう。

 

これをJavaからPOIで取得するとどうなるか?を試してみた。

 

ほんとうはExcelファイルを作って、POIで読み込んで…、とするべきなんだろうけど、面倒なのでPOIのDataUtil.getJavaDateに直接シリアル値を渡してみる。

 

Excelでは、1900/2/29のシリアル値は60。

その前後の値をDateで表示してみる。

 

DateFormat format = new SimpleDateFormat("yyyy/MM/dd");
System.out.println(format.format(DateUtil.getJavaDate(59)));
System.out.println(format.format(DateUtil.getJavaDate(60)));
System.out.println(format.format(DateUtil.getJavaDate(61)));

 

結果は、

1900/02/28
1900/03/01
1900/03/01

で、1900/2/29は1900/3/1になるようだ。

 

POIのソースを見ると、org.apache.poi.ss.usermodel.DateUtil#setCalendarに以下のようなコードがあった。

 

int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it isn't
… if (wholeDays < 61) {
    // Date is prior to 3/1/1900, so adjust because Excel thinks 2/29/1900 exists
    // If Excel date == 2/29/1900, will become 3/1/1900 in Java representation
    dayAdjust = 0;
}

なるほど。60と61の間で分岐している。

気になってOpenOfficeでも試してみたところ、「1900/2/29」は日付として認識されなかった。Excelとの比較は下の通り。

シリアル値OpenOfficeExcel
59 1900/2/27 1900/2/28
60 1900/2/28 1900/2/29
61 1900/3/1 1900/3/1

 

 互換製品を作るとき、バグもそのまま移植するかどうかは、悩むところだろうなあ。

 

POI : 3.11

OpenOffice: 4.1.1