]> source.dussan.org Git - poi.git/commitdiff
Fix from Pavel Krupets for Excel Bug Date (1900/2/29)
authorNick Burch <nick@apache.org>
Tue, 25 Sep 2007 10:52:30 +0000 (10:52 +0000)
committerNick Burch <nick@apache.org>
Tue, 25 Sep 2007 10:52:30 +0000 (10:52 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@579194 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java

index af16204fde3ce74d237a5bdf4569b13f1139f75e..fc9ac3a3b3793790d994f0b0281f5c9543445bc3 100644 (file)
@@ -43,13 +43,10 @@ public class HSSFDateUtil
     {
     }
 
-    private static final int    BAD_DATE          =
+    private static final int    BAD_DATE         =
         -1;   // used to specify that date is invalid
-    private static final long   DAY_MILLISECONDS  = 24 * 60 * 60 * 1000;
-    private static final double CAL_1900_ABSOLUTE =
-        ( double ) absoluteDay(new GregorianCalendar(1900, Calendar
-        .JANUARY, 1)) - 2.0;
-
+    private static final long   DAY_MILLISECONDS = 24 * 60 * 60 * 1000;
+    
     /**
      * Given a Date, converts it into a double representing its internal Excel representation,
      *   which is the number of days since 1/1/1900. Fractional days represent hours, minutes, and seconds.
@@ -84,8 +81,13 @@ public class HSSFDateUtil
                               ) / ( double ) DAY_MILLISECONDS;
             calStart = dayStart(calStart);
 
-            return fraction + ( double ) absoluteDay(calStart)
-                   - CAL_1900_ABSOLUTE;
+            double value = fraction + absoluteDay(calStart);
+            
+            if (value >= 60) {
+                value += 1;
+            }
+            
+            return value;
         }
     }
 
@@ -287,9 +289,9 @@ public class HSSFDateUtil
     }
 
     /**
-     * Given a Calendar, return the number of days since 1600/12/31.
+     * Given a Calendar, return the number of days since 1900/12/31.
      *
-     * @return days number of days since 1600/12/31
+     * @return days number of days since 1900/12/31
      * @param  cal the Calendar
      * @exception IllegalArgumentException if date is invalid
      */
@@ -301,29 +303,29 @@ public class HSSFDateUtil
     }
 
     /**
-     * Return the number of days in prior years since 1601
+     * Return the number of days in prior years since 1900
      *
      * @return    days  number of days in years prior to yr.
-     * @param     yr    a year (1600 < yr < 4000)
+     * @param     yr    a year (1900 < yr < 4000)
      * @exception IllegalArgumentException if year is outside of range.
      */
 
     private static int daysInPriorYears(int yr)
     {
-        if (yr < 1601)
-        {
+        if (yr < 1900) {
             throw new IllegalArgumentException(
-                "'year' must be 1601 or greater");
+                "'year' must be 1900 or greater");
         }
-        int y    = yr - 1601;
-        int days = 365 * y      // days in prior years
-                   + y / 4      // plus julian leap days in prior years
-                   - y / 100    // minus prior century years
-                   + y / 400;   // plus years divisible by 400
-
-        return days;
+        
+        int yr1  = yr - 1;
+        int leapDays =   yr1 / 4   // plus julian leap days in prior years
+                       - yr1 / 100 // minus prior century years
+                       + yr1 / 400 // plus years divisible by 400 
+                       - 460;      // leap days in previous 1900 years
+        
+        return 365 * (yr - 1900) + leapDays;
     }
-
+    
     // set HH:MM:SS fields of cal to 00:00:00:000
     private static Calendar dayStart(final Calendar cal)
     {
index c1516f25313c8f7b662c125fa166e3aad6ba983e..d5c6b74a4b72dc35cb359f915e482b417cd2efc7 100644 (file)
@@ -42,6 +42,12 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 public class TestHSSFDateUtil
         extends TestCase
 {
+
+       public static final int CALENDAR_JANUARY = 0;
+       public static final int CALENDAR_FEBRUARY = 0;
+       public static final int CALENDAR_MARCH = 0;
+       public static final int CALENDAR_APRIL = 0;
+
     public TestHSSFDateUtil(String s)
     {
         super(s);
@@ -308,9 +314,37 @@ public class TestHSSFDateUtil
         assertTrue(HSSFDateUtil.isCellDateFormatted(cell));
     }
     
+    public void testDateBug_2Excel() {
+        assertEquals(59.0, HSSFDateUtil.getExcelDate(createDate(1900, CALENDAR_FEBRUARY, 28)), 0.00001);
+        assertEquals(61.0, HSSFDateUtil.getExcelDate(createDate(1900, CALENDAR_MARCH, 1)), 0.00001);
+        
+        assertEquals(37315.00, HSSFDateUtil.getExcelDate(createDate(2002, CALENDAR_FEBRUARY, 28)), 0.00001);
+        assertEquals(37316.00, HSSFDateUtil.getExcelDate(createDate(2002, CALENDAR_MARCH, 1)), 0.00001);
+        assertEquals(37257.00, HSSFDateUtil.getExcelDate(createDate(2002, CALENDAR_JANUARY, 1)), 0.00001);
+        assertEquals(38074.00, HSSFDateUtil.getExcelDate(createDate(2004, CALENDAR_MARCH, 28)), 0.00001);
+    }
+    
+    public void testDateBug_2Java() {
+        assertEquals(createDate(1900, Calendar.FEBRUARY, 28), HSSFDateUtil.getJavaDate(59.0));
+        assertEquals(createDate(1900, Calendar.MARCH, 1), HSSFDateUtil.getJavaDate(61.0));
+        
+        assertEquals(createDate(2002, Calendar.FEBRUARY, 28), HSSFDateUtil.getJavaDate(37315.00));
+        assertEquals(createDate(2002, Calendar.MARCH, 1), HSSFDateUtil.getJavaDate(37316.00));
+        assertEquals(createDate(2002, Calendar.JANUARY, 1), HSSFDateUtil.getJavaDate(37257.00));
+        assertEquals(createDate(2004, Calendar.MARCH, 28), HSSFDateUtil.getJavaDate(38074.00));
+    }
+
+    private Date createDate(int year, int month, int day) {
+        Calendar c = new GregorianCalendar();
+        c.set(year, month, day, 0, 0, 0);
+        c.set(Calendar.MILLISECOND, 0);
+        return c.getTime();
+    }
+    
     public static void main(String [] args) {
         System.out
                 .println("Testing org.apache.poi.hssf.usermodel.TestHSSFDateUtil");
         junit.textui.TestRunner.run(TestHSSFDateUtil.class);
     }
 }
+