2

我使用一个 xlsx 文件,其中包含DATE(year, month, day)一个单元格中的公式。此单元格被格式化为日期,因此 Excel/OpenOffice 显示正确的日期。例如,单元格内容会'=DATE(2013;1;1)'产生:'01.01.2013' 到目前为止 - 非常好。

使用 poi 库读取此文件时,我会:

XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream(new File("/home/detlef/temp/test.xlsx")));
XSSFSheet sheet = workbook.getSheet("Sheet A");
XSSFCell cell = sheet.getRow(0).getCell(0);
System.out.println(cell.getDateCellValue());

这将打印出:

Sun Dec 31 00:00:00 CET 1899

我正在使用 POI 3.9。

谁能告诉我为什么会这样?

找到了一种方法:

if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) {
   FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
   CellValue evaluate = evaluator.evaluate(cell);
   Date date = DateUtil.getJavaDate(evaluate.getNumberValue());
   System.out.println(date);
}

这会产生:

Tue Jan 01 00:00:00 CET 2013

不管怎么说,还是要谢谢你。

4

1 回答 1

4

您所描述的一切都是完全正确和预期的

当 Excel 将公式存储在单元格中时,它不仅存储公式本身(.xlsx 中的字符串,或 .xls 的已解析标记形式),它还存储该公式的最后评估答案。这意味着当 Excel 加载时,它不必花很长时间计算要显示的公式结果,它可以像任何其他单元格一样使用最后一个值呈现它们。

这就是为什么当您使用 Apache POI 更改您的 Excel 文件时,您需要运行评估以更新所有这些缓存的公式值,因此在您转到该单元格之前它在 Excel 中看起来正确

但是,Excel 中有一些特殊的公式函数,它们被定义为 volatile。这些函数每次总是返回不同的值,例如DATE,对于这些 Excel,只需将一个虚拟值(例如 0 或 -1)写入单元格,并在加载时重新评估它

当您在 POI 中读取公式单元格的数值时,它会返回缓存值。如果您希望 POI 评估公式,您需要要求它,就像您正在做的那样

Excel 中的日期存储为自 1900 年 1 月 1 日或 1904 年 1 月 1 日以来的小数天数(取决于标志)。-1 的值是 1899 年 12 月 31 日,所以当 Excel 写入 -1 并且您将其作为日期请求时,您会看到

于 2013-10-17T09:55:48.383 回答