import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.formula.ptg.StringPtg;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
+import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.util.LocaleUtil;
/**
if (timeStr == null) {
return null;
}
- return Double.valueOf(HSSFDateUtil.convertTime(timeStr));
+ return Double.valueOf(DateUtil.convertTime(timeStr));
}
/**
* @param dateFormat pass <code>null</code> for default YYYYMMDD
}
Date dateVal;
if (dateFormat == null) {
- dateVal = HSSFDateUtil.parseYYYYMMDDDate(dateStr);
+ dateVal = DateUtil.parseYYYYMMDDDate(dateStr);
} else {
try {
dateVal = dateFormat.parse(dateStr);
+ "' using specified format '" + dateFormat + "'", e);
}
}
- return Double.valueOf(HSSFDateUtil.getExcelDate(dateVal));
+ return Double.valueOf(DateUtil.getExcelDate(dateVal));
}
public static DVConstraint createCustomFormulaConstraint(String formula) {
package org.apache.poi.hssf.usermodel;
import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.CellValue;
import org.apache.poi.ss.usermodel.Comment;
+import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.FormulaError;
import org.apache.poi.ss.usermodel.Hyperlink;
import org.apache.poi.ss.usermodel.RichTextString;
* {@inheritDoc}
*
* <p>In HSSF, only the number of days is stored. The fractional part is ignored.</p>
- * @see HSSFDateUtil
+ * @see DateUtil
* @see org.apache.poi.ss.usermodel.DateUtil
*/
protected void setCellValueImpl(Date value) {
- setCellValue(HSSFDateUtil.getExcelDate(value, _book.getWorkbook().isUsing1904DateWindowing()));
+ setCellValue(DateUtil.getExcelDate(value, _book.getWorkbook().isUsing1904DateWindowing()));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>In HSSF, only the number of days is stored. The fractional part is ignored.</p>
+ * @see DateUtil
+ * @see org.apache.poi.ss.usermodel.DateUtil
+ */
+ protected void setCellValueImpl(LocalDateTime value) {
+ setCellValue(DateUtil.getExcelDate(value, _book.getWorkbook().isUsing1904DateWindowing()));
}
/**
*/
@Override
protected void setCellValueImpl(Calendar value) {
- setCellValue( HSSFDateUtil.getExcelDate(value, _book.getWorkbook().isUsing1904DateWindowing()) );
+ setCellValue( DateUtil.getExcelDate(value, _book.getWorkbook().isUsing1904DateWindowing()) );
}
/**
}
double value = getNumericCellValue();
if (_book.getWorkbook().isUsing1904DateWindowing()) {
- return HSSFDateUtil.getJavaDate(value, true);
+ return DateUtil.getJavaDate(value, true);
}
- return HSSFDateUtil.getJavaDate(value, false);
+ return DateUtil.getJavaDate(value, false);
+ }
+
+ /**
+ * Get the value of the cell as a LocalDateTime.
+ * For strings we throw an exception.
+ * For blank cells we return a null.
+ * See {@link HSSFDataFormatter} for formatting
+ * this date into a string similar to how excel does.
+ */
+ public LocalDateTime getLocalDateTimeCellValue() {
+
+ if (_cellType == CellType.BLANK) {
+ return null;
+ }
+ double value = getNumericCellValue();
+ if (_book.getWorkbook().isUsing1904DateWindowing()) {
+ return DateUtil.getLocalDateTime(value, true);
+ }
+ return DateUtil.getLocalDateTime(value, false);
}
/**
default:
throw new IllegalStateException("Unexpected formula result type (" + _cellType + ")");
}
-
+
}
/**
/**
* <p>Set the style for the cell. The style should be an HSSFCellStyle created/retreived from
* the HSSFWorkbook.</p>
- *
+ *
* <p>To change the style of a cell without affecting other cells that use the same style,
* use {@link org.apache.poi.ss.util.CellUtil#setCellStyleProperties(org.apache.poi.ss.usermodel.Cell, java.util.Map)}</p>
*
return getCellFormula();
case NUMERIC:
//TODO apply the dataformat for this cell
- if (HSSFDateUtil.isCellDateFormatted(this)) {
+ if (DateUtil.isCellDateFormatted(this)) {
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy", LocaleUtil.getUserLocale());
sdf.setTimeZone(LocaleUtil.getUserTimeZone());
return sdf.format(getDateCellValue());
/**
* Contains methods for dealing with Excel dates.
+ * @deprecated Use {@link DateUtil} instead
*/
-public class HSSFDateUtil extends DateUtil {
+@Deprecated
+public final class HSSFDateUtil extends DateUtil {
protected static int absoluteDay(Calendar cal, boolean use1904windowing) {
return DateUtil.absoluteDay(cal, use1904windowing);
}
package org.apache.poi.ss.usermodel;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
*/
void setCellValue(Date value);
+ /**
+ * <p>Converts the supplied date to its equivalent Excel numeric value and sets
+ * that into the cell.</p>
+ *
+ * <p><b>Note</b> - There is actually no 'DATE' cell type in Excel. In many
+ * cases (when entering date values), Excel automatically adjusts the
+ * <i>cell style</i> to some date format, creating the illusion that the cell
+ * data type is now something besides {@link CellType#NUMERIC}. POI
+ * does not attempt to replicate this behaviour. To make a numeric cell
+ * display as a date, use {@link #setCellStyle(CellStyle)} etc.</p>
+ *
+ * @param value the numeric value to set this cell to. For formulas we'll set the
+ * precalculated value, for numerics we'll set its value. For other types we
+ * will change the cell to a numerics cell and set its value.
+ */
+ void setCellValue(LocalDateTime value);
+
+ /**
+ * <p>Converts the supplied date to its equivalent Excel numeric value and sets
+ * that into the cell.</p>
+ *
+ * <p><b>Note</b> - There is actually no 'DATE' cell type in Excel. In many
+ * cases (when entering date values), Excel automatically adjusts the
+ * <i>cell style</i> to some date format, creating the illusion that the cell
+ * data type is now something besides {@link CellType#NUMERIC}. POI
+ * does not attempt to replicate this behaviour. To make a numeric cell
+ * display as a date, use {@link #setCellStyle(CellStyle)} etc.</p>
+ *
+ * @param value the numeric value to set this cell to. For formulas we'll set the
+ * precalculated value, for numerics we'll set its value. For other types we
+ * will change the cell to a numerics cell and set its value.
+ */
+ default void setCellValue(LocalDate value) {
+ setCellValue(value.atStartOfDay());
+ }
+
/**
* <p>Set a date value for the cell. Excel treats dates as numeric so you will need to format the cell as
* a date.</p>
*/
Date getDateCellValue();
+ /**
+ * Get the value of the cell as a LocalDateTime.
+ * <p>
+ * For strings we throw an exception. For blank cells we return a null.
+ * </p>
+ * @return the value of the cell as a LocalDateTime
+ * @throws IllegalStateException if the cell type returned by {@link #getCellType()} is {@link CellType#STRING}
+ * @exception NumberFormatException if the cell value isn't a parsable <code>double</code>.
+ * @see DataFormatter for formatting this date into a string similar to how excel does.
+ */
+ LocalDateTime getLocalDateTimeCellValue();
+
/**
* Get the value of the cell as a XSSFRichTextString
* <p>
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.util.Removal;
+import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
setCellValueImpl(value);
}
+ @Override
+ public void setCellValue(LocalDateTime value) {
+ if(value == null) {
+ setBlank();
+ return;
+ }
+ setCellValueImpl(value);
+ }
+
/**
* Implementation-specific way to set a date value.
* <code>value</code> is guaranteed to be non-null.
*/
protected abstract void setCellValueImpl(Date value);
+ /**
+ * Implementation-specific way to set a date value.
+ * <code>value</code> is guaranteed to be non-null.
+ * The implementation is expected to adjust the cell type accordingly, so that after this call
+ * getCellType() or getCachedFormulaResultType() would return {@link CellType#NUMERIC}.
+ * @param value the new date to set
+ */
+ protected abstract void setCellValueImpl(LocalDateTime value);
+
/**
* {@inheritDoc}
*/
package org.apache.poi.ss.usermodel;
+import org.apache.poi.ss.formula.ConditionalFormattingEvaluator;
+import org.apache.poi.util.LocaleUtil;
+
import java.time.LocalDate;
+import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.TimeZone;
import java.util.regex.Pattern;
-import org.apache.poi.ss.formula.ConditionalFormattingEvaluator;
-import org.apache.poi.util.LocaleUtil;
-
/**
* Contains methods for dealing with Excel dates.
*/
public class DateUtil {
+ // FIXME this should be changed to private and the class marked final once HSSFDateUtil can be removed
protected DateUtil() {
// no instances of this class
}
.parseDefaulting(ChronoField.YEAR_OF_ERA, LocaleUtil.getLocaleCalendar().get(Calendar.YEAR))
.toFormatter();
+ /**
+ * Convert a Java Date (at UTC) to LocalDateTime.
+ * @param date the date
+ * @return LocalDateTime instance
+ */
+ public static LocalDateTime toLocalDateTime(Date date) {
+ return date.toInstant()
+ .atZone(TimeZone.getTimeZone("UTC").toZoneId()) // java.util.Date uses UTC
+ .toLocalDateTime();
+ }
+
+ /**
+ * Convert a Java Calendar (at UTC) to LocalDateTime.
+ * @param date the date
+ * @return LocalDateTime instance
+ */
+ public static LocalDateTime toLocalDateTime(Calendar date) {
+ return date.toInstant()
+ .atZone(TimeZone.getTimeZone("UTC").toZoneId()) // java.util.Date uses UTC
+ .toLocalDateTime();
+ }
+
+ /**
+ * Given a LocalDate, 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.
+ *
+ * @return Excel representation of Date (-1 if error - test for error by checking for less than 0.1)
+ * @param date the Date
+ */
+ public static double getExcelDate(LocalDate date) {
+ return getExcelDate(date, false);
+ }
+
+ /**
+ * Given a LocalDate, 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.
+ *
+ * @return Excel representation of Date (-1 if error - test for error by checking for less than 0.1)
+ * @param date the Date
+ * @param use1904windowing Should 1900 or 1904 date windowing be used?
+ */
+ public static double getExcelDate(LocalDate date, boolean use1904windowing) {
+ int year = date.getYear();
+ int dayOfYear = date.getDayOfYear();
+ int hour = 0;
+ int minute = 0;
+ int second = 0;
+ int milliSecond = 0;
+
+ return internalGetExcelDate(year, dayOfYear, hour, minute, second, milliSecond, use1904windowing);
+ }
+
+ /**
+ * Given a LocalDateTime, 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.
+ *
+ * @return Excel representation of Date (-1 if error - test for error by checking for less than 0.1)
+ * @param date the Date
+ */
+ public static double getExcelDate(LocalDateTime date) {
+ return getExcelDate(date, false);
+ }
+
+ /**
+ * Given a LocalDateTime, 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.
+ *
+ * @return Excel representation of Date (-1 if error - test for error by checking for less than 0.1)
+ * @param date the Date
+ * @param use1904windowing Should 1900 or 1904 date windowing be used?
+ */
+ public static double getExcelDate(LocalDateTime date, boolean use1904windowing) {
+ int year = date.getYear();
+ int dayOfYear = date.getDayOfYear();
+ int hour = date.getHour();
+ int minute = date.getMinute();
+ int second = date.getSecond();
+ int milliSecond = date.getNano()/1_000_000;
+
+ return internalGetExcelDate(year, dayOfYear, hour, minute, second, milliSecond, use1904windowing);
+ }
+
/**
* 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.
public static double getExcelDate(Date date) {
return getExcelDate(date, false);
}
+
/**
* 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.
*/
public static double getExcelDate(Date date, boolean use1904windowing) {
Calendar calStart = LocaleUtil.getLocaleCalendar();
- calStart.setTime(date); // If date includes hours, minutes, and seconds, set them to 0
- return internalGetExcelDate(calStart, use1904windowing);
+ calStart.setTime(date);
+ int year = calStart.get(Calendar.YEAR);
+ int dayOfYear = calStart.get(Calendar.DAY_OF_YEAR);
+ int hour = calStart.get(Calendar.HOUR_OF_DAY);
+ int minute = calStart.get(Calendar.MINUTE);
+ int second = calStart.get(Calendar.SECOND);
+ int milliSecond = calStart.get(Calendar.MILLISECOND);
+
+ return internalGetExcelDate(year, dayOfYear, hour, minute, second, milliSecond, use1904windowing);
}
+
/**
* Given a Date in the form of a Calendar, converts it into a double
* representing its internal Excel representation, which is the
* @param use1904windowing Should 1900 or 1904 date windowing be used?
*/
public static double getExcelDate(Calendar date, boolean use1904windowing) {
- // Don't alter the supplied Calendar as we do our work
- return internalGetExcelDate( (Calendar)date.clone(), use1904windowing );
- }
- private static double internalGetExcelDate(Calendar date, boolean use1904windowing) {
- if ((!use1904windowing && date.get(Calendar.YEAR) < 1900) ||
- (use1904windowing && date.get(Calendar.YEAR) < 1904))
+ int year = date.get(Calendar.YEAR);
+ int dayOfYear = date.get(Calendar.DAY_OF_YEAR);
+ int hour = date.get(Calendar.HOUR_OF_DAY);
+ int minute = date.get(Calendar.MINUTE);
+ int second = date.get(Calendar.SECOND);
+ int milliSecond = date.get(Calendar.MILLISECOND);
+
+ return internalGetExcelDate(year, dayOfYear, hour, minute, second, milliSecond, use1904windowing);
+ }
+
+ private static double internalGetExcelDate(int year, int dayOfYear, int hour, int minute, int second, int milliSecond, boolean use1904windowing) {
+ if ((!use1904windowing && year < 1900) ||
+ (use1904windowing && year < 1904))
{
return BAD_DATE;
}
+
// Because of daylight time saving we cannot use
// date.getTime() - calStart.getTimeInMillis()
// as the difference in milliseconds between 00:00 and 04:00
// 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 = (((date.get(Calendar.HOUR_OF_DAY) * 60.0
- + date.get(Calendar.MINUTE)
- ) * 60.0 + date.get(Calendar.SECOND)
- ) * 1000.0 + date.get(Calendar.MILLISECOND)
+ double fraction = (((hour * 60.0
+ + minute
+ ) * 60.0 + second
+ ) * 1000.0 + milliSecond
) / DAY_MILLISECONDS;
- Calendar calStart = dayStart(date);
- double value = fraction + absoluteDay(calStart, use1904windowing);
+ double value = fraction + absoluteDay(year, dayOfYear, use1904windowing);
if (!use1904windowing && value >= 60) {
value++;
public static Date getJavaDate(double date, boolean use1904windowing) {
return getJavaDate(date, use1904windowing, null, false);
}
+
+ /**
+ * Given an Excel date with using 1900 date windowing, and
+ * converts it to a java.time.LocalDateTime.
+ *
+ * NOTE: If the default <code>TimeZone</code> in Java uses Daylight
+ * Saving Time then the conversion back to an Excel date may not give
+ * the same value, that is the comparison
+ * <CODE>excelDate == getExcelDate(getLocalDateTime(excelDate,false))</CODE>
+ * is not always true. For example if default timezone is
+ * <code>Europe/Copenhagen</code>, 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.
+ * @return Java representation of the date, or null if date is not a valid Excel date
+ * @see java.util.TimeZone
+ */
+ public static LocalDateTime getLocalDateTime(double date) {
+ return getLocalDateTime(date, false, false);
+ }
+
+ /**
+ * Given an Excel date with either 1900 or 1904 date windowing,
+ * converts it to a java.time.LocalDateTime.
+ *
+ * Excel Dates and Times are stored without any timezone
+ * information. If you know (through other means) that your file
+ * uses a different TimeZone to the system default, you can use
+ * this version of the getJavaDate() method to handle it.
+ *
+ * @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 LocalDateTime getLocalDateTime(double date, boolean use1904windowing) {
+ return getLocalDateTime(date, use1904windowing, false);
+ }
+
+ /**
+ * Given an Excel date with either 1900 or 1904 date windowing,
+ * converts it to a java.time.LocalDateTime.
+ *
+ * Excel Dates and Times are stored without any timezone
+ * information. If you know (through other means) that your file
+ * uses a different TimeZone to the system default, you can use
+ * this version of the getJavaDate() method to handle it.
+ *
+ * @param date The Excel date.
+ * @param use1904windowing true if date uses 1904 windowing,
+ * or false if using 1900 date windowing.
+ * @param roundSeconds round to closest second
+ * @return Java representation of the date, or null if date is not a valid Excel date
+ */
+ public static LocalDateTime getLocalDateTime(double date, boolean use1904windowing, boolean roundSeconds) {
+ if (!isValidExcelDate(date)) {
+ return null;
+ }
+ int wholeDays = (int)Math.floor(date);
+ int millisecondsInDay = (int)((date - wholeDays) * DAY_MILLISECONDS + 0.5);
+
+ int startYear = 1900;
+ int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it isn't
+ 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;
+ }
+
+ LocalDateTime ldt = LocalDateTime.of(startYear, 1, 1, 0, 0);
+ ldt = ldt.plusDays(wholeDays+dayAdjust-1);
+ ldt = ldt.plusNanos(millisecondsInDay*1_000_000L);
+
+ return ldt;
+ }
public static void setCalendar(Calendar calendar, int wholeDays,
int millisecondsInDay, boolean use1904windowing, boolean roundSeconds) {
*/
protected static int absoluteDay(Calendar cal, boolean use1904windowing)
{
- return cal.get(Calendar.DAY_OF_YEAR)
- + daysInPriorYears(cal.get(Calendar.YEAR), use1904windowing);
+ return absoluteDay(cal.get(Calendar.YEAR), cal.get(Calendar.DAY_OF_YEAR), use1904windowing);
+ }
+
+ /**
+ * Given a LocalDateTime, return the number of days since 1900/12/31.
+ *
+ * @return days number of days since 1900/12/31
+ * @param date the Date
+ * @exception IllegalArgumentException if date is invalid
+ */
+ protected static int absoluteDay(LocalDateTime date, boolean use1904windowing)
+ {
+ return absoluteDay(date.getYear(), date.getDayOfYear(), use1904windowing);
}
+ /**
+ * Given a year and day of year, return the number of days since 1900/12/31.
+ *
+ * @return days number of days since 1900/12/31
+ * @param dayOfYear the day of the year
+ * @param year the year
+ * @exception IllegalArgumentException if date is invalid
+ */
+ private static int absoluteDay(int year, int dayOfYear, boolean use1904windowing) {
+ return dayOfYear + daysInPriorYears(year, use1904windowing);
+ }
+
/**
* Return the number of days in prior years since 1900
*
* @exception IllegalArgumentException if year is outside of range.
*/
- private static int daysInPriorYears(int yr, boolean use1904windowing)
+ static int daysInPriorYears(int yr, boolean use1904windowing)
{
if ((!use1904windowing && yr < 1900) || (use1904windowing && yr < 1904)) {
throw new IllegalArgumentException("'year' must be 1900 or greater");
import java.text.DateFormat;
import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
setCellValue(DateUtil.getExcelDate(value, date1904));
}
-
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void setCellValueImpl(LocalDateTime value) {
+ boolean date1904 = getSheet().getWorkbook().isDate1904();
+ setCellValue(DateUtil.getExcelDate(value, date1904));
+ }
+
/**
* {@inheritDoc}
*/
return DateUtil.getJavaDate(value, date1904);
}
+ /**
+ * Get the value of the cell as a LocalDateTime.
+ * <p>
+ * For strings we throw an exception. For blank cells we return a null.
+ * </p>
+ * @return the value of the cell as a date
+ * @throws IllegalStateException if the cell type returned by {@link #getCellType()} is CellType.STRING
+ * @exception NumberFormatException if the cell value isn't a parsable <code>double</code>.
+ * @see org.apache.poi.ss.usermodel.DataFormatter for formatting this date into a string similar to how excel does.
+ */
+ @Override
+ public LocalDateTime getLocalDateTimeCellValue() {
+ if (getCellType() == CellType.BLANK) {
+ return null;
+ }
+
+ double value = getNumericCellValue();
+ boolean date1904 = getSheet().getWorkbook().isDate1904();
+ return DateUtil.getLocalDateTime(value, date1904);
+ }
+
/**
* Get the value of the cell as a XSSFRichTextString
* <p>
import java.text.DateFormat;
import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
return DateUtil.getJavaDate(value, date1904);
}
+ /**
+ * Get the value of the cell as a LocalDateTime.
+ * <p>
+ * For strings we throw an exception. For blank cells we return a null.
+ * </p>
+ * @return the value of the cell as a LocalDateTime
+ * @throws IllegalStateException if the cell type returned by {@link #getCellType()} is {@link CellType#STRING}
+ * @exception NumberFormatException if the cell value isn't a parsable <code>double</code>.
+ * @see DataFormatter for formatting this date into a string similar to how excel does.
+ */
+ @Override
+ public LocalDateTime getLocalDateTimeCellValue() {
+ if (getCellType() == CellType.BLANK) {
+ return null;
+ }
+
+ double value = getNumericCellValue();
+ boolean date1904 = getSheet().getWorkbook().isDate1904();
+ return DateUtil.getLocalDateTime(value, date1904);
+ }
+
/**
* {@inheritDoc}
*/
setCellValue(DateUtil.getExcelDate(value, date1904));
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void setCellValueImpl(LocalDateTime value) {
+ boolean date1904 = getSheet().getWorkbook().isDate1904();
+ setCellValue(DateUtil.getExcelDate(value, date1904));
+ }
+
/**
* {@inheritDoc}
*/
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
Cell cell = row.getCell(idxCell);
cell.getCellStyle().getDataFormatString();
if (cell.getCellType() == CellType.NUMERIC) {
- boolean isDate = HSSFDateUtil.isCellDateFormatted(cell);
+ boolean isDate = DateUtil.isCellDateFormatted(cell);
if (idxCell > 0 && isDate) {
fail("cell " + idxCell + " is not a date: " + idxCell);
}
c.setCellStyle(cellStyle);
// assertEquals("Checking hour = " + hour, date.getTime().getTime(),
- // HSSFDateUtil.getJavaDate(excelDate).getTime());
+ // DateUtil.getJavaDate(excelDate).getTime());
for (int k=1; k < 100; k++) {
r=s.createRow(k);
package org.apache.poi.hssf.usermodel;
-import static java.util.Calendar.AUGUST;
-import static java.util.Calendar.FEBRUARY;
-import static java.util.Calendar.JANUARY;
-import static java.util.Calendar.JULY;
-import static java.util.Calendar.MARCH;
-import static java.util.Calendar.MAY;
-import static java.util.Calendar.OCTOBER;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import java.io.IOException;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.Locale;
import java.util.TimeZone;
import org.apache.poi.hssf.HSSFTestDataSamples;
public static void resetTimeZone() {
LocaleUtil.setUserTimeZone(userTimeZone);
}
-
- /**
- * Checks the date conversion functions in the HSSFDateUtil class.
- */
- @Test
- public void dateConversion() {
-
- // Iteratating over the hours exposes any rounding issues.
- Calendar cal = LocaleUtil.getLocaleCalendar(2002,JANUARY,1,0,1,1);
- for (int hour = 0; hour < 23; hour++) {
- double excelDate = HSSFDateUtil.getExcelDate(cal.getTime(), false);
-
- assertEquals("Checking hour = " + hour, cal.getTime().getTime(),
- HSSFDateUtil.getJavaDate(excelDate, false).getTime());
-
- cal.add(Calendar.HOUR_OF_DAY, 1);
- }
-
- // check 1900 and 1904 date windowing conversions
- double excelDate = 36526.0;
- // with 1900 windowing, excelDate is Jan. 1, 2000
- // with 1904 windowing, excelDate is Jan. 2, 2004
- cal.set(2000,JANUARY,1,0,0,0); // Jan. 1, 2000
- Date dateIf1900 = cal.getTime();
- cal.add(Calendar.YEAR,4); // now Jan. 1, 2004
- cal.add(Calendar.DATE,1); // now Jan. 2, 2004
- Date dateIf1904 = cal.getTime();
- // 1900 windowing
- assertEquals("Checking 1900 Date Windowing",
- dateIf1900.getTime(),
- HSSFDateUtil.getJavaDate(excelDate,false).getTime());
- // 1904 windowing
- assertEquals("Checking 1904 Date Windowing",
- 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.
- */
- @Test
- public void excelConversionOnDSTStart() {
- Calendar cal = LocaleUtil.getLocaleCalendar(2004,MARCH,28,0,0,0);
- 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, false);
- 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, false).getTime());
- }
- }
-
- /**
- * Checks the conversion of an Excel date to a java.util.date on a day when
- * Daylight Saving Time starts.
- */
- @Test
- public void javaConversionOnDSTStart() {
- Calendar cal = LocaleUtil.getLocaleCalendar(2004,MARCH,28,0,0,0);
- double excelDate = HSSFDateUtil.getExcelDate(cal.getTime(), false);
- 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, false);
- double actDate = HSSFDateUtil.getExcelDate(javaDate, false);
- assertEquals("Checking " + hour + " hours on Daylight Saving Time start date",
- excelDate, actDate, oneMinute);
- }
- }
-
- /**
- * Checks the conversion of a java.util.Date to Excel on a day when
- * Daylight Saving Time ends.
- */
- @Test
- public void excelConversionOnDSTEnd() {
- Calendar cal = LocaleUtil.getLocaleCalendar(2004,OCTOBER,31,0,0,0);
- for (int hour = 0; hour < 24; hour++) {
- cal.set(Calendar.HOUR_OF_DAY, hour);
- Date javaDate = cal.getTime();
- double excelDate = HSSFDateUtil.getExcelDate(javaDate, false);
- 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, false).getTime());
- }
- }
-
- /**
- * Checks the conversion of an Excel date to java.util.Date on a day when
- * Daylight Saving Time ends.
- */
- @Test
- public void javaConversionOnDSTEnd() {
- Calendar cal = LocaleUtil.getLocaleCalendar(2004,OCTOBER,31,0,0,0);
- double excelDate = HSSFDateUtil.getExcelDate(cal.getTime(), false);
- 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, false);
- assertEquals("Checking " + hour + " hours on Daylight Saving Time start date",
- excelDate,
- HSSFDateUtil.getExcelDate(javaDate, false), oneMinute);
- }
- }
-
- /**
- * Tests that we deal with time-zones properly
- */
- @Test
- public void calendarConversion() {
- TimeZone userTZ = LocaleUtil.getUserTimeZone();
- LocaleUtil.setUserTimeZone(TimeZone.getTimeZone("CET"));
- try {
- Calendar cal = LocaleUtil.getLocaleCalendar(2002,JANUARY,1,12,1,1);
- Date expected = cal.getTime();
-
- // Iterating over the hours exposes any rounding issues.
- for (int hour = -12; hour <= 12; hour++)
- {
- String id = "GMT" + (hour < 0 ? "" : "+") + hour + ":00";
- cal.setTimeZone(TimeZone.getTimeZone(id));
- cal.set(Calendar.HOUR_OF_DAY, 12);
- double excelDate = HSSFDateUtil.getExcelDate(cal, false);
- Date javaDate = HSSFDateUtil.getJavaDate(excelDate);
-
- // Should match despite time-zone
- assertEquals("Checking timezone " + id, expected.getTime(), javaDate.getTime());
- }
-
- // Check that the timezone aware getter works correctly
- TimeZone cet = TimeZone.getTimeZone("Europe/Copenhagen");
- TimeZone ldn = TimeZone.getTimeZone("Europe/London");
-
- // 12:45 on 27th April 2012
- double excelDate = 41026.53125;
-
- // Same, no change
- assertEquals(
- HSSFDateUtil.getJavaDate(excelDate, false).getTime(),
- HSSFDateUtil.getJavaDate(excelDate, false, cet).getTime()
- );
-
- // London vs Copenhagen, should differ by an hour
- Date cetDate = HSSFDateUtil.getJavaDate(excelDate, false);
- Date ldnDate = HSSFDateUtil.getJavaDate(excelDate, false, ldn);
- assertEquals(ldnDate.getTime() - cetDate.getTime(), 60*60*1000);
- } finally {
- LocaleUtil.setUserTimeZone(userTZ);
- }
- }
-
- /**
- * Tests that we correctly detect date formats as such
- */
- @Test
- public void identifyDateFormats() {
- // First up, try with a few built in date formats
- short[] builtins = new short[] { 0x0e, 0x0f, 0x10, 0x16, 0x2d, 0x2e };
- for (short builtin : builtins) {
- String formatStr = HSSFDataFormat.getBuiltinFormat(builtin);
- assertTrue( HSSFDateUtil.isInternalDateFormat(builtin) );
- assertTrue( HSSFDateUtil.isADateFormat(builtin,formatStr) );
- }
-
- // Now try a few built-in non date formats
- builtins = new short[] { 0x01, 0x02, 0x17, 0x1f, 0x30 };
- for (short builtin : builtins) {
- String formatStr = HSSFDataFormat.getBuiltinFormat(builtin);
- assertFalse( HSSFDateUtil.isInternalDateFormat(builtin) );
- assertFalse( HSSFDateUtil.isADateFormat(builtin,formatStr) );
- }
-
- // Now for some non-internal ones
- // These come after the real ones
- int numBuiltins = HSSFDataFormat.getNumberOfBuiltinBuiltinFormats();
- assertTrue(numBuiltins < 60);
- short formatId = 60;
- assertFalse( HSSFDateUtil.isInternalDateFormat(formatId) );
-
- // Valid ones first
- String[] formats = new String[] {
- "yyyy-mm-dd", "yyyy/mm/dd", "yy/mm/dd", "yy/mmm/dd",
- "dd/mm/yy", "dd/mm/yyyy", "dd/mmm/yy",
- "dd-mm-yy", "dd-mm-yyyy",
- "DD-MM-YY", "DD-mm-YYYY",
- "dd\\-mm\\-yy", // Sometimes escaped
- "dd.mm.yyyy", "dd\\.mm\\.yyyy",
- "dd\\ mm\\.yyyy AM", "dd\\ mm\\.yyyy pm",
- "dd\\ mm\\.yyyy\\-dd", "[h]:mm:ss",
- "mm/dd/yy", "\"mm\"/\"dd\"/\"yy\"",
- "m\\/d\\/yyyy",
-
- // These crazy ones are valid
- "yyyy-mm-dd;@", "yyyy/mm/dd;@",
- "dd-mm-yy;@", "dd-mm-yyyy;@",
- // These even crazier ones are also valid
- // (who knows what they mean though...)
- "[$-F800]dddd\\,\\ mmm\\ dd\\,\\ yyyy",
- "[$-F900]ddd/mm/yyy",
- // These ones specify colours, who knew that was allowed?
- "[BLACK]dddd/mm/yy",
- "[yeLLow]yyyy-mm-dd"
- };
- for (String format : formats) {
- assertTrue(
- format + " is a date format",
- HSSFDateUtil.isADateFormat(formatId, format)
- );
- }
-
- // Then time based ones too
- formats = new String[] {
- "yyyy-mm-dd hh:mm:ss", "yyyy/mm/dd HH:MM:SS",
- "mm/dd HH:MM", "yy/mmm/dd SS",
- "mm/dd HH:MM AM", "mm/dd HH:MM am",
- "mm/dd HH:MM PM", "mm/dd HH:MM pm",
- "m/d/yy h:mm AM/PM",
- "hh:mm:ss", "hh:mm:ss.0", "mm:ss.0",
- //support elapsed time [h],[m],[s]
- "[hh]", "[mm]", "[ss]", "[SS]", "[red][hh]"
- };
- for (String format : formats) {
- assertTrue(
- format + " is a datetime format",
- HSSFDateUtil.isADateFormat(formatId, format)
- );
- }
-
- // Then invalid ones
- formats = new String[] {
- "yyyy*mm*dd",
- "0.0", "0.000",
- "0%", "0.0%",
- "[]Foo", "[BLACK]0.00%",
- "[ms]", "[Mh]",
- "", null
- };
- for (String format : formats) {
- assertFalse(
- format + " is not a date or datetime format",
- HSSFDateUtil.isADateFormat(formatId, format)
- );
- }
-
- // And these are ones we probably shouldn't allow,
- // but would need a better regexp
- formats = new String[] {
- "yyyy:mm:dd",
- };
- for (String format : formats) {
- // assertFalse( HSSFDateUtil.isADateFormat(formatId, formats[i]) );
- }
- }
/**
* Test that against a real, test file, we still do everything
style = cell.getCellStyle();
assertEquals(aug_10_2007, cell.getNumericCellValue(), 0.0001);
assertEquals("d-mmm-yy", style.getDataFormatString());
- assertTrue(HSSFDateUtil.isInternalDateFormat(style.getDataFormat()));
- assertTrue(HSSFDateUtil.isADateFormat(style.getDataFormat(), style.getDataFormatString()));
- assertTrue(HSSFDateUtil.isCellDateFormatted(cell));
+ assertTrue(DateUtil.isInternalDateFormat(style.getDataFormat()));
+ assertTrue(DateUtil.isADateFormat(style.getDataFormat(), style.getDataFormatString()));
+ assertTrue(DateUtil.isCellDateFormatted(cell));
row = sheet.getRow(1);
cell = row.getCell(1);
style = cell.getCellStyle();
assertEquals(aug_10_2007, cell.getNumericCellValue(), 0.0001);
- assertFalse(HSSFDateUtil.isInternalDateFormat(cell.getCellStyle().getDataFormat()));
- assertTrue(HSSFDateUtil.isADateFormat(style.getDataFormat(), style.getDataFormatString()));
- assertTrue(HSSFDateUtil.isCellDateFormatted(cell));
+ assertFalse(DateUtil.isInternalDateFormat(cell.getCellStyle().getDataFormat()));
+ assertTrue(DateUtil.isADateFormat(style.getDataFormat(), style.getDataFormatString()));
+ assertTrue(DateUtil.isCellDateFormatted(cell));
row = sheet.getRow(2);
cell = row.getCell(1);
style = cell.getCellStyle();
assertEquals(aug_10_2007, cell.getNumericCellValue(), 0.0001);
- assertTrue(HSSFDateUtil.isInternalDateFormat(cell.getCellStyle().getDataFormat()));
- assertTrue(HSSFDateUtil.isADateFormat(style.getDataFormat(), style.getDataFormatString()));
- assertTrue(HSSFDateUtil.isCellDateFormatted(cell));
+ assertTrue(DateUtil.isInternalDateFormat(cell.getCellStyle().getDataFormat()));
+ assertTrue(DateUtil.isADateFormat(style.getDataFormat(), style.getDataFormatString()));
+ assertTrue(DateUtil.isCellDateFormatted(cell));
row = sheet.getRow(3);
cell = row.getCell(1);
style = cell.getCellStyle();
assertEquals(aug_10_2007, cell.getNumericCellValue(), 0.0001);
- assertFalse(HSSFDateUtil.isInternalDateFormat(cell.getCellStyle().getDataFormat()));
- assertTrue(HSSFDateUtil.isADateFormat(style.getDataFormat(), style.getDataFormatString()));
- assertTrue(HSSFDateUtil.isCellDateFormatted(cell));
+ assertFalse(DateUtil.isInternalDateFormat(cell.getCellStyle().getDataFormat()));
+ assertTrue(DateUtil.isADateFormat(style.getDataFormat(), style.getDataFormatString()));
+ assertTrue(DateUtil.isCellDateFormatted(cell));
row = sheet.getRow(4);
cell = row.getCell(1);
style = cell.getCellStyle();
assertEquals(aug_10_2007, cell.getNumericCellValue(), 0.0001);
- assertFalse(HSSFDateUtil.isInternalDateFormat(cell.getCellStyle().getDataFormat()));
- assertTrue(HSSFDateUtil.isADateFormat(style.getDataFormat(), style.getDataFormatString()));
- assertTrue(HSSFDateUtil.isCellDateFormatted(cell));
-
- workbook.close();
- }
-
- @Test
- public void excelDateBorderCases() throws ParseException {
- SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd", Locale.ROOT);
- df.setTimeZone(LocaleUtil.getUserTimeZone());
-
- assertEquals(1.0, DateUtil.getExcelDate(df.parse("1900-01-01")), 0.00001);
- assertEquals(31.0, DateUtil.getExcelDate(df.parse("1900-01-31")), 0.00001);
- assertEquals(32.0, DateUtil.getExcelDate(df.parse("1900-02-01")), 0.00001);
- assertEquals(/* BAD_DATE! */ -1.0, DateUtil.getExcelDate(df.parse("1899-12-31")), 0.00001);
- }
-
- @Test
- public void dateBug_2Excel() {
- assertEquals(59.0, HSSFDateUtil.getExcelDate(createDate(1900, FEBRUARY, 28), false), 0.00001);
- assertEquals(61.0, HSSFDateUtil.getExcelDate(createDate(1900, MARCH, 1), false), 0.00001);
-
- assertEquals(37315.00, HSSFDateUtil.getExcelDate(createDate(2002, FEBRUARY, 28), false), 0.00001);
- assertEquals(37316.00, HSSFDateUtil.getExcelDate(createDate(2002, MARCH, 1), false), 0.00001);
- assertEquals(37257.00, HSSFDateUtil.getExcelDate(createDate(2002, JANUARY, 1), false), 0.00001);
- assertEquals(38074.00, HSSFDateUtil.getExcelDate(createDate(2004, MARCH, 28), false), 0.00001);
- }
-
- @Test
- public void dateBug_2Java() {
- assertEquals(createDate(1900, FEBRUARY, 28), HSSFDateUtil.getJavaDate(59.0, false));
- assertEquals(createDate(1900, MARCH, 1), HSSFDateUtil.getJavaDate(61.0, false));
-
- assertEquals(createDate(2002, FEBRUARY, 28), HSSFDateUtil.getJavaDate(37315.00, false));
- assertEquals(createDate(2002, MARCH, 1), HSSFDateUtil.getJavaDate(37316.00, false));
- assertEquals(createDate(2002, JANUARY, 1), HSSFDateUtil.getJavaDate(37257.00, false));
- assertEquals(createDate(2004, MARCH, 28), HSSFDateUtil.getJavaDate(38074.00, false));
- }
-
- @Test
- public void date1904() {
- assertEquals(createDate(1904, JANUARY, 2), HSSFDateUtil.getJavaDate(1.0, true));
- assertEquals(createDate(1904, JANUARY, 1), HSSFDateUtil.getJavaDate(0.0, true));
- assertEquals(0.0, HSSFDateUtil.getExcelDate(createDate(1904, JANUARY, 1), true), 0.00001);
- assertEquals(1.0, HSSFDateUtil.getExcelDate(createDate(1904, JANUARY, 2), true), 0.00001);
-
- assertEquals(createDate(1998, JULY, 5), HSSFDateUtil.getJavaDate(35981, false));
- assertEquals(createDate(1998, JULY, 5), HSSFDateUtil.getJavaDate(34519, true));
-
- assertEquals(35981.0, HSSFDateUtil.getExcelDate(createDate(1998, JULY, 5), false), 0.00001);
- assertEquals(34519.0, HSSFDateUtil.getExcelDate(createDate(1998, JULY, 5), true), 0.00001);
- }
-
- /**
- * @param month zero based
- * @param day one based
- */
- private static Date createDate(int year, int month, int day) {
- return createDate(year, month, day, 0, 0, 0);
- }
-
- /**
- * @param month zero based
- * @param day one based
- */
- private static Date createDate(int year, int month, int day, int hour, int minute, int second) {
- Calendar c = LocaleUtil.getLocaleCalendar(year, month, day, hour, minute, second);
- return c.getTime();
- }
-
- /**
- * Check if HSSFDateUtil.getAbsoluteDay works as advertised.
- */
- @Test
- public void absoluteDay() {
- // 1 Jan 1900 is 1 day after 31 Dec 1899
- Calendar cal = LocaleUtil.getLocaleCalendar(1900,JANUARY,1,0,0,0);
- assertEquals("Checking absolute day (1 Jan 1900)", 1, HSSFDateUtil.absoluteDay(cal, false));
- // 1 Jan 1901 is 366 days after 31 Dec 1899
- cal.set(1901,JANUARY,1,0,0,0);
- assertEquals("Checking absolute day (1 Jan 1901)", 366, HSSFDateUtil.absoluteDay(cal, false));
- }
-
- @Test
- public void absoluteDayYearTooLow() {
- Calendar cal = LocaleUtil.getLocaleCalendar(1899,JANUARY,1,0,0,0);
- try {
- HSSFDateUtil.absoluteDay(cal, false);
- fail("Should fail here");
- } catch (IllegalArgumentException e) {
- // expected here
- }
-
- try {
- cal.set(1903,JANUARY,1,0,0,0);
- HSSFDateUtil.absoluteDay(cal, true);
- fail("Should fail here");
- } catch (IllegalArgumentException e) {
- // expected here
- }
- }
+ assertFalse(DateUtil.isInternalDateFormat(cell.getCellStyle().getDataFormat()));
+ assertTrue(DateUtil.isADateFormat(style.getDataFormat(), style.getDataFormatString()));
+ assertTrue(DateUtil.isCellDateFormatted(cell));
- @Test
- public void convertTime() {
-
- final double delta = 1E-7; // a couple of digits more accuracy than strictly required
- assertEquals(0.5, HSSFDateUtil.convertTime("12:00"), delta);
- assertEquals(2.0/3, HSSFDateUtil.convertTime("16:00"), delta);
- assertEquals(0.0000116, HSSFDateUtil.convertTime("0:00:01"), delta);
- assertEquals(0.7330440, HSSFDateUtil.convertTime("17:35:35"), delta);
- }
-
- @Test
- public void parseDate() {
- assertEquals(createDate(2008, AUGUST, 3), HSSFDateUtil.parseYYYYMMDDDate("2008/08/03"));
- assertEquals(createDate(1994, MAY, 1), HSSFDateUtil.parseYYYYMMDDDate("1994/05/01"));
- }
-
- /**
- * Ensure that date values *with* a fractional portion get the right time of day
- */
- @Test
- public void convertDateTime() {
- // Excel day 30000 is date 18-Feb-1982
- // 0.7 corresponds to time 16:48:00
- Date actual = HSSFDateUtil.getJavaDate(30000.7);
- Date expected = createDate(1982, 1, 18, 16, 48, 0);
- assertEquals(expected, actual);
- }
-
- /**
- * User reported a datetime issue in POI-2.5:
- * Setting Cell's value to Jan 1, 1900 without a time doesn't return the same value set to
- * @throws IOException
- */
- @Test
- public void bug19172() throws IOException
- {
- HSSFWorkbook workbook = new HSSFWorkbook();
- HSSFSheet sheet = workbook.createSheet();
- HSSFCell cell = sheet.createRow(0).createCell(0);
-
- // A pseudo special Excel dates
- Calendar cal = LocaleUtil.getLocaleCalendar(1900, JANUARY, 1);
-
- Date valueToTest = cal.getTime();
-
- cell.setCellValue(valueToTest);
-
- Date returnedValue = cell.getDateCellValue();
-
- assertEquals(valueToTest.getTime(), returnedValue.getTime());
-
workbook.close();
}
-
- /**
- * DateUtil.isCellFormatted(Cell) should not true for a numeric cell
- * that's formatted as ".0000"
- */
- @Test
- public void bug54557() throws Exception {
- final String format = ".0000";
- boolean isDateFormat = HSSFDateUtil.isADateFormat(165, format);
-
- assertEquals(false, isDateFormat);
- }
-
- @Test
- public void bug56269() throws Exception {
- double excelFraction = 41642.45833321759d;
- Calendar calNoRound = HSSFDateUtil.getJavaCalendar(excelFraction, false);
- assertEquals(10, calNoRound.get(Calendar.HOUR));
- assertEquals(59, calNoRound.get(Calendar.MINUTE));
- assertEquals(59, calNoRound.get(Calendar.SECOND));
- Calendar calRound = HSSFDateUtil.getJavaCalendar(excelFraction, false, null, true);
- assertEquals(11, calRound.get(Calendar.HOUR));
- assertEquals(0, calRound.get(Calendar.MINUTE));
- assertEquals(0, calRound.get(Calendar.SECOND));
- }
}
import org.apache.poi.hssf.record.BOFRecord;
import org.apache.poi.hssf.record.EOFRecord;
import org.apache.poi.hssf.record.RecordBase;
+import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.util.LocaleUtil;
import org.junit.Test;
//System.out.println("first assertion for date");
Calendar calExp = LocaleUtil.getLocaleCalendar(2000, 0, 1, 10, 51, 2);
- Date dateAct = HSSFDateUtil.getJavaDate(firstCell.getNumericCellValue(), false);
+ Date dateAct = DateUtil.getJavaDate(firstCell.getNumericCellValue(), false);
assertEquals(calExp.getTime(), dateAct);
HSSFRow row = sheet.createRow(15);
HSSFCell cell = row.createCell(1);
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.eval.EvaluationException;
import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.util.LocaleUtil;
import org.junit.Test;
int month = getIntCell(row, yearColumn + 1);
int day = getIntCell(row, yearColumn + 2);
Calendar c = LocaleUtil.getLocaleCalendar(year, month-1, day);
- return HSSFDateUtil.getExcelDate(c.getTime());
+ return DateUtil.getExcelDate(c.getTime());
}
private static int getIntCell(HSSFRow row, int colIx) {
import java.util.Date;
import java.util.Locale;
-import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.formula.eval.BoolEval;
import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.util.LocaleUtil;
import org.junit.Test;
}
private static NumberEval convert(Date d) {
- return new NumberEval(HSSFDateUtil.getExcelDate(d));
+ return new NumberEval(DateUtil.getExcelDate(d));
}
}
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
assertProhibitedValueAccess(cell, CellType.BOOLEAN, CellType.STRING,
CellType.FORMULA, CellType.ERROR);
+ cell.setCellErrorValue(FormulaError.NA.getCode());
+ assertEquals(FormulaError.NA.getCode(), cell.getErrorCellValue());
+ assertEquals(CellType.ERROR, cell.getCellType());
+ assertProhibitedValueAccess(cell, CellType.NUMERIC, CellType.BOOLEAN,
+ CellType.FORMULA, CellType.STRING);
+
+ LocalDateTime ldt = DateUtil.toLocalDateTime(c);
+ cell.setCellValue(ldt);
+ assertEquals(ldt, cell.getLocalDateTimeCellValue());
+ assertEquals(CellType.NUMERIC, cell.getCellType());
+ assertProhibitedValueAccess(cell, CellType.BOOLEAN, CellType.STRING,
+ CellType.FORMULA, CellType.ERROR);
+
+ LocalDate ld = ldt.toLocalDate();
+ cell.setCellValue(ld);
+ assertEquals(ld, cell.getLocalDateTimeCellValue().toLocalDate());
+ assertEquals(CellType.NUMERIC, cell.getCellType());
+ assertProhibitedValueAccess(cell, CellType.BOOLEAN, CellType.STRING,
+ CellType.FORMULA, CellType.ERROR);
+
cell.setCellErrorValue(FormulaError.NA.getCode());
assertEquals(FormulaError.NA.getCode(), cell.getErrorCellValue());
assertEquals(CellType.ERROR, cell.getCellType());
package org.apache.poi.ss.usermodel;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static java.util.Calendar.*;
+import static org.junit.Assert.*;
+import static org.junit.Assert.fail;
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
+import java.util.Locale;
import java.util.TimeZone;
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.model.InternalWorkbook;
+import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.util.LocaleUtil;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
import org.junit.Test;
public class TestDateUtil {
+ static TimeZone userTimeZone;
+
+ @BeforeClass
+ public static void setCEST() {
+ userTimeZone = LocaleUtil.getUserTimeZone();
+ LocaleUtil.setUserTimeZone(TimeZone.getTimeZone("CEST"));
+ }
+
+ @AfterClass
+ public static void resetTimeZone() {
+ LocaleUtil.setUserTimeZone(userTimeZone);
+ }
+
@Test
public void getJavaDate_InvalidValue() {
double dateValue = -1;
assertEquals(expCal, actCal[2]);
assertEquals(expCal, actCal[3]);
}
+
+ @Test
+ public void getLocalDateTime_InvalidValue() {
+ double dateValue = -1;
+ TimeZone tz = LocaleUtil.getUserTimeZone();
+ boolean use1904windowing = false;
+ boolean roundSeconds = false;
+
+ assertEquals(null, DateUtil.getLocalDateTime(dateValue));
+ assertEquals(null, DateUtil.getLocalDateTime(dateValue, use1904windowing));
+ assertEquals(null, DateUtil.getLocalDateTime(dateValue, use1904windowing, roundSeconds));
+ }
+
+ @Test
+ public void getLocalDateTime_ValidValue() {
+ double dateValue = 0;
+ boolean use1904windowing = false;
+ boolean roundSeconds = false;
+
+ // note that the Date and Calendar examples use a zero day of month which is invalid in LocalDateTime
+ LocalDateTime date = LocalDateTime.of(1899, 12, 31, 0, 0);
+
+ assertEquals(date, DateUtil.getLocalDateTime(dateValue));
+ assertEquals(date, DateUtil.getLocalDateTime(dateValue, use1904windowing));
+ assertEquals(date, DateUtil.getLocalDateTime(dateValue, use1904windowing, roundSeconds));
+ }
@Test
public void isADateFormat() {
// Cell show "2016年12月8日"
assertTrue(DateUtil.isADateFormat(178, "[DBNum3][$-804]yyyy\"\u5e74\"m\"\u6708\"d\"\u65e5\";@"));
}
+ /**
+ * Checks the date conversion functions in the DateUtil class.
+ */
+ @Test
+ public void dateConversion() {
+
+ // Iteratating over the hours exposes any rounding issues.
+ Calendar cal = LocaleUtil.getLocaleCalendar(2002,JANUARY,1,0,1,1);
+ for (int hour = 0; hour < 24; hour++) {
+ double excelDate = DateUtil.getExcelDate(cal.getTime(), false);
+
+ assertEquals("getJavaDate: Checking hour = " + hour, cal.getTime().getTime(),
+ DateUtil.getJavaDate(excelDate, false).getTime());
+
+ LocalDateTime ldt = LocalDateTime.ofInstant(cal.toInstant(), cal.getTimeZone().toZoneId());
+ assertEquals("getLocalDateTime: Checking hour = " + hour, ldt,
+ DateUtil.getLocalDateTime(excelDate, false));
+
+ cal.add(Calendar.HOUR_OF_DAY, 1);
+ }
+
+ // check 1900 and 1904 date windowing conversions
+ double excelDate = 36526.0;
+ // with 1900 windowing, excelDate is Jan. 1, 2000
+ // with 1904 windowing, excelDate is Jan. 2, 2004
+ cal.set(2000,JANUARY,1,0,0,0); // Jan. 1, 2000
+ Date dateIf1900 = cal.getTime();
+ cal.add(Calendar.YEAR,4); // now Jan. 1, 2004
+ cal.add(Calendar.DATE,1); // now Jan. 2, 2004
+ Date dateIf1904 = cal.getTime();
+ // 1900 windowing
+ assertEquals("Checking 1900 Date Windowing",
+ dateIf1900.getTime(),
+ DateUtil.getJavaDate(excelDate,false).getTime());
+ // 1904 windowing
+ assertEquals("Checking 1904 Date Windowing",
+ dateIf1904.getTime(),
+ DateUtil.getJavaDate(excelDate,true).getTime());
+ // 1900 windowing (LocalDateTime)
+ assertEquals("Checking 1900 Date Windowing",
+ LocalDateTime.of(2000,1,1,0,0),
+ DateUtil.getLocalDateTime(excelDate,false));
+ // 1904 windowing (LocalDateTime)
+ assertEquals("Checking 1904 Date Windowing",
+ LocalDateTime.of(2004,1,2,0,0),
+ DateUtil.getLocalDateTime(excelDate,true));
+ }
+
+ /**
+ * Checks the conversion of a java.util.date to Excel on a day when
+ * Daylight Saving Time starts.
+ */
+ @Test
+ public void excelConversionOnDSTStart() {
+ Calendar cal = LocaleUtil.getLocaleCalendar(2004,MARCH,28,0,0,0);
+ 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 = DateUtil.getExcelDate(javaDate, false);
+ 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(),
+ DateUtil.getJavaDate(excelDate, false).getTime());
+
+ // perform the same checks with LocalDateTime
+ LocalDateTime localDate = LocalDateTime.of(2004,3,28,hour,0,0);
+ double excelLocalDate = DateUtil.getExcelDate(localDate, false);
+ double differenceLocalDate = excelLocalDate - Math.floor(excelLocalDate);
+ int differenceLocalDateInHours = (int) (differenceLocalDate * 24 * 60 + 0.5) / 60;
+
+ assertEquals("Checking " + hour + " hour on Daylight Saving Time start date (LocalDateTime)",
+ hour,
+ differenceLocalDateInHours);
+ assertEquals("Checking " + hour + " hour on Daylight Saving Time start date (LocalDateTime)",
+ localDate,
+ DateUtil.getLocalDateTime(excelLocalDate, false));
+ }
+ }
+
+ /**
+ * Checks the conversion of an Excel date to a java.util.date on a day when
+ * Daylight Saving Time starts.
+ */
+ @Test
+ public void javaConversionOnDSTStart() {
+ Calendar cal = LocaleUtil.getLocaleCalendar(2004,MARCH,28,0,0,0);
+ double excelDate = DateUtil.getExcelDate(cal.getTime(), false);
+ 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 = DateUtil.getJavaDate(excelDate, false);
+ double actDate = DateUtil.getExcelDate(javaDate, false);
+ assertEquals("Checking " + hour + " hours on Daylight Saving Time start date",
+ excelDate, actDate, oneMinute);
+
+ // perform the same check with LocalDateTime
+ cal.set(Calendar.HOUR_OF_DAY, hour);
+ LocalDateTime localDate = DateUtil.getLocalDateTime(excelDate, false);
+ double actLocalDate = DateUtil.getExcelDate(localDate, false);
+ assertEquals("Checking " + hour + " hours on Daylight Saving Time start date (LocalDateTime)",
+ excelDate, actLocalDate, oneMinute);
+ }
+ }
+
+ /**
+ * Checks the conversion of a java.util.Date to Excel on a day when
+ * Daylight Saving Time ends.
+ */
+ @Test
+ public void excelConversionOnDSTEnd() {
+ Calendar cal = LocaleUtil.getLocaleCalendar(2004,OCTOBER,31,0,0,0);
+ for (int hour = 0; hour < 24; hour++) {
+ cal.set(Calendar.HOUR_OF_DAY, hour);
+ Date javaDate = cal.getTime();
+ double excelDate = DateUtil.getExcelDate(javaDate, false);
+ 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(),
+ DateUtil.getJavaDate(excelDate, false).getTime());
+
+ // perform the same checks using LocalDateTime
+ LocalDateTime localDate = LocalDateTime.of(2004,10,31,hour,0,0);
+ double excelLocalDate = DateUtil.getExcelDate(localDate, false);
+ double differenceLocalDate = excelLocalDate - Math.floor(excelLocalDate);
+ int differenceLocalDateInHours = (int) (difference * 24 * 60 + 0.5) / 60;
+ assertEquals("Checking " + hour + " hour on Daylight Saving Time end date (LocalDateTime)",
+ hour,
+ differenceLocalDateInHours);
+ assertEquals("Checking " + hour + " hour on Daylight Saving Time start date (LocalDateTime)",
+ localDate,
+ DateUtil.getLocalDateTime(excelLocalDate, false));
+ }
+ }
+
+ /**
+ * Checks the conversion of an Excel date to java.util.Date on a day when
+ * Daylight Saving Time ends.
+ */
+ @Test
+ public void javaConversionOnDSTEnd() {
+ Calendar cal = LocaleUtil.getLocaleCalendar(2004,OCTOBER,31,0,0,0);
+ double excelDate = DateUtil.getExcelDate(cal.getTime(), false);
+ 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 = DateUtil.getJavaDate(excelDate, false);
+ assertEquals("Checking " + hour + " hours on Daylight Saving Time start date",
+ excelDate,
+ DateUtil.getExcelDate(javaDate, false), oneMinute);
+
+ // perform the same checks using LocalDateTime
+ LocalDateTime localDate = DateUtil.getLocalDateTime(excelDate, false);
+ assertEquals("Checking " + hour + " hours on Daylight Saving Time start date",
+ excelDate,
+ DateUtil.getExcelDate(localDate, false), oneMinute);
+ }
+ }
+
+ /**
+ * Tests that we deal with time-zones properly
+ */
+ @Test
+ public void calendarConversion() {
+ TimeZone userTZ = LocaleUtil.getUserTimeZone();
+ LocaleUtil.setUserTimeZone(TimeZone.getTimeZone("CET"));
+ try {
+ Calendar cal = LocaleUtil.getLocaleCalendar(2002,JANUARY,1,12,1,1);
+ Date expected = cal.getTime();
+
+ // Iterating over the hours exposes any rounding issues.
+ for (int hour = -12; hour <= 12; hour++)
+ {
+ String id = "GMT" + (hour < 0 ? "" : "+") + hour + ":00";
+ cal.setTimeZone(TimeZone.getTimeZone(id));
+ cal.set(Calendar.HOUR_OF_DAY, 12);
+ double excelDate = DateUtil.getExcelDate(cal, false);
+ Date javaDate = DateUtil.getJavaDate(excelDate);
+
+ // Should match despite time-zone
+ assertEquals("Checking timezone " + id, expected.getTime(), javaDate.getTime());
+ }
+
+ // Check that the timezone aware getter works correctly
+ TimeZone cet = TimeZone.getTimeZone("Europe/Copenhagen");
+ TimeZone ldn = TimeZone.getTimeZone("Europe/London");
+
+ // 12:45 on 27th April 2012
+ double excelDate = 41026.53125;
+
+ // Same, no change
+ assertEquals(
+ DateUtil.getJavaDate(excelDate, false).getTime(),
+ DateUtil.getJavaDate(excelDate, false, cet).getTime()
+ );
+
+ // London vs Copenhagen, should differ by an hour
+ Date cetDate = DateUtil.getJavaDate(excelDate, false);
+ Date ldnDate = DateUtil.getJavaDate(excelDate, false, ldn);
+ assertEquals(ldnDate.getTime() - cetDate.getTime(), 60*60*1000);
+ } finally {
+ LocaleUtil.setUserTimeZone(userTZ);
+ }
+ }
+
+ /**
+ * Tests that we correctly detect date formats as such
+ */
+ @Test
+ public void identifyDateFormats() {
+ // First up, try with a few built in date formats
+ short[] builtins = new short[] { 0x0e, 0x0f, 0x10, 0x16, 0x2d, 0x2e };
+ for (short builtin : builtins) {
+ String formatStr = HSSFDataFormat.getBuiltinFormat(builtin);
+ assertTrue( DateUtil.isInternalDateFormat(builtin) );
+ assertTrue( DateUtil.isADateFormat(builtin,formatStr) );
+ }
+
+ // Now try a few built-in non date formats
+ builtins = new short[] { 0x01, 0x02, 0x17, 0x1f, 0x30 };
+ for (short builtin : builtins) {
+ String formatStr = HSSFDataFormat.getBuiltinFormat(builtin);
+ assertFalse( DateUtil.isInternalDateFormat(builtin) );
+ assertFalse( DateUtil.isADateFormat(builtin,formatStr) );
+ }
+
+ // Now for some non-internal ones
+ // These come after the real ones
+ int numBuiltins = HSSFDataFormat.getNumberOfBuiltinBuiltinFormats();
+ assertTrue(numBuiltins < 60);
+ short formatId = 60;
+ assertFalse( DateUtil.isInternalDateFormat(formatId) );
+
+ // Valid ones first
+ String[] formats = new String[] {
+ "yyyy-mm-dd", "yyyy/mm/dd", "yy/mm/dd", "yy/mmm/dd",
+ "dd/mm/yy", "dd/mm/yyyy", "dd/mmm/yy",
+ "dd-mm-yy", "dd-mm-yyyy",
+ "DD-MM-YY", "DD-mm-YYYY",
+ "dd\\-mm\\-yy", // Sometimes escaped
+ "dd.mm.yyyy", "dd\\.mm\\.yyyy",
+ "dd\\ mm\\.yyyy AM", "dd\\ mm\\.yyyy pm",
+ "dd\\ mm\\.yyyy\\-dd", "[h]:mm:ss",
+ "mm/dd/yy", "\"mm\"/\"dd\"/\"yy\"",
+ "m\\/d\\/yyyy",
+
+ // These crazy ones are valid
+ "yyyy-mm-dd;@", "yyyy/mm/dd;@",
+ "dd-mm-yy;@", "dd-mm-yyyy;@",
+ // These even crazier ones are also valid
+ // (who knows what they mean though...)
+ "[$-F800]dddd\\,\\ mmm\\ dd\\,\\ yyyy",
+ "[$-F900]ddd/mm/yyy",
+ // These ones specify colours, who knew that was allowed?
+ "[BLACK]dddd/mm/yy",
+ "[yeLLow]yyyy-mm-dd"
+ };
+ for (String format : formats) {
+ assertTrue(
+ format + " is a date format",
+ DateUtil.isADateFormat(formatId, format)
+ );
+ }
+
+ // Then time based ones too
+ formats = new String[] {
+ "yyyy-mm-dd hh:mm:ss", "yyyy/mm/dd HH:MM:SS",
+ "mm/dd HH:MM", "yy/mmm/dd SS",
+ "mm/dd HH:MM AM", "mm/dd HH:MM am",
+ "mm/dd HH:MM PM", "mm/dd HH:MM pm",
+ "m/d/yy h:mm AM/PM",
+ "hh:mm:ss", "hh:mm:ss.0", "mm:ss.0",
+ //support elapsed time [h],[m],[s]
+ "[hh]", "[mm]", "[ss]", "[SS]", "[red][hh]"
+ };
+ for (String format : formats) {
+ assertTrue(
+ format + " is a datetime format",
+ DateUtil.isADateFormat(formatId, format)
+ );
+ }
+
+ // Then invalid ones
+ formats = new String[] {
+ "yyyy*mm*dd",
+ "0.0", "0.000",
+ "0%", "0.0%",
+ "[]Foo", "[BLACK]0.00%",
+ "[ms]", "[Mh]",
+ "", null
+ };
+ for (String format : formats) {
+ assertFalse(
+ format + " is not a date or datetime format",
+ DateUtil.isADateFormat(formatId, format)
+ );
+ }
+
+ // And these are ones we probably shouldn't allow,
+ // but would need a better regexp
+ formats = new String[] {
+ "yyyy:mm:dd",
+ };
+ for (String format : formats) {
+ // assertFalse( DateUtil.isADateFormat(formatId, formats[i]) );
+ }
+ }
+
+ @Test
+ public void excelDateBorderCases() throws ParseException {
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd", Locale.ROOT);
+ df.setTimeZone(LocaleUtil.getUserTimeZone());
+
+ Date date1 = df.parse("1900-01-01");
+ assertEquals(1.0, DateUtil.getExcelDate(date1), 0.00001);
+ assertEquals(1.0, DateUtil.getExcelDate(DateUtil.toLocalDateTime(date1)), 0.00001);
+ Date date31 = df.parse("1900-01-31");
+ assertEquals(31.0, DateUtil.getExcelDate(date31), 0.00001);
+ assertEquals(31.0, DateUtil.getExcelDate(DateUtil.toLocalDateTime(date31)), 0.00001);
+ Date date32 = df.parse("1900-02-01");
+ assertEquals(32.0, DateUtil.getExcelDate(date32), 0.00001);
+ assertEquals(32.0, DateUtil.getExcelDate(DateUtil.toLocalDateTime(date32)), 0.00001);
+ Date dateMinus1 = df.parse("1899-12-31");
+ assertEquals(/* BAD_DATE! */ -1.0, DateUtil.getExcelDate(dateMinus1), 0.00001);
+ assertEquals(/* BAD_DATE! */ -1.0, DateUtil.getExcelDate(DateUtil.toLocalDateTime(dateMinus1)), 0.00001);
+ }
+
+ @Test
+ public void dateBug_2Excel() {
+ assertEquals(59.0, DateUtil.getExcelDate(createDate(1900, FEBRUARY, 28), false), 0.00001);
+ assertEquals(61.0, DateUtil.getExcelDate(createDate(1900, MARCH, 1), false), 0.00001);
+
+ assertEquals(37315.00, DateUtil.getExcelDate(createDate(2002, FEBRUARY, 28), false), 0.00001);
+ assertEquals(37316.00, DateUtil.getExcelDate(createDate(2002, MARCH, 1), false), 0.00001);
+ assertEquals(37257.00, DateUtil.getExcelDate(createDate(2002, JANUARY, 1), false), 0.00001);
+ assertEquals(38074.00, DateUtil.getExcelDate(createDate(2004, MARCH, 28), false), 0.00001);
+
+ // perform the same checks using LocalDateTime
+ assertEquals(59.0, DateUtil.getExcelDate(LocalDateTime.of(1900, 2, 28, 0,0), false), 0.00001);
+ assertEquals(61.0, DateUtil.getExcelDate(LocalDateTime.of(1900, 3, 1, 0,0), false), 0.00001);
+
+ assertEquals(37315.00, DateUtil.getExcelDate(LocalDateTime.of(2002, 2, 28, 0,0), false), 0.00001);
+ assertEquals(37316.00, DateUtil.getExcelDate(LocalDateTime.of(2002, 3, 1, 0,0), false), 0.00001);
+ assertEquals(37257.00, DateUtil.getExcelDate(LocalDateTime.of(2002, 1, 1, 0,0), false), 0.00001);
+ assertEquals(38074.00, DateUtil.getExcelDate(LocalDateTime.of(2004, 3, 28, 0,0), false), 0.00001);
+ }
+
+ @Test
+ public void dateBug_2Java() {
+ assertEquals(createDate(1900, FEBRUARY, 28), DateUtil.getJavaDate(59.0, false));
+ assertEquals(createDate(1900, MARCH, 1), DateUtil.getJavaDate(61.0, false));
+
+ assertEquals(createDate(2002, FEBRUARY, 28), DateUtil.getJavaDate(37315.00, false));
+ assertEquals(createDate(2002, MARCH, 1), DateUtil.getJavaDate(37316.00, false));
+ assertEquals(createDate(2002, JANUARY, 1), DateUtil.getJavaDate(37257.00, false));
+ assertEquals(createDate(2004, MARCH, 28), DateUtil.getJavaDate(38074.00, false));
+
+ // perform the same checks using LocalDateTime
+ assertEquals(LocalDateTime.of(1900, 2, 28, 0, 0), DateUtil.getLocalDateTime(59.0, false));
+ assertEquals(LocalDateTime.of(1900, 3, 1, 0, 0), DateUtil.getLocalDateTime(61.0, false));
+
+ assertEquals(LocalDateTime.of(2002, 2, 28, 0, 0), DateUtil.getLocalDateTime(37315.00, false));
+ assertEquals(LocalDateTime.of(2002, 3, 1, 0, 0), DateUtil.getLocalDateTime(37316.00, false));
+ assertEquals(LocalDateTime.of(2002, 1, 1, 0, 0), DateUtil.getLocalDateTime(37257.00, false));
+ assertEquals(LocalDateTime.of(2004, 3, 28, 0, 0), DateUtil.getLocalDateTime(38074.00, false));
+ }
+
+ @Test
+ public void date1904() {
+ assertEquals(createDate(1904, JANUARY, 2), DateUtil.getJavaDate(1.0, true));
+ assertEquals(createDate(1904, JANUARY, 1), DateUtil.getJavaDate(0.0, true));
+ assertEquals(0.0, DateUtil.getExcelDate(createDate(1904, JANUARY, 1), true), 0.00001);
+ assertEquals(1.0, DateUtil.getExcelDate(createDate(1904, JANUARY, 2), true), 0.00001);
+
+ assertEquals(createDate(1998, JULY, 5), DateUtil.getJavaDate(35981, false));
+ assertEquals(createDate(1998, JULY, 5), DateUtil.getJavaDate(34519, true));
+
+ assertEquals(35981.0, DateUtil.getExcelDate(createDate(1998, JULY, 5), false), 0.00001);
+ assertEquals(34519.0, DateUtil.getExcelDate(createDate(1998, JULY, 5), true), 0.00001);
+
+ // perform the same checks using LocalDateTime
+ assertEquals(LocalDateTime.of(1904, 1, 2, 0, 0), DateUtil.getLocalDateTime(1.0, true));
+ assertEquals(LocalDateTime.of(1904, 1, 1, 0, 0), DateUtil.getLocalDateTime(0.0, true));
+ assertEquals(0.0, DateUtil.getExcelDate(LocalDateTime.of(1904, 1, 1, 0, 0), true), 0.00001);
+ assertEquals(1.0, DateUtil.getExcelDate(LocalDateTime.of(1904, 1, 2, 0, 0), true), 0.00001);
+
+ assertEquals(LocalDateTime.of(1998, 7, 5, 0, 0), DateUtil.getLocalDateTime(35981, false));
+ assertEquals(LocalDateTime.of(1998, 7, 5, 0, 0), DateUtil.getLocalDateTime(34519, true));
+
+ assertEquals(35981.0, DateUtil.getExcelDate(LocalDateTime.of(1998, 7, 5, 0, 0), false), 0.00001);
+ assertEquals(34519.0, DateUtil.getExcelDate(LocalDateTime.of(1998, 7, 5, 0, 0), true), 0.00001);
+ }
+
+ /**
+ * @param month zero based
+ * @param day one based
+ */
+ private static Date createDate(int year, int month, int day) {
+ return createDate(year, month, day, 0, 0, 0);
+ }
+
+ /**
+ * @param month zero based
+ * @param day one based
+ */
+ private static Date createDate(int year, int month, int day, int hour, int minute, int second) {
+ Calendar c = LocaleUtil.getLocaleCalendar(year, month, day, hour, minute, second);
+ return c.getTime();
+ }
+
+ /**
+ * Check if DateUtil.getAbsoluteDay works as advertised.
+ */
+ @Test
+ public void absoluteDay() {
+ // 1 Jan 1900 is 1 day after 31 Dec 1899
+ Calendar cal = LocaleUtil.getLocaleCalendar(1900,JANUARY,1,0,0,0);
+ assertEquals("Checking absolute day (1 Jan 1900)", 1, DateUtil.absoluteDay(cal, false));
+ LocalDateTime ldt = LocalDateTime.of(1900,1,1,0,0,0);
+ assertEquals("Checking absolute day (1 Jan 1900) (LocalDateTime)", 1, DateUtil.absoluteDay(ldt, false));
+ // 1 Jan 1901 is 366 days after 31 Dec 1899
+ ldt = LocalDateTime.of(1901,1,1,0,0,0);
+ cal.set(1901,JANUARY,1,0,0,0);
+ assertEquals("Checking absolute day (1 Jan 1901) (LocalDateTime)", 366, DateUtil.absoluteDay(ldt, false));
+ }
+
+ @Test
+ public void absoluteDayYearTooLow() {
+ Calendar cal = LocaleUtil.getLocaleCalendar(1899,JANUARY,1,0,0,0);
+ try {
+ DateUtil.absoluteDay(cal, false);
+ fail("Should fail here");
+ } catch (IllegalArgumentException e) {
+ // expected here
+ }
+
+ try {
+ cal.set(1903,JANUARY,1,0,0,0);
+ DateUtil.absoluteDay(cal, true);
+ fail("Should fail here");
+ } catch (IllegalArgumentException e) {
+ // expected here
+ }
+
+ // same for LocalDateTime
+ try {
+ DateUtil.absoluteDay(LocalDateTime.of(1899,1,1,0,0,0), false);
+ fail("Should fail here");
+ } catch (IllegalArgumentException e) {
+ // expected here
+ }
+
+ try {
+ DateUtil.absoluteDay(LocalDateTime.of(1903,1,1,0,0,0), true);
+ fail("Should fail here");
+ } catch (IllegalArgumentException e) {
+ // expected here
+ }
+ }
+
+ @Test
+ public void convertTime() {
+
+ final double delta = 1E-7; // a couple of digits more accuracy than strictly required
+ assertEquals(0.5, DateUtil.convertTime("12:00"), delta);
+ assertEquals(2.0/3, DateUtil.convertTime("16:00"), delta);
+ assertEquals(0.0000116, DateUtil.convertTime("0:00:01"), delta);
+ assertEquals(0.7330440, DateUtil.convertTime("17:35:35"), delta);
+ }
+
+ @Test
+ public void parseDate() {
+ assertEquals(createDate(2008, AUGUST, 3), DateUtil.parseYYYYMMDDDate("2008/08/03"));
+ assertEquals(createDate(1994, MAY, 1), DateUtil.parseYYYYMMDDDate("1994/05/01"));
+ }
+
+ /**
+ * Ensure that date values *with* a fractional portion get the right time of day
+ */
+ @Test
+ public void convertDateTime() {
+ // Excel day 30000 is date 18-Feb-1982
+ // 0.7 corresponds to time 16:48:00
+ Date actual = DateUtil.getJavaDate(30000.7);
+ Date expected = createDate(1982, 1, 18, 16, 48, 0);
+ assertEquals(expected, actual);
+
+ // note that months in Calendar are zero-based, in LocalDateTime one-based
+ LocalDateTime actualLocalDate = DateUtil.getLocalDateTime(30000.7);
+ LocalDateTime expectedLocalDate = LocalDateTime.of(1982, 2, 18, 16, 48, 0);
+ assertEquals(expectedLocalDate, actualLocalDate);
+ }
+
+ /**
+ * User reported a datetime issue in POI-2.5:
+ * Setting Cell's value to Jan 1, 1900 without a time doesn't return the same value set to
+ * @throws IOException
+ */
+ @Test
+ public void bug19172() throws IOException
+ {
+ HSSFWorkbook workbook = new HSSFWorkbook();
+ HSSFSheet sheet = workbook.createSheet();
+ HSSFCell cell = sheet.createRow(0).createCell(0);
+
+ // A pseudo special Excel dates
+ Calendar cal = LocaleUtil.getLocaleCalendar(1900, JANUARY, 1);
+
+ Date valueToTest = cal.getTime();
+
+ cell.setCellValue(valueToTest);
+
+ Date returnedValue = cell.getDateCellValue();
+
+ assertEquals(valueToTest.getTime(), returnedValue.getTime());
+
+ workbook.close();
+ }
+
+ /**
+ * DateUtil.isCellFormatted(Cell) should not true for a numeric cell
+ * that's formatted as ".0000"
+ */
+ @Test
+ public void bug54557() throws Exception {
+ final String format = ".0000";
+ boolean isDateFormat = DateUtil.isADateFormat(165, format);
+
+ assertEquals(false, isDateFormat);
+ }
+
+ @Test
+ public void bug56269() throws Exception {
+ double excelFraction = 41642.45833321759d;
+ Calendar calNoRound = DateUtil.getJavaCalendar(excelFraction, false);
+ assertEquals(10, calNoRound.get(Calendar.HOUR));
+ assertEquals(59, calNoRound.get(Calendar.MINUTE));
+ assertEquals(59, calNoRound.get(Calendar.SECOND));
+ Calendar calRound = DateUtil.getJavaCalendar(excelFraction, false, null, true);
+ assertEquals(11, calRound.get(Calendar.HOUR));
+ assertEquals(0, calRound.get(Calendar.MINUTE));
+ assertEquals(0, calRound.get(Calendar.SECOND));
+ }
}