From 994cc7c045a5a17a521f4c87da1acb90a8f56178 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Tue, 25 Sep 2007 10:52:30 +0000 Subject: [PATCH] Fix from Pavel Krupets for Excel Bug Date (1900/2/29) git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@579194 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/hssf/usermodel/HSSFDateUtil.java | 48 ++++++++++--------- .../poi/hssf/usermodel/TestHSSFDateUtil.java | 34 +++++++++++++ 2 files changed, 59 insertions(+), 23 deletions(-) diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java b/src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java index af16204fde..fc9ac3a3b3 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java @@ -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) { diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java index c1516f2531..d5c6b74a4b 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java @@ -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); } } +