From 50cfe3c10ed4dbee2d9b066d78e5fedf01921e4e Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Sun, 25 Apr 2021 17:16:05 +0000 Subject: [PATCH] [github-235] Fix date formatting for number cell values. Thanks to Anthony Schott. This close #235 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1889179 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/ss/tests/format/TestCellFormatPart.java | 11 +++++++++++ .../apache/poi/ss/format/CellDateFormatter.java | 14 +++++++++++--- .../spreadsheet/DateFormatNumberTests.xlsx | Bin 0 -> 10981 bytes 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 test-data/spreadsheet/DateFormatNumberTests.xlsx diff --git a/poi-ooxml/src/test/java/org/apache/poi/ss/tests/format/TestCellFormatPart.java b/poi-ooxml/src/test/java/org/apache/poi/ss/tests/format/TestCellFormatPart.java index 8514542080..e49021f578 100644 --- a/poi-ooxml/src/test/java/org/apache/poi/ss/tests/format/TestCellFormatPart.java +++ b/poi-ooxml/src/test/java/org/apache/poi/ss/tests/format/TestCellFormatPart.java @@ -135,6 +135,17 @@ class TestCellFormatPart { } } + @Test + void testDateFormatNumbers() throws IOException { + TimeZone tz = LocaleUtil.getUserTimeZone(); + LocaleUtil.setUserTimeZone(TimeZone.getTimeZone("CET")); + try { + runFormatTests("DateFormatNumberTests.xlsx", Cell::getNumericCellValue); + } finally { + LocaleUtil.setUserTimeZone(tz); + } + } + @Test void testElapsedFormat() throws IOException { runFormatTests("ElapsedFormatTests.xlsx", Cell::getNumericCellValue); diff --git a/poi/src/main/java/org/apache/poi/ss/format/CellDateFormatter.java b/poi/src/main/java/org/apache/poi/ss/format/CellDateFormatter.java index 4a963d7d3d..08afdf4b33 100644 --- a/poi/src/main/java/org/apache/poi/ss/format/CellDateFormatter.java +++ b/poi/src/main/java/org/apache/poi/ss/format/CellDateFormatter.java @@ -39,9 +39,11 @@ public class CellDateFormatter extends CellFormatter { private final DateFormat dateFmt; private String sFmt; - private final Calendar EXCEL_EPOCH_CAL = + private static final Calendar EXCEL_EPOCH_CAL = LocaleUtil.getLocaleCalendar(1904, 0, 1); + private static final double NUM_MILLISECONDS_IN_DAY = 1000 * 60 * 60 * 24; + private static /* final */ CellDateFormatter SIMPLE_DATE; class DatePartHandler implements CellFormatPart.PartHandler { @@ -177,12 +179,15 @@ public class CellDateFormatter extends CellFormatter { value = 0.0; if (value instanceof Number) { Number num = (Number) value; - long v = num.longValue(); + // Convert from fractional days to milliseconds. Excel always rounds up. + double v = Math.round(num.doubleValue() * NUM_MILLISECONDS_IN_DAY); if (v == 0L) { value = EXCEL_EPOCH_CAL.getTime(); } else { Calendar c = (Calendar)EXCEL_EPOCH_CAL.clone(); - c.add(Calendar.SECOND, (int)(v / 1000)); + // If milliseconds were not requested in the format string, round the seconds. + int seconds = (int) (sFmt == null ? Math.round(v / 1000) : v / 1000); + c.add(Calendar.SECOND, seconds); c.add(Calendar.MILLISECOND, (int)(v % 1000)); value = c.getTime(); } @@ -201,6 +206,9 @@ public class CellDateFormatter extends CellFormatter { int pos = toAppendTo.length(); try (Formatter formatter = new Formatter(toAppendTo, Locale.ROOT)) { long msecs = dateObj.getTime() % 1000; + if (msecs < 0) { + msecs += 1000; + } formatter.format(locale, sFmt, msecs / 1000.0); } toAppendTo.delete(pos, pos + 2); diff --git a/test-data/spreadsheet/DateFormatNumberTests.xlsx b/test-data/spreadsheet/DateFormatNumberTests.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f585d9fde873fd5c4fa12ad674f25236cc5d7a22 GIT binary patch literal 10981 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 literal 0 HcmV?d00001 -- 2.39.5