mirror of
https://github.com/apache/poi.git
synced 2026-02-27 20:40:08 +08:00
JUnit5 test classes and methods should have default package visibility git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1885308 13f79535-47bb-0310-9956-ffa450edef68
717 lines
31 KiB
Java
717 lines
31 KiB
Java
/* ====================================================================
|
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
|
contributor license agreements. See the NOTICE file distributed with
|
|
this work for additional information regarding copyright ownership.
|
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
|
(the "License"); you may not use this file except in compliance with
|
|
the License. You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
==================================================================== */
|
|
|
|
package org.apache.poi.ss.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.jupiter.api.Assertions.assertEquals;
|
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
|
|
import java.io.IOException;
|
|
import java.text.ParseException;
|
|
import java.text.SimpleDateFormat;
|
|
import java.time.LocalDateTime;
|
|
import java.util.Calendar;
|
|
import java.util.Date;
|
|
import java.util.Locale;
|
|
import java.util.TimeZone;
|
|
|
|
import org.apache.poi.hssf.usermodel.HSSFCell;
|
|
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
|
|
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
|
import org.apache.poi.util.LocaleUtil;
|
|
import org.junit.jupiter.api.AfterAll;
|
|
import org.junit.jupiter.api.BeforeAll;
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
public class TestDateUtil {
|
|
|
|
static TimeZone userTimeZone;
|
|
|
|
@BeforeAll
|
|
public static void setCEST() {
|
|
userTimeZone = LocaleUtil.getUserTimeZone();
|
|
LocaleUtil.setUserTimeZone(TimeZone.getTimeZone("CEST"));
|
|
}
|
|
|
|
@AfterAll
|
|
public static void resetTimeZone() {
|
|
LocaleUtil.setUserTimeZone(userTimeZone);
|
|
}
|
|
|
|
@Test
|
|
void getJavaDate_InvalidValue() {
|
|
final double dateValue = -1;
|
|
final TimeZone tz = LocaleUtil.getUserTimeZone();
|
|
final boolean use1904windowing = false;
|
|
final boolean roundSeconds = false;
|
|
|
|
assertNull(DateUtil.getJavaDate(dateValue));
|
|
assertNull(DateUtil.getJavaDate(dateValue, tz));
|
|
assertNull(DateUtil.getJavaDate(dateValue, use1904windowing));
|
|
assertNull(DateUtil.getJavaDate(dateValue, use1904windowing, tz));
|
|
assertNull(DateUtil.getJavaDate(dateValue, use1904windowing, tz, roundSeconds));
|
|
}
|
|
|
|
@Test
|
|
void getJavaDate_ValidValue() {
|
|
final double dateValue = 0;
|
|
final TimeZone tz = LocaleUtil.getUserTimeZone();
|
|
final boolean use1904windowing = false;
|
|
final boolean roundSeconds = false;
|
|
|
|
Calendar calendar = LocaleUtil.getLocaleCalendar(1900, 0, 0);
|
|
Date date = calendar.getTime();
|
|
|
|
assertEquals(date, DateUtil.getJavaDate(dateValue));
|
|
assertEquals(date, DateUtil.getJavaDate(dateValue, tz));
|
|
assertEquals(date, DateUtil.getJavaDate(dateValue, use1904windowing));
|
|
assertEquals(date, DateUtil.getJavaDate(dateValue, use1904windowing, tz));
|
|
assertEquals(date, DateUtil.getJavaDate(dateValue, use1904windowing, tz, roundSeconds));
|
|
}
|
|
|
|
@Test
|
|
void getJavaCalendar_InvalidValue() {
|
|
final double dateValue = -1;
|
|
final TimeZone tz = LocaleUtil.getUserTimeZone();
|
|
final boolean use1904windowing = false;
|
|
final boolean roundSeconds = false;
|
|
|
|
assertNull(DateUtil.getJavaCalendar(dateValue));
|
|
assertNull(DateUtil.getJavaCalendar(dateValue, use1904windowing));
|
|
assertNull(DateUtil.getJavaCalendar(dateValue, use1904windowing, tz));
|
|
assertNull(DateUtil.getJavaCalendar(dateValue, use1904windowing, tz, roundSeconds));
|
|
}
|
|
|
|
@Test
|
|
void getJavaCalendar_ValidValue() {
|
|
final double dateValue = 0;
|
|
final TimeZone tz = LocaleUtil.getUserTimeZone();
|
|
final boolean use1904windowing = false;
|
|
final boolean roundSeconds = false;
|
|
|
|
Calendar expCal = LocaleUtil.getLocaleCalendar(1900, 0, 0);
|
|
|
|
Calendar[] actCal = {
|
|
DateUtil.getJavaCalendar(dateValue),
|
|
DateUtil.getJavaCalendar(dateValue, use1904windowing),
|
|
DateUtil.getJavaCalendar(dateValue, use1904windowing, tz),
|
|
DateUtil.getJavaCalendar(dateValue, use1904windowing, tz, roundSeconds)
|
|
};
|
|
assertEquals(expCal, actCal[0]);
|
|
assertEquals(expCal, actCal[1]);
|
|
assertEquals(expCal, actCal[2]);
|
|
assertEquals(expCal, actCal[3]);
|
|
}
|
|
|
|
@Test
|
|
void getLocalDateTime_InvalidValue() {
|
|
final double dateValue = -1;
|
|
final boolean use1904windowing = false;
|
|
final boolean roundSeconds = false;
|
|
|
|
assertNull(DateUtil.getLocalDateTime(dateValue));
|
|
assertNull(DateUtil.getLocalDateTime(dateValue, use1904windowing));
|
|
assertNull(DateUtil.getLocalDateTime(dateValue, use1904windowing, roundSeconds));
|
|
}
|
|
|
|
@Test
|
|
void getLocalDateTime_ValidValue() {
|
|
final double dateValue = 0;
|
|
final boolean use1904windowing = false;
|
|
final 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
|
|
void isADateFormat() {
|
|
// Cell content 2016-12-8 as an example
|
|
// Cell show "12/8/2016"
|
|
assertTrue(DateUtil.isADateFormat(14, "m/d/yy"));
|
|
// Cell show "Thursday, December 8, 2016"
|
|
assertTrue(DateUtil.isADateFormat(182, "[$-F800]dddd\\,\\ mmmm\\ dd\\,\\ yyyy"));
|
|
// Cell show "12/8"
|
|
assertTrue(DateUtil.isADateFormat(183, "m/d;@"));
|
|
// Cell show "12/08/16"
|
|
assertTrue(DateUtil.isADateFormat(184, "mm/dd/yy;@"));
|
|
// Cell show "8-Dec-16"
|
|
assertTrue(DateUtil.isADateFormat(185, "[$-409]d\\-mmm\\-yy;@"));
|
|
// Cell show "D-16"
|
|
assertTrue(DateUtil.isADateFormat(186, "[$-409]mmmmm\\-yy;@"));
|
|
|
|
// Cell show "2016年12月8日"
|
|
assertTrue(DateUtil.isADateFormat(165, "yyyy\"\u5e74\"m\"\u6708\"d\"\u65e5\";@"));
|
|
// Cell show "2016年12月"
|
|
assertTrue(DateUtil.isADateFormat(164, "yyyy\"\u5e74\"m\"\u6708\";@"));
|
|
// Cell show "12月8日"
|
|
assertTrue(DateUtil.isADateFormat(168, "m\"\u6708\"d\"\u65e5\";@"));
|
|
// Cell show "十二月八日"
|
|
assertTrue(DateUtil.isADateFormat(181, "[DBNum1][$-404]m\"\u6708\"d\"\u65e5\";@"));
|
|
// Cell show "贰零壹陆年壹拾贰月捌日"
|
|
assertTrue(DateUtil.isADateFormat(177, "[DBNum2][$-804]yyyy\"\u5e74\"m\"\u6708\"d\"\u65e5\";@"));
|
|
// 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
|
|
void dateConversion() {
|
|
|
|
// Iterating 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(cal.getTime().getTime(), DateUtil.getJavaDate(excelDate, false).getTime(),
|
|
"getJavaDate: Checking hour = " + hour);
|
|
|
|
LocalDateTime ldt = LocalDateTime.ofInstant(cal.toInstant(), cal.getTimeZone().toZoneId());
|
|
assertEquals(ldt, DateUtil.getLocalDateTime(excelDate, false),
|
|
"getLocalDateTime: Checking hour = " + hour);
|
|
|
|
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(dateIf1900.getTime(), DateUtil.getJavaDate(excelDate,false).getTime(),
|
|
"Checking 1900 Date Windowing");
|
|
// 1904 windowing
|
|
assertEquals(dateIf1904.getTime(), DateUtil.getJavaDate(excelDate,true).getTime(),
|
|
"Checking 1904 Date Windowing");
|
|
// 1900 windowing (LocalDateTime)
|
|
assertEquals(LocalDateTime.of(2000,1,1,0,0), DateUtil.getLocalDateTime(excelDate,false),
|
|
"Checking 1900 Date Windowing");
|
|
// 1904 windowing (LocalDateTime)
|
|
assertEquals(LocalDateTime.of(2004,1,2,0,0), DateUtil.getLocalDateTime(excelDate,true),
|
|
"Checking 1904 Date Windowing");
|
|
}
|
|
|
|
/**
|
|
* Checks the conversion of a java.util.date to Excel on a day when
|
|
* Daylight Saving Time starts.
|
|
*/
|
|
@Test
|
|
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(hour, differenceInHours, "Checking " + hour + " hour on Daylight Saving Time start date");
|
|
assertEquals(javaDate.getTime(), DateUtil.getJavaDate(excelDate, false).getTime(),
|
|
"Checking " + hour + " hour on Daylight Saving Time start date");
|
|
|
|
// 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(hour, differenceLocalDateInHours,
|
|
"Checking " + hour + " hour on Daylight Saving Time start date (LocalDateTime)");
|
|
assertEquals(localDate, DateUtil.getLocalDateTime(excelLocalDate, false),
|
|
"Checking " + hour + " hour on Daylight Saving Time start date (LocalDateTime)");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks the conversion of an Excel date to a java.util.date on a day when
|
|
* Daylight Saving Time starts.
|
|
*/
|
|
@Test
|
|
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(excelDate, actDate, oneMinute,
|
|
"Checking " + hour + " hours on Daylight Saving Time start date");
|
|
|
|
// 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(excelDate, actLocalDate, oneMinute,
|
|
"Checking " + hour + " hours on Daylight Saving Time start date (LocalDateTime)");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks the conversion of a java.util.Date to Excel on a day when
|
|
* Daylight Saving Time ends.
|
|
*/
|
|
@Test
|
|
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(hour, differenceInHours,
|
|
"Checking " + hour + " hour on Daylight Saving Time end date");
|
|
assertEquals(javaDate.getTime(), DateUtil.getJavaDate(excelDate, false).getTime(),
|
|
"Checking " + hour + " hour on Daylight Saving Time start date");
|
|
|
|
// perform the same checks using LocalDateTime
|
|
LocalDateTime localDate = LocalDateTime.of(2004,10,31,hour,0,0);
|
|
double excelLocalDate = DateUtil.getExcelDate(localDate, false);
|
|
int differenceLocalDateInHours = (int) (difference * 24 * 60 + 0.5) / 60;
|
|
assertEquals(hour, differenceLocalDateInHours,
|
|
"Checking " + hour + " hour on Daylight Saving Time end date (LocalDateTime)");
|
|
assertEquals(localDate, DateUtil.getLocalDateTime(excelLocalDate, false),
|
|
"Checking " + hour + " hour on Daylight Saving Time start date (LocalDateTime)");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks the conversion of an Excel date to java.util.Date on a day when
|
|
* Daylight Saving Time ends.
|
|
*/
|
|
@Test
|
|
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(excelDate, DateUtil.getExcelDate(javaDate, false), oneMinute,
|
|
"Checking " + hour + " hours on Daylight Saving Time start date");
|
|
|
|
// perform the same checks using LocalDateTime
|
|
LocalDateTime localDate = DateUtil.getLocalDateTime(excelDate, false);
|
|
assertEquals(excelDate, DateUtil.getExcelDate(localDate, false), oneMinute,
|
|
"Checking " + hour + " hours on Daylight Saving Time start date");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Tests that we deal with time-zones properly
|
|
*/
|
|
@Test
|
|
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(expected.getTime(), javaDate.getTime(), "Checking timezone " + id);
|
|
}
|
|
|
|
// 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
|
|
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(DateUtil.isADateFormat(formatId, format), format + " is a date 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(DateUtil.isADateFormat(formatId, format), format + " is a datetime 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(DateUtil.isADateFormat(formatId, format), format + " is not a date or datetime 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, format) );
|
|
// }
|
|
}
|
|
|
|
@Test
|
|
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
|
|
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
|
|
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
|
|
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);
|
|
}
|
|
|
|
/**
|
|
* @param month zero based
|
|
* @param day one based
|
|
*/
|
|
private static Date createDate(int year, int month, int day, int hour, int minute) {
|
|
Calendar c = LocaleUtil.getLocaleCalendar(year, month, day, hour, minute, 0);
|
|
return c.getTime();
|
|
}
|
|
|
|
/**
|
|
* Check if DateUtil.getAbsoluteDay works as advertised.
|
|
*/
|
|
@Test
|
|
void absoluteDay() {
|
|
// 1 Jan 1900 is 1 day after 31 Dec 1899
|
|
Calendar cal = LocaleUtil.getLocaleCalendar(1900,JANUARY,1,0,0,0);
|
|
assertEquals(1, DateUtil.absoluteDay(cal, false), "Checking absolute day (1 Jan 1900)");
|
|
LocalDateTime ldt = LocalDateTime.of(1900,1,1,0,0,0);
|
|
assertEquals(1, DateUtil.absoluteDay(ldt, false), "Checking absolute day (1 Jan 1900) (LocalDateTime)");
|
|
// 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(366, DateUtil.absoluteDay(ldt, false), "Checking absolute day (1 Jan 1901) (LocalDateTime)");
|
|
}
|
|
|
|
@Test
|
|
void absoluteDayYearTooLow() {
|
|
Calendar cal = LocaleUtil.getLocaleCalendar(1899,JANUARY,1,0,0,0);
|
|
assertThrows(IllegalArgumentException.class, () -> DateUtil.absoluteDay(cal, false));
|
|
|
|
cal.set(1903,JANUARY,1,0,0,0);
|
|
assertThrows(IllegalArgumentException.class, () -> DateUtil.absoluteDay(cal, true));
|
|
|
|
// same for LocalDateTime
|
|
assertThrows(IllegalArgumentException.class, () -> DateUtil.absoluteDay(LocalDateTime.of(1899,1,1,0,0,0), false));
|
|
assertThrows(IllegalArgumentException.class, () -> DateUtil.absoluteDay(LocalDateTime.of(1903,1,1,0,0,0), true));
|
|
}
|
|
|
|
@Test
|
|
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
|
|
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
|
|
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);
|
|
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
|
|
*/
|
|
@Test
|
|
void bug19172() throws IOException {
|
|
try (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());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* DateUtil.isCellFormatted(Cell) should not true for a numeric cell
|
|
* that's formatted as ".0000"
|
|
*/
|
|
@Test
|
|
void bug54557() {
|
|
final String format = ".0000";
|
|
boolean isDateFormat = DateUtil.isADateFormat(165, format);
|
|
|
|
assertFalse(isDateFormat);
|
|
}
|
|
|
|
@Test
|
|
void bug56269() {
|
|
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);
|
|
assertNotNull(calRound);
|
|
assertEquals(11, calRound.get(Calendar.HOUR));
|
|
assertEquals(0, calRound.get(Calendar.MINUTE));
|
|
assertEquals(0, calRound.get(Calendar.SECOND));
|
|
|
|
LocalDateTime ldtNoRound = DateUtil.getLocalDateTime(excelFraction, false);
|
|
assertEquals(10, ldtNoRound.getHour());
|
|
assertEquals(59, ldtNoRound.getMinute());
|
|
assertEquals(59, ldtNoRound.getSecond());
|
|
LocalDateTime ldtRound = DateUtil.getLocalDateTime(excelFraction, false, true);
|
|
assertNotNull(ldtRound);
|
|
assertEquals(11, ldtRound.getHour());
|
|
assertEquals(0, ldtRound.getMinute());
|
|
assertEquals(0, ldtRound.getSecond());
|
|
}
|
|
}
|