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
This commit is contained in:
Andrew C. Oliver 2002-11-28 19:32:52 +00:00
parent 0c5f8a6bf4
commit 27a7b12c20
3 changed files with 71 additions and 14 deletions

View File

@ -89,6 +89,7 @@ import org.apache.poi.hssf.util.HSSFColor;
* @author Glen Stampoultzis (glens at apache.org) * @author Glen Stampoultzis (glens at apache.org)
* @author Sergei Kozello (sergeikozello at mail.ru) * @author Sergei Kozello (sergeikozello at mail.ru)
* @author Luc Girardin (luc dot girardin at macrofocus dot com) * @author Luc Girardin (luc dot girardin at macrofocus dot com)
* @author Dan Sherman (dsherman at isisph.com)
* @see org.apache.poi.hssf.usermodel.HSSFWorkbook * @see org.apache.poi.hssf.usermodel.HSSFWorkbook
* @version 1.0-pre * @version 1.0-pre
*/ */
@ -156,6 +157,8 @@ public class Workbook implements Model {
0; // holds the position of sup book 0; // holds the position of sup book
private short maxformatid = private short maxformatid =
-1; // holds the max format id -1; // holds the max format id
private boolean uses1904datewindowing =
false; // whether 1904 date windowing is being used
private static POILogger log = private static POILogger log =
POILogFactory.getLogger(Workbook.class); POILogFactory.getLogger(Workbook.class);
@ -249,6 +252,10 @@ public class Workbook implements Model {
retval.formats.add(rec); retval.formats.add(rec);
retval.maxformatid = retval.maxformatid >= ((FormatRecord)rec).getIndexCode() ? retval.maxformatid : ((FormatRecord)rec).getIndexCode(); retval.maxformatid = retval.maxformatid >= ((FormatRecord)rec).getIndexCode() ? retval.maxformatid : ((FormatRecord)rec).getIndexCode();
break; break;
case DateWindow1904Record.sid :
log.log(DEBUG, "found datewindow1904 record at " + k);
retval.uses1904datewindowing = ((DateWindow1904Record)rec).getWindowing() == 1;
break;
default : default :
} }
@ -1912,4 +1919,14 @@ public class Workbook implements Model {
{ {
return records; 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;
}
} }

View File

@ -94,6 +94,7 @@ import java.util.Calendar;
* NOTE: the alpha won't be implementing formulas * NOTE: the alpha won't be implementing formulas
* *
* @author Andrew C. Oliver (acoliver at apache dot org) * @author Andrew C. Oliver (acoliver at apache dot org)
* @author Dan Sherman (dsherman at isisph.com)
* @version 1.0-pre * @version 1.0-pre
*/ */
@ -783,7 +784,12 @@ public class HSSFCell
throw new NumberFormatException( throw new NumberFormatException(
"You cannot get a date value from an error cell"); "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);
}
} }
/** /**

View File

@ -69,6 +69,7 @@ import java.util.GregorianCalendar;
* *
* @author Michael Harhen * @author Michael Harhen
* @author Glen Stampoultzis (glens at apache.org) * @author Glen Stampoultzis (glens at apache.org)
* @author Dan Sherman (dsherman at isisph.com)
*/ */
public class HSSFDateUtil public class HSSFDateUtil
@ -115,33 +116,54 @@ public class HSSFDateUtil
/** /**
* Given a excel date, converts it into a Date. * Given a excel date, converts it into a Date.
* Assumes 1900 date windowing.
* *
* @param date the Excel Date * @param date the Excel Date
* *
* @return Java representation of a date (null if error) * @return Java representation of a date (null if error)
* @see #getJavaDate(double,boolean)
*/ */
public static Date getJavaDate(double date) public static Date getJavaDate(double date)
{ {
if (isValidExcelDate(date)) return getJavaDate(date,false);
{ }
int wholeDaysSince1900 = ( int ) Math.floor(date);
GregorianCalendar calendar = new GregorianCalendar(1900, /**
0, wholeDaysSince1900 * Given an Excel date with either 1900 or 1904 date windowing,
- 1); * converts it to a java.util.Date.
int millisecondsInDay = *
( int ) ((date - Math.floor(date)) * @param date The Excel date.
* ( double ) DAY_MILLISECONDS + 0.5); * @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); calendar.set(GregorianCalendar.MILLISECOND, millisecondsInDay);
return calendar.getTime(); return calendar.getTime();
} }
else else {
{
return null; return null;
} }
} }
/** /**
* given a format ID this will check whether the format represents * given a format ID this will check whether the format represents
* an internal date format or not. * an internal date format or not.
@ -164,6 +186,18 @@ public class HSSFDateUtil
case 0x2d: case 0x2d:
case 0x2e: case 0x2e:
case 0x2f: 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; retval = true;
break; break;