From b153040a9e62a6e33a8e95c1e76f88d05102055c Mon Sep 17 00:00:00 2001 From: "Andrew C. Oliver" Date: Thu, 28 Nov 2002 19:32:52 +0000 Subject: [PATCH] http://nagoya.apache.org/bugzilla/show_bug.cgi?id=14375 PR: Obtained from: Submitted by: Reviewed by: git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@352931 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/poi/hssf/model/Workbook.java | 17 ++++++ .../apache/poi/hssf/usermodel/HSSFCell.java | 8 ++- .../poi/hssf/usermodel/HSSFDateUtil.java | 60 +++++++++++++++---- 3 files changed, 71 insertions(+), 14 deletions(-) diff --git a/src/java/org/apache/poi/hssf/model/Workbook.java b/src/java/org/apache/poi/hssf/model/Workbook.java index a07862b5b..d7f305968 100644 --- a/src/java/org/apache/poi/hssf/model/Workbook.java +++ b/src/java/org/apache/poi/hssf/model/Workbook.java @@ -89,6 +89,7 @@ import org.apache.poi.hssf.util.HSSFColor; * @author Glen Stampoultzis (glens at apache.org) * @author Sergei Kozello (sergeikozello at mail.ru) * @author Luc Girardin (luc dot girardin at macrofocus dot com) + * @author Dan Sherman (dsherman at isisph.com) * @see org.apache.poi.hssf.usermodel.HSSFWorkbook * @version 1.0-pre */ @@ -156,6 +157,8 @@ public class Workbook implements Model { 0; // holds the position of sup book private short maxformatid = -1; // holds the max format id + private boolean uses1904datewindowing = + false; // whether 1904 date windowing is being used private static POILogger log = POILogFactory.getLogger(Workbook.class); @@ -249,6 +252,10 @@ public class Workbook implements Model { retval.formats.add(rec); retval.maxformatid = retval.maxformatid >= ((FormatRecord)rec).getIndexCode() ? retval.maxformatid : ((FormatRecord)rec).getIndexCode(); break; + case DateWindow1904Record.sid : + log.log(DEBUG, "found datewindow1904 record at " + k); + retval.uses1904datewindowing = ((DateWindow1904Record)rec).getWindowing() == 1; + break; default : } @@ -1912,4 +1919,14 @@ public class Workbook implements Model { { return records; } + + /** + * Whether date windowing is based on 1/2/1904 or 1/1/1900. + * Some versions of Excel (Mac) can save workbooks using 1904 date windowing. + * + * @return true if using 1904 date windowing + */ + public boolean isUsing1904DateWindowing() { + return uses1904datewindowing; + } } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java index b3aaf2dbb..2a38d6aa8 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java @@ -94,6 +94,7 @@ import java.util.Calendar; * NOTE: the alpha won't be implementing formulas * * @author Andrew C. Oliver (acoliver at apache dot org) + * @author Dan Sherman (dsherman at isisph.com) * @version 1.0-pre */ @@ -783,7 +784,12 @@ public class HSSFCell throw new NumberFormatException( "You cannot get a date value from an error cell"); } - return HSSFDateUtil.getJavaDate(cellValue); + if (book.isUsing1904DateWindowing()) { + return HSSFDateUtil.getJavaDate(cellValue,true); + } + else { + return HSSFDateUtil.getJavaDate(cellValue,false); + } } /** diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java b/src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java index fb26a7d97..9024e246f 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java @@ -69,6 +69,7 @@ import java.util.GregorianCalendar; * * @author Michael Harhen * @author Glen Stampoultzis (glens at apache.org) + * @author Dan Sherman (dsherman at isisph.com) */ public class HSSFDateUtil @@ -115,33 +116,54 @@ public class HSSFDateUtil /** * Given a excel date, converts it into a Date. + * Assumes 1900 date windowing. * * @param date the Excel Date * * @return Java representation of a date (null if error) + * @see #getJavaDate(double,boolean) */ public static Date getJavaDate(double date) { - if (isValidExcelDate(date)) - { - int wholeDaysSince1900 = ( int ) Math.floor(date); - GregorianCalendar calendar = new GregorianCalendar(1900, - 0, wholeDaysSince1900 - - 1); - int millisecondsInDay = - ( int ) ((date - Math.floor(date)) - * ( double ) DAY_MILLISECONDS + 0.5); - + return getJavaDate(date,false); + } + + /** + * Given an Excel date with either 1900 or 1904 date windowing, + * converts it to a java.util.Date. + * + * @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 + */ + public static Date getJavaDate(double date, boolean use1904windowing) { + if (isValidExcelDate(date)) { + int startYear = 1900; + int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it isn't + int wholeDays = (int)Math.floor(date); + if (use1904windowing) { + startYear = 1904; + dayAdjust = 1; // 1904 date windowing uses 1/2/1904 as the first day + } + else if (wholeDays < 61) { + // Date is prior to 3/1/1900, so adjust because Excel thinks 2/29/1900 exists + // If Excel date == 2/29/1900, will become 3/1/1900 in Java representation + dayAdjust = 0; + } + GregorianCalendar calendar = new GregorianCalendar(startYear,0, + wholeDays + dayAdjust); + int millisecondsInDay = (int)((date - Math.floor(date)) * + (double) DAY_MILLISECONDS + 0.5); calendar.set(GregorianCalendar.MILLISECOND, millisecondsInDay); return calendar.getTime(); } - else - { + else { return null; } } - + /** * given a format ID this will check whether the format represents * an internal date format or not. @@ -164,6 +186,18 @@ public class HSSFDateUtil case 0x2d: case 0x2e: case 0x2f: + // Additional internal date formats found by inspection + // Using Excel v.X 10.1.0 (Mac) + case 0xa4: + case 0xa5: + case 0xa6: + case 0xa7: + case 0xa8: + case 0xa9: + case 0xaa: + case 0xab: + case 0xac: + case 0xad: retval = true; break;