From fab7653cd42256adefad49ce6c2624bed3e0f0f1 Mon Sep 17 00:00:00 2001
From: Jiaju Zhuang <zhuangjiaju@qq.com>
Date: Wed, 11 Sep 2024 20:30:11 +0800
Subject: [PATCH 1/2] # 4.0.2
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* 兼容部分日期格式读取异常的问题
---
 README.md                                     |   2 +-
 .../com/alibaba/excel/util/DateUtils.java     | 101 +++++++++++++++++-
 .../test/core/dataformat/DateFormatTest.java  |  15 +++
 .../resources/dataformat/dataformatv2.xlsx    | Bin 0 -> 8782 bytes
 pom.xml                                       |   2 +-
 update.md                                     |   4 +
 6 files changed, 117 insertions(+), 7 deletions(-)
 create mode 100644 easyexcel-test/src/test/resources/dataformat/dataformatv2.xlsx

diff --git a/README.md b/README.md
index 7fef9d91a..25bd3be33 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析
 <dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>easyexcel</artifactId>
-    <version>4.0.2</version>
+    <version>4.0.3</version>
 </dependency>
 ```
 
diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/util/DateUtils.java b/easyexcel-core/src/main/java/com/alibaba/excel/util/DateUtils.java
index 3184d0875..035b984c4 100644
--- a/easyexcel-core/src/main/java/com/alibaba/excel/util/DateUtils.java
+++ b/easyexcel-core/src/main/java/com/alibaba/excel/util/DateUtils.java
@@ -1,3 +1,20 @@
+/* ====================================================================
+   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 com.alibaba.excel.util;
 
 import java.math.BigDecimal;
@@ -9,13 +26,16 @@
 import java.time.LocalTime;
 import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
+import java.util.Calendar;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
+import java.util.TimeZone;
 import java.util.regex.Pattern;
 
 import org.apache.poi.ss.usermodel.DateUtil;
+import org.apache.poi.util.LocaleUtil;
 
 /**
  * Date utils
@@ -63,6 +83,15 @@ public class DateUtils {
 
     public static String defaultLocalDateFormat = DATE_FORMAT_10;
 
+    public static final int SECONDS_PER_MINUTE = 60;
+    public static final int MINUTES_PER_HOUR = 60;
+    public static final int HOURS_PER_DAY = 24;
+    public static final int SECONDS_PER_DAY = (HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
+
+    // used to specify that date is invalid
+    private static final int BAD_DATE         = -1;
+    public static final long DAY_MILLISECONDS = SECONDS_PER_DAY * 1000L;
+
     private DateUtils() {}
 
     /**
@@ -301,13 +330,75 @@ private static DateFormat getCacheDateFormat(String dateFormat) {
      * @return Java representation of the date, or null if date is not a valid Excel date
      */
     public static Date getJavaDate(double date, boolean use1904windowing) {
-        //To calculate the Date, in the use of `org.apache.poi.ss.usermodel.DateUtil.getJavaDate(double, boolean,
-        // java.util.TimeZone, boolean), Date when similar `2023-01-01 00:00:00.500`, returns the`2023-01-01
-        // 00:00:01`, but excel in fact shows the `2023-01-01 00:00:00`.
-        // `org.apache.poi.ss.usermodel.DateUtil.getLocalDateTime(double, boolean, boolean)` There is no problem.
-        return Date.from(getLocalDateTime(date, use1904windowing).atZone(ZoneId.systemDefault()).toInstant());
+        Calendar calendar = getJavaCalendar(date, use1904windowing, null, true);
+        return calendar == null ? null : calendar.getTime();
     }
 
