Index: src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java,v retrieving revision 1.7 diff -u -r1.7 HSSFDateUtil.java --- src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java 1 Jan 2004 09:03:32 -0000 1.7 +++ src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java 10 Mar 2004 16:43:44 -0000 @@ -70,6 +70,7 @@ * @author Michael Harhen * @author Glen Stampoultzis (glens at apache.org) * @author Dan Sherman (dsherman at isisph.com) + * @author Hack Kampbjorn (hak at 2mba.dk) */ public class HSSFDateUtil @@ -105,9 +106,19 @@ } else { + // Because of daylight time saving we cannot use + // date.getTime() - calStart.getTimeInMillis() + // as the difference in milliseconds between 00:00 and 04:00 + // can be 3, 4 or 5 hours but Excel expects it to always + // be 4 hours. + // E.g. 2004-03-28 04:00 CEST - 2004-03-28 00:00 CET is 3 hours + // and 2004-10-31 04:00 CET - 2004-10-31 00:00 CEST is 5 hours + double fraction = (((calStart.get(Calendar.HOUR_OF_DAY) * 60 + + calStart.get(Calendar.MINUTE) + ) * 60 + calStart.get(Calendar.SECOND) + ) * 1000 + calStart.get(Calendar.MILLISECOND) + ) / ( double ) DAY_MILLISECONDS; calStart = dayStart(calStart); - double fraction = (date.getTime() - calStart.getTime().getTime()) - / ( double ) DAY_MILLISECONDS; return fraction + ( double ) absoluteDay(calStart) - CAL_1900_ABSOLUTE; @@ -133,10 +144,20 @@ * Given an Excel date with either 1900 or 1904 date windowing, * converts it to a java.util.Date. * + * NOTE: If the default TimeZone in Java uses Daylight + * Saving Time then the conversion back to an Excel date may not give + * the same value, that is the comparison + * excelDate == getExcelDate(getJavaDate(excelDate,false)) + * is not always true. For example if default timezone is + * Europe/Copenhagen, on 2004-03-28 the minute after + * 01:59 CET is 03:00 CEST, if the excel date represents a time between + * 02:00 and 03:00 then it is converted to past 03:00 summer time + * * @param date The Excel date. * @param use1904windowing true if date uses 1904 windowing, * or false if using 1900 date windowing. * @return Java representation of the date, or null if date is not a valid Excel date + * @see java.util.TimeZone */ public static Date getJavaDate(double date, boolean use1904windowing) { if (isValidExcelDate(date)) { Index: src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java,v retrieving revision 1.3 diff -u -r1.3 TestHSSFDateUtil.java --- src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java 30 Apr 2003 04:38:58 -0000 1.3 +++ src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java 10 Mar 2004 16:43:46 -0000 @@ -58,7 +58,9 @@ import junit.framework.TestCase; import java.util.Date; +import java.util.Calendar; import java.util.GregorianCalendar; +import java.util.TimeZone; /** * Class TestHSSFDateUtil @@ -66,6 +68,7 @@ * * @author * @author Dan Sherman (dsherman at isisph.com) + * @author Hack Kampbjorn (hak at 2mba.dk) * @version %I%, %G% */ @@ -115,4 +118,111 @@ dateIf1904.getTime(), HSSFDateUtil.getJavaDate(excelDate,true).getTime()); } + + /** + * Checks the conversion of a java.util.date to Excel on a day when + * Daylight Saving Time starts. + */ + public void testExcelConversionOnDSTStart() { + TimeZone cet = TimeZone.getTimeZone("Europe/Copenhagen"); + TimeZone.setDefault(cet); + Calendar cal = new GregorianCalendar(2004, Calendar.MARCH, 28); + for (int hour = 0; hour < 24; hour++) { + + // Skip 02:00 CET as that is the Daylight change time + // and Java converts it automatically to 03:00 CEST + if (hour == 2) { + continue; + } + + cal.set(Calendar.HOUR_OF_DAY, hour); + Date javaDate = cal.getTime(); + double excelDate = HSSFDateUtil.getExcelDate(javaDate); + double difference = excelDate - Math.floor(excelDate); + int differenceInHours = (int) (difference * 24 * 60 + 0.5) / 60; + assertEquals("Checking " + hour + " hour on Daylight Saving Time start date", + hour, + differenceInHours); + assertEquals("Checking " + hour + " hour on Daylight Saving Time start date", + javaDate.getTime(), + HSSFDateUtil.getJavaDate(excelDate).getTime()); + } + } + + /** + * Checks the conversion of an Excel date to a java.util.date on a day when + * Daylight Saving Time starts. + */ + public void testJavaConversionOnDSTStart() { + TimeZone cet = TimeZone.getTimeZone("Europe/Copenhagen"); + TimeZone.setDefault(cet); + Calendar cal = new GregorianCalendar(2004, Calendar.MARCH, 28); + double excelDate = HSSFDateUtil.getExcelDate(cal.getTime()); + double oneHour = 1.0 / 24; + double oneMinute = oneHour / 60; + for (int hour = 0; hour < 24; hour++, excelDate += oneHour) { + + // Skip 02:00 CET as that is the Daylight change time + // and Java converts it automatically to 03:00 CEST + if (hour == 2) { + continue; + } + + cal.set(Calendar.HOUR_OF_DAY, hour); + Date javaDate = HSSFDateUtil.getJavaDate(excelDate); + assertEquals("Checking " + hour + " hours on Daylight Saving Time start date", + excelDate, + HSSFDateUtil.getExcelDate(javaDate), oneMinute); + } + } + + /** + * Checks the conversion of a java.util.Date to Excel on a day when + * Daylight Saving Time ends. + */ + public void testExcelConversionOnDSTEnd() { + TimeZone cet = TimeZone.getTimeZone("Europe/Copenhagen"); + TimeZone.setDefault(cet); + Calendar cal = new GregorianCalendar(2004, Calendar.OCTOBER, 31); + for (int hour = 0; hour < 24; hour++) { + cal.set(Calendar.HOUR_OF_DAY, hour); + Date javaDate = cal.getTime(); + double excelDate = HSSFDateUtil.getExcelDate(javaDate); + double difference = excelDate - Math.floor(excelDate); + int differenceInHours = (int) (difference * 24 * 60 + 0.5) / 60; + assertEquals("Checking " + hour + " hour on Daylight Saving Time end date", + hour, + differenceInHours); + assertEquals("Checking " + hour + " hour on Daylight Saving Time start date", + javaDate.getTime(), + HSSFDateUtil.getJavaDate(excelDate).getTime()); + } + } + + /** + * Checks the conversion of an Excel date to java.util.Date on a day when + * Daylight Saving Time ends. + */ + public void testJavaConversionOnDSTEnd() { + TimeZone cet = TimeZone.getTimeZone("Europe/Copenhagen"); + TimeZone.setDefault(cet); + Calendar cal = new GregorianCalendar(2004, Calendar.OCTOBER, 31); + double excelDate = HSSFDateUtil.getExcelDate(cal.getTime()); + double oneHour = 1.0 / 24; + double oneMinute = oneHour / 60; + for (int hour = 0; hour < 24; hour++, excelDate += oneHour) { + cal.set(Calendar.HOUR_OF_DAY, hour); + Date javaDate = HSSFDateUtil.getJavaDate(excelDate); + assertEquals("Checking " + hour + " hours on Daylight Saving Time start date", + excelDate, + HSSFDateUtil.getExcelDate(javaDate), oneMinute); + } + } + + public static void main(String [] args) { + System.out + .println("Testing org.apache.poi.hssf.usermodel.TestHSSFDateUtil"); + junit.textui.TestRunner.run(TestHSSFDateUtil.class); + } + }