プログラマメモ2 - programmer no memo2

シリアル値の計算、その2 エクセル - java POI頼み 2014/02/15

エクセルで使われるシリアル値の計算についてです。
と、実は、自前で計算しようとすると、とても面倒な気が....

これ素直に、ライブラリまかせのほういいと思う。
「下手に手出すと帰ってこれない」いつものパターン



poiに渡すまえに計算して、渡すのではなく、Dateかカレンダーにして渡すのがよいと思う。自前で、計算すると、正しいかどうか、ちょっと検証するのつらそうなのと、実績あるpoiのほうが、3.8888倍(当社比)信頼性が高いと思うのであった。

HSSFCellに実装みると、シリアル値にしてから設定しているのがわかる。
3.10-finalのコード参照

public void setCellValue(Calendar value) { setCellValue( HSSFDateUtil.getExcelDate(value, _book.getWorkbook().isUsing1904DateWindowing()) ); }

public void setCellValue(Date value) { setCellValue(HSSFDateUtil.getExcelDate(value, _book.getWorkbook().isUsing1904DateWindowing())); }

使うエクセルの設定によっては、1900 年日付システムと 1904 年日付システムを区別する必要があるのが上記のコードからもみてとれる。自前で、算出する場合、これも考慮しないといけないので、素直にpoiまかせで。

お試しとして、シリアル値が必要なら、HSSFDateUtilを使うのよいと思う。

変換自体のロジックはorg.apache.poi.ss.usermodel.DateUtilあるようです。
以下、poiのソースコードから
org.apache.poi.ss.usermodel.DateUtil
private static double internalGetExcelDate(Calendar date, boolean use1904windowing) { if ((!use1904windowing && date.get(Calendar.YEAR) < 1900) || (use1904windowing && date.get(Calendar.YEAR) < 1904)) { return BAD_DATE; } // Because of daylight time saving we cannot use // date.getTime() - calStart.getTimeInMillis() // as the difference in milliseconds between 00:00 and 04:00 // can be 3, 4 or 5 hours but Excel expects it to always // be 4 hours. // E.g. 2004-03-28 04:00 CEST - 2004-03-28 00:00 CET is 3 hours // and 2004-10-31 04:00 CET - 2004-10-31 00:00 CEST is 5 hours double fraction = (((date.get(Calendar.HOUR_OF_DAY) * 60 + date.get(Calendar.MINUTE) ) * 60 + date.get(Calendar.SECOND) ) * 1000 + date.get(Calendar.MILLISECOND) ) / ( double ) DAY_MILLISECONDS; Calendar calStart = dayStart(date); double value = fraction + absoluteDay(calStart, use1904windowing); if (!use1904windowing && value >= 60) { value++; } else if (use1904windowing) { value--; } return value; }

: