Skip to content

Commit 3afdea9

Browse files
authored
Merge pull request #3986 from alibaba/bugfix
Bugfix
2 parents c42183d + 4826273 commit 3afdea9

File tree

6 files changed

+120
-7
lines changed

6 files changed

+120
-7
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析
3333
<dependency>
3434
<groupId>com.alibaba</groupId>
3535
<artifactId>easyexcel</artifactId>
36-
<version>4.0.2</version>
36+
<version>4.0.3</version>
3737
</dependency>
3838
```
3939

easyexcel-core/src/main/java/com/alibaba/excel/util/DateUtils.java

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
/* ====================================================================
2+
Licensed to the Apache Software Foundation (ASF) under one or more
3+
contributor license agreements. See the NOTICE file distributed with
4+
this work for additional information regarding copyright ownership.
5+
The ASF licenses this file to You under the Apache License, Version 2.0
6+
(the "License"); you may not use this file except in compliance with
7+
the License. You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
==================================================================== */
17+
118
package com.alibaba.excel.util;
219

320
import java.math.BigDecimal;
@@ -9,13 +26,16 @@
926
import java.time.LocalTime;
1027
import java.time.ZoneId;
1128
import java.time.format.DateTimeFormatter;
29+
import java.util.Calendar;
1230
import java.util.Date;
1331
import java.util.HashMap;
1432
import java.util.Locale;
1533
import java.util.Map;
34+
import java.util.TimeZone;
1635
import java.util.regex.Pattern;
1736

1837
import org.apache.poi.ss.usermodel.DateUtil;
38+
import org.apache.poi.util.LocaleUtil;
1939

2040
/**
2141
* Date utils
@@ -63,6 +83,15 @@ public class DateUtils {
6383

6484
public static String defaultLocalDateFormat = DATE_FORMAT_10;
6585

86+
public static final int SECONDS_PER_MINUTE = 60;
87+
public static final int MINUTES_PER_HOUR = 60;
88+
public static final int HOURS_PER_DAY = 24;
89+
public static final int SECONDS_PER_DAY = (HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
90+
91+
// used to specify that date is invalid
92+
private static final int BAD_DATE = -1;
93+
public static final long DAY_MILLISECONDS = SECONDS_PER_DAY * 1000L;
94+
6695
private DateUtils() {}
6796

6897
/**
@@ -301,13 +330,75 @@ private static DateFormat getCacheDateFormat(String dateFormat) {
301330
* @return Java representation of the date, or null if date is not a valid Excel date
302331
*/
303332
public static Date getJavaDate(double date, boolean use1904windowing) {
304-
//To calculate the Date, in the use of `org.apache.poi.ss.usermodel.DateUtil.getJavaDate(double, boolean,
305-
// java.util.TimeZone, boolean), Date when similar `2023-01-01 00:00:00.500`, returns the`2023-01-01
306-
// 00:00:01`, but excel in fact shows the `2023-01-01 00:00:00`.
307-
// `org.apache.poi.ss.usermodel.DateUtil.getLocalDateTime(double, boolean, boolean)` There is no problem.
308-
return Date.from(getLocalDateTime(date, use1904windowing).atZone(ZoneId.systemDefault()).toInstant());
333+
Calendar calendar = getJavaCalendar(date, use1904windowing, null, true);
334+
return calendar == null ? null : calendar.getTime();
309335
}
310336