+    /**
+     * Get EXCEL date as Java Calendar with given time zone.
+     * @param date  The Excel date.
+     * @param use1904windowing  true if date uses 1904 windowing,
+     *  or false if using 1900 date windowing.
+     * @param timeZone The TimeZone to evaluate the date in
+     * @param roundSeconds round to closest second
+     * @return Java representation of the date, or null if date is not a valid Excel date
+     */
+    public static Calendar getJavaCalendar(double date, boolean use1904windowing, TimeZone timeZone, boolean roundSeconds) {
+        if (!isValidExcelDate(date)) {
+            return null;
+        }
+        int wholeDays = (int)Math.floor(date);
+        int millisecondsInDay = (int)((date - wholeDays) * DAY_MILLISECONDS + 0.5);
+        Calendar calendar;
+        if (timeZone != null) {
+            calendar = LocaleUtil.getLocaleCalendar(timeZone);
+        } else {
+            calendar = LocaleUtil.getLocaleCalendar(); // using default time-zone
+        }
+        setCalendar(calendar, wholeDays, millisecondsInDay, use1904windowing, roundSeconds);
+        return calendar;
+    }
+
+
+    public static void setCalendar(Calendar calendar, int wholeDays,
+        int millisecondsInDay, boolean use1904windowing, boolean roundSeconds) {
+        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;
+        }
+        calendar.set(startYear, Calendar.JANUARY, wholeDays + dayAdjust, 0, 0, 0);
+        calendar.set(Calendar.MILLISECOND, millisecondsInDay);
+        if (calendar.get(Calendar.MILLISECOND) == 0) {
+            calendar.clear(Calendar.MILLISECOND);
+        }
+        if (roundSeconds) {
+            // This is different from poi where you need to change 500 to 499
+            calendar.add(Calendar.MILLISECOND, 499);
+            calendar.clear(Calendar.MILLISECOND);
+        }
+    }
+
+
+    /**
+     * Given a double, checks if it is a valid Excel date.
+     *
+     * @return true if valid
+     * @param  value the double value
+     */
+
+    public static boolean isValidExcelDate(double value)
+    {
+        return (value > -Double.MIN_VALUE);
+    }
+
+
     /**
      * Given an Excel date with either 1900 or 1904 date windowing,
      * converts it to a java.time.LocalDateTime.
diff --git a/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java b/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java
index 1229b2382..fa7a517ba 100644
--- a/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java
+++ b/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java
@@ -3,10 +3,12 @@
 import java.io.File;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Objects;
 
 import com.alibaba.easyexcel.test.util.TestFileUtil;
 import com.alibaba.excel.EasyExcel;
+import com.alibaba.fastjson2.JSON;
 
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.Assertions;
@@ -22,6 +24,7 @@
 @Slf4j
 public class DateFormatTest {
 
+    private static File file07V2;
     private static File file07;
     private static File file03;
 
@@ -29,6 +32,8 @@ public class DateFormatTest {
     public static void init() {
         file07 = TestFileUtil.readFile("dataformat" + File.separator + "dataformat.xlsx");
         file03 = TestFileUtil.readFile("dataformat" + File.separator + "dataformat.xls");
+        file07V2 = TestFileUtil.readFile("dataformat" + File.separator + "dataformatv2.xlsx");
+
     }
 
     @Test
@@ -43,6 +48,16 @@ public void t02Read03() {
         readUs(file03);
     }
 
+    @Test
+    public void t03Read() {
+        List<Map<Integer, String>> dataMap = EasyExcel.read(file07V2).headRowNumber(0).doReadAllSync();
+        log.info("dataMap:{}", JSON.toJSONString(dataMap));
+        Assertions.assertEquals("15:00", dataMap.get(0).get(0));
+        Assertions.assertEquals("2023-1-01 00:00:00", dataMap.get(1).get(0));
+        Assertions.assertEquals("2023-1-01 00:00:00", dataMap.get(2).get(0));
+        Assertions.assertEquals("2023-1-01 00:00:01", dataMap.get(3).get(0));
+    }
+
     private void readCn(File file) {
         List<DateFormatData> list =
             EasyExcel.read(file, DateFormatData.class, null).locale(Locale.CHINA).sheet().doReadSync();
diff --git a/easyexcel-test/src/test/resources/dataformat/dataformatv2.xlsx b/easyexcel-test/src/test/resources/dataformat/dataformatv2.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..8b9c7cbb59edd507fffb216c6fde3cbe282554df
GIT binary patch
literal 8782
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
BG(i9W

literal 0
HcmV?d00001

diff --git a/pom.xml b/pom.xml
index a9734c4da..ab227234b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,7 +20,7 @@
 
 
     <properties>
-        <revision>4.0.2</revision>
+        <revision>4.0.3</revision>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <jdk.version>1.8</jdk.version>
         <gpg.skip>true</gpg.skip>
diff --git a/update.md b/update.md
index 829bcb8ac..c31e8bdf5 100644
--- a/update.md
+++ b/update.md
@@ -1,3 +1,7 @@
+# 4.0.3
+
+* 兼容部分日期格式读取异常的问题
+
 # 4.0.2
 
 * 兼容某些特殊的xls: 修改了内置的样式导致判断样式错误

From 4826273f09d0d1658037da600c721db47ea4212e Mon Sep 17 00:00:00 2001
From: Jiaju Zhuang <zhuangjiaju@qq.com>
Date: Wed, 11 Sep 2024 20:34:01 +0800
Subject: [PATCH 2/2] # 4.0.3
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* 兼容部分日期格式读取异常的问题
---
 .../test/core/dataformat/DateFormatTest.java  |   3 +++
 .../resources/dataformat/dataformatv2.xlsx    | Bin 8782 -> 8889 bytes
 2 files changed, 3 insertions(+)

diff --git a/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java b/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java
index fa7a517ba..d8fd95b37 100644
--- a/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java
+++ b/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java
@@ -56,6 +56,9 @@ public void t03Read() {
         Assertions.assertEquals("2023-1-01 00:00:00", dataMap.get(1).get(0));
         Assertions.assertEquals("2023-1-01 00:00:00", dataMap.get(2).get(0));
         Assertions.assertEquals("2023-1-01 00:00:01", dataMap.get(3).get(0));
+        Assertions.assertEquals("2023-1-01 00:00:00", dataMap.get(4).get(0));
+        Assertions.assertEquals("2023-1-01 00:00:00", dataMap.get(5).get(0));
+        Assertions.assertEquals("2023-1-01 00:00:01", dataMap.get(6).get(0));
     }
 
     private void readCn(File file) {
diff --git a/easyexcel-test/src/test/resources/dataformat/dataformatv2.xlsx b/easyexcel-test/src/test/resources/dataformat/dataformatv2.xlsx
index 8b9c7cbb59edd507fffb216c6fde3cbe282554df..c49aa0440841205e938b36dcec1ed2abd6ecbb9c 100644
GIT binary patch
delta 2217
zcmV;a2v+ybM7c$<+6aH&+^oct0{{Th2mk;N0001ZY%h0ja%*C5Z)+}iZEUPn+iv4F
z5PdJue-QMpP}JQ*oP}jcXn<r9INqdv3K)sDm`I{aQnAxu|Gh)mvXgaDxY-&qufwA=
zGiRvtFPo+|UZ{|aw__8Z*``6;f|smaj?HiL+=@&?D$<su<}H66o3B)wUoL+A<$TS>
z^CRca1^~2jY*tFGVuWN-(T2z~zM?JcEVyWhf~i;{xe}C=vZ7QqHF9h_Kn-E7xkZS@
zDHwdQU<FNi(KWPHTM$8OqJX}v*h&s)O>qibL&S5pvI^d;0OFC=OuhD?rqLAf<+A01
zJl5d$2K&ZFz!QJKAKTD4!<%61=v56X1ebiF&Hx&1Ngw%-ZG`cM5NwWPa2k?_1btyT
zhkI5c_#~@fj};uiu>I3$7^Kx}C5GUA63yRpbIgnL1*_@ZR=NgRt-g{*XR0=hnn;zE
zOwn>|hA`!8`e8wItE6K!>|$&?k%=z$a=sBpNf)H6)f|6>Jivot5R4pOTY@kqwW6XW
zicWc}K!-cOepYim_O#-laAQXQ?3kcXSfDTP6<Sin<Wb%bRT-VA$0qtF!Flvo)sc4j
z#K=>JE=x*o1b?E1l86%dN;d_q4<k!KAdnOV>IZ<&J5f-HN}|ZNR?$0Mlj9=#56UKm
z4i|!WZGC^*j(?0DxF+I3y*El2FuqK$AcME$1@Z~1DR<?5sT1Ztw1tTA!&{!<B(QOA
zIngMzu<hAaG|hd>Npa@5qtFd}=Q}tfg1F$MQ`Jr?8hUJcpo^oeYqA-3upM`-JkWTv
zcRx$_KQzPMckQsg6z>>a%Y&%&)Y#m!w&ZJ2q!WLEQ?J9+9eFTa_nY^uRMpsY!sxK}
z8)eH17~`NfgyPZ6#^zfTr9t5MzU5+!EgX6yD+x2#3d1xABR88QlWETgy`$7$zd)_;
zjkYhDTYV*CxaW1>2iY`4tluFnOWY@MI98ClfD+MNZx})SjI;&as4J=Z9@NQz9`@`>
zXpet9%g$Wi@}iMrMV{+eQ!jNgKg`lB@pXRm=Og|<F44Y7;^DibSyn`-xgf<ee9dNb
zkq`-j+ByV$-;+)JD6w6j=;fd&507jsNdnLE)7<q#oK7=8Kakb#FFtvNMW{bbiRz&I
zbY=JRShx9Zb-%dSF6{F3q4wfgs^h*p{ckgdx8QwEPc+W&PBff;y`Ep6XnU2-AMW!L
zjVH6&<d1pw`)~yPV}MYfK;8DTLqpmx{sxnQ0~E7;3^)r4MhvZ55(5ALkOq^#7cPH7
zXcL803EOCUTkS`CHf9J`Y|PpwNwwPl-T{=fQZ7*?K*Qj9-WmLQ`Eb&T9Kbqhnv6!1
zkP>KwDP^<E=%3%);GPoac~f#_8p!A?IQp>q`ek`EcJFEcPms{KjMm<_3&xzNL31}T
zEj0M0GFEesuXe{=Yk`+Tkyb1Y!<2t%E*m-$7WNi~sVXVpn-QIc#*YvSihJze)v|SG
znijX<G`IV%4TRAxA_}Rbe;uHdXt8+OHOBHn;oPSv;ewnjUNPR&v&@jcQqodb<4olz
zNM>Wt*W=IGoN;j>UC)0LCQ6uvgX}l(9Tk7BrD%3x#qY4`Ct>LY*8eWM=wyGH(SONZ
zlEja*BnYSLZ7|Q1O)yX6X^?O7`Qtj-B=?)yf4W+h5_h<tidd*Jx{em>JIYqe!9ULu
zj_yNDJTHEM0^tEQB1(FD7RK!Rg-@6Yk?4j6J&_A950HaW8O>94_}@VTLlj^ag^%%B
zZ95qHhb0AfkQ?<POJAcT9-My?D&8so(;UBp+|?el15g-+)%YY@_J<6;#ZP0GV{sf$
zqBIH9ct(lnoHzPR9r_vS-v9sr|Nj600RR7Vk<kjmFbqY1W%L8qv}>D9x`N=3lriv0
zWgGMNO<olBt`KMr+(Sb0dY$L(Qny<2a(_0<Xq;)*N4>4`J2_MGr0{>NbTnT2y-=Hc
z%yuu?PEwM4hdm4{Rk4Oc7(BP6FLKY+9hf?3QVLBRLrQq208L7vY3P%4*c72j>6ZzI
z6AUW_V-PtP`CuW2CZ+!-(a5prcOm<^`wIX7|Nj600RR6yk3kB;Knz8%5^?~mh=^dj
z(Txj1=m|!fb_VMtq)~sdr#Fgqm-iR%|7<04CQFx-Ld)3>O^FKxdkK}8dB^!dIwa0m
zR9guh9fNi$571L<CC+DS1WjF>Ze#hTD}*zf@ol0=p&|Xy61|CSf}gi0y9-DV(mIV^
zzCmD3lr5Oomnf{JAsIsSeDtlM-%D~Mf^YN}{_M))$$A|kkyQb2lYj#iv#=W10tJ*0
zf(=Wvj2$uof0w2mGDF*e%AOnwP88ola=Qhaq$JU9|K7CSYGn#OCg<EQ=UkF6_o|LQ
z!8&PlfygXD5om6N)Y}3*Z&vXFMb0xVSZy>E=l~8a%gc+LH<TL-kJdC`y#yBpl6I6g
z1=@MvP>dblfnshJ96E@Vv5NU{v|HRT{?4|5(<HgVe+oPk%ro2p<7OnHBU11Y*?ic#
z2MCU#1_jzXOlAasdp%g?ejVtQiBm~`XhNrB+$me|K^)zCCr4x3wzD?tV}$$!zpn3}
z`l_+i-L5#GG8de33(Ol^t|hm|naW2GRV6t@&kk&kCys8LHFJI)7GFsaH;2E5&W+)v
zzS!^_Ify7kr9-ik@{--&ZC0pElXM;@*D)a*l2WpuS@PE9_%Yu_A1>4}&A*9RM$`F(
zcmk9;KKm}^7XXv=AJ_@s+^oct0{{Thlhq(j4U7x`0C;RKb98xZWpk5pArzA)5D*Ih
z000000000005y|eAtoC}46Rxc0{{S!1^@sU0000000000000000K}7^Aw>cV8<XcD
rA{&$sf(=Un004Ue000pH000000000000000<C7#JBnD+5000007Pb*D

delta 2107
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