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
This commit is contained in:
Nick Burch 2007-09-25 10:52:30 +00:00
parent a6fba24d1a
commit af0eef9988
2 changed files with 59 additions and 23 deletions

View 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 -1; // used to specify that date is invalid
private static final long DAY_MILLISECONDS = 24 * 60 * 60 * 1000; 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;
/** /**
* Given a Date, converts it into a double representing its internal Excel representation, * 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. * 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; ) / ( double ) DAY_MILLISECONDS;
calStart = dayStart(calStart); calStart = dayStart(calStart);
return fraction + ( double ) absoluteDay(calStart) double value = fraction + absoluteDay(calStart);
- CAL_1900_ABSOLUTE;
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 * @param cal the Calendar
* @exception IllegalArgumentException if date is invalid * @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. * @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. * @exception IllegalArgumentException if year is outside of range.
*/ */
private static int daysInPriorYears(int yr) private static int daysInPriorYears(int yr)
{ {
if (yr < 1601) if (yr < 1900) {
{
throw new IllegalArgumentException( 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 int yr1 = yr - 1;
+ y / 4 // plus julian leap days in prior years int leapDays = yr1 / 4 // plus julian leap days in prior years
- y / 100 // minus prior century years - yr1 / 100 // minus prior century years
+ y / 400; // plus years divisible by 400 + yr1 / 400 // plus years divisible by 400
- 460; // leap days in previous 1900 years
return days;
return 365 * (yr - 1900) + leapDays;
} }
// set HH:MM:SS fields of cal to 00:00:00:000 // set HH:MM:SS fields of cal to 00:00:00:000
private static Calendar dayStart(final Calendar cal) private static Calendar dayStart(final Calendar cal)
{ {

View File

@ -42,6 +42,12 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
public class TestHSSFDateUtil public class TestHSSFDateUtil
extends TestCase 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) public TestHSSFDateUtil(String s)
{ {
super(s); super(s);
@ -308,9 +314,37 @@ public class TestHSSFDateUtil
assertTrue(HSSFDateUtil.isCellDateFormatted(cell)); 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) { public static void main(String [] args) {
System.out System.out
.println("Testing org.apache.poi.hssf.usermodel.TestHSSFDateUtil"); .println("Testing org.apache.poi.hssf.usermodel.TestHSSFDateUtil");
junit.textui.TestRunner.run(TestHSSFDateUtil.class); junit.textui.TestRunner.run(TestHSSFDateUtil.class);
} }
} }