337+
/**
338+
* Get EXCEL date as Java Calendar with given time zone.
339+
* @param date The Excel date.
340+
* @param use1904windowing true if date uses 1904 windowing,
341+
* or false if using 1900 date windowing.
342+
* @param timeZone The TimeZone to evaluate the date in
343+
* @param roundSeconds round to closest second
344+
* @return Java representation of the date, or null if date is not a valid Excel date
345+
*/
346+
public static Calendar getJavaCalendar(double date, boolean use1904windowing, TimeZone timeZone, boolean roundSeconds) {
347+
if (!isValidExcelDate(date)) {
348+
return null;
349+
}
350+
int wholeDays = (int)Math.floor(date);
351+
int millisecondsInDay = (int)((date - wholeDays) * DAY_MILLISECONDS + 0.5);
352+
Calendar calendar;
353+
if (timeZone != null) {
354+
calendar = LocaleUtil.getLocaleCalendar(timeZone);
355+
} else {
356+
calendar = LocaleUtil.getLocaleCalendar(); // using default time-zone
357+
}
358+
setCalendar(calendar, wholeDays, millisecondsInDay, use1904windowing, roundSeconds);
359+
return calendar;
360+
}
361+
362+
363+
public static void setCalendar(Calendar calendar, int wholeDays,
364+
int millisecondsInDay, boolean use1904windowing, boolean roundSeconds) {
365+
int startYear = 1900;
366+
int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it isn't
367+
if (use1904windowing) {
368+
startYear = 1904;
369+
dayAdjust = 1; // 1904 date windowing uses 1/2/1904 as the first day
370+
}
371+
else if (wholeDays < 61) {
372+
// Date is prior to 3/1/1900, so adjust because Excel thinks 2/29/1900 exists
373+
// If Excel date == 2/29/1900, will become 3/1/1900 in Java representation
374+
dayAdjust = 0;
375+
}
376+
calendar.set(startYear, Calendar.JANUARY, wholeDays + dayAdjust, 0, 0, 0);
377+
calendar.set(Calendar.MILLISECOND, millisecondsInDay);
378+
if (calendar.get(Calendar.MILLISECOND) == 0) {
379+
calendar.clear(Calendar.MILLISECOND);
380+
}
381+
if (roundSeconds) {
382+
// This is different from poi where you need to change 500 to 499
383+
calendar.add(Calendar.MILLISECOND, 499);
384+
calendar.clear(Calendar.MILLISECOND);
385+
}
386+
}
387+
388+
389+
/**
390+
* Given a double, checks if it is a valid Excel date.
391+
*
392+
* @return true if valid
393+
* @param value the double value
394+
*/
395+
396+
public static boolean isValidExcelDate(double value)
397+
{
398+
return (value > -Double.MIN_VALUE);
399+
}
400+
401+
311402
/**
312403
* Given an Excel date with either 1900 or 1904 date windowing,
313404
* converts it to a java.time.LocalDateTime.

easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
import java.io.File;
44
import java.util.List;
55
import java.util.Locale;
6+
import java.util.Map;
67
import java.util.Objects;
78

89
import com.alibaba.easyexcel.test.util.TestFileUtil;
910
import com.alibaba.excel.EasyExcel;
11+
import com.alibaba.fastjson2.JSON;
1012

1113
import lombok.extern.slf4j.Slf4j;
1214
import org.junit.jupiter.api.Assertions;
@@ -22,13 +24,16 @@
2224
@Slf4j
2325
public class DateFormatTest {
2426

27+
private static File file07V2;
2528
private static File file07;
2629
private static File file03;
2730

2831
@BeforeAll
2932
public static void init() {
3033
file07 = TestFileUtil.readFile("dataformat" + File.separator + "dataformat.xlsx");
3134
file03 = TestFileUtil.readFile("dataformat" + File.separator + "dataformat.xls");
35+
file07V2 = TestFileUtil.readFile("dataformat" + File.separator + "dataformatv2.xlsx");
36+
3237
}
3338

3439
@Test
@@ -43,6 +48,19 @@ public void t02Read03() {
4348
readUs(file03);
4449
}
4550

51+
@Test
52+
public void t03Read() {
53+
List<Map<Integer, String>> dataMap = EasyExcel.read(file07V2).headRowNumber(0).doReadAllSync();
54+
log.info("dataMap:{}", JSON.toJSONString(dataMap));
55+
Assertions.assertEquals("15:00", dataMap.get(0).get(0));
56+
Assertions.assertEquals("2023-1-01 00:00:00", dataMap.get(1).get(0));
57+
Assertions.assertEquals("2023-1-01 00:00:00", dataMap.get(2).get(0));
58+
Assertions.assertEquals("2023-1-01 00:00:01", dataMap.get(3).get(0));
59+
Assertions.assertEquals("2023-1-01 00:00:00", dataMap.get(4).get(0));
60+
Assertions.assertEquals("2023-1-01 00:00:00", dataMap.get(5).get(0));
61+
Assertions.assertEquals("2023-1-01 00:00:01", dataMap.get(6).get(0));
62+
}
63+
4664
private void readCn(File file) {
4765
List<DateFormatData> list =
4866
EasyExcel.read(file, DateFormatData.class, null).locale(Locale.CHINA).sheet().doReadSync();
Binary file not shown.

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121

2222
<properties>
23-
<revision>4.0.2</revision>
23+
<revision>4.0.3</revision>
2424
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
2525
<jdk.version>1.8</jdk.version>
2626
<gpg.skip>true</gpg.skip>

update.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 4.0.3
2+
3+
* 兼容部分日期格式读取异常的问题
4+
15
# 4.0.2
26

37
* 兼容某些特殊的xls: 修改了内置的样式导致判断样式错误

0 commit comments

Comments
 (0)