]> source.dussan.org Git - poi.git/commitdiff
[github-235] Fix date formatting for number cell values. Thanks to Anthony Schott...
authorPJ Fanning <fanningpj@apache.org>
Sun, 25 Apr 2021 17:16:05 +0000 (17:16 +0000)
committerPJ Fanning <fanningpj@apache.org>
Sun, 25 Apr 2021 17:16:05 +0000 (17:16 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1889179 13f79535-47bb-0310-9956-ffa450edef68

poi-ooxml/src/test/java/org/apache/poi/ss/tests/format/TestCellFormatPart.java
poi/src/main/java/org/apache/poi/ss/format/CellDateFormatter.java
test-data/spreadsheet/DateFormatNumberTests.xlsx [new file with mode: 0644]

index 851454208099c4f2ed9cebbb53b269c9f7e76a57..e49021f5789325e3e23b3c9cd245f54f2519fe4f 100644 (file)
@@ -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);
index 4a963d7d3d79bba27045418515915531f644e15a..08afdf4b33f7ec491276163e30c4e49ebaf14e82 100644 (file)
@@ -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 (file)
index 0000000..f585d9f
Binary files /dev/null and b/test-data/spreadsheet/DateFormatNumberTests.xlsx differ