Skip to content

Commit

Permalink
Merge branch 'alibaba:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
psxjoy authored Sep 11, 2024
2 parents 94297c9 + 3afdea9 commit 31151af
Show file tree
Hide file tree
Showing 9 changed files with 307 additions and 37 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>4.0.1</version>
<version>4.0.3</version>
</dependency>
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.Map;

import com.alibaba.excel.util.MapUtils;
import com.alibaba.excel.util.StringUtils;

/**
* Excel's built-in format conversion.Currently only supports Chinese.
Expand All @@ -20,8 +21,116 @@
**/
public class BuiltinFormats {

private static final String RESERVED = "reserved-";

public static short GENERAL = 0;

public static final String[] BUILTIN_FORMATS_ALL_LANGUAGES = {
// 0
"General",
// 1
"0",
// 2
"0.00",
// 3
"#,##0",
// 4
"#,##0.00",
// 5
"\"\"#,##0_);(\"\"#,##0)",
// 6
"\"\"#,##0_);[Red](\"\"#,##0)",
// 7
"\"\"#,##0.00_);(\"\"#,##0.00)",
// 8
"\"\"#,##0.00_);[Red](\"\"#,##0.00)",
// 9
"0%",
// 10
"0.00%",
// 11
"0.00E+00",
// 12
"# ?/?",
// 13
"# ??/??",
// 14
// The official documentation shows "m/d/yy", but the actual test is "yyyy/m/d".
"yyyy/m/d",
// 15
"d-mmm-yy",
// 16
"d-mmm",
// 17
"mmm-yy",
// 18
"h:mm AM/PM",
// 19
"h:mm:ss AM/PM",
// 20
"h:mm",
// 21
"h:mm:ss",
// 22
// The official documentation shows "m/d/yy h:mm", but the actual test is "yyyy-m-d h:mm".
"yyyy-m-d h:mm",
// 23-36 No specific correspondence found in the official documentation.
// 23
null,
// 24
null,
// 25
null,
// 26
null,
// 27
null,
// 28
null,
// 29
null,
// 30
null,
// 31
null,
// 32
null,
// 33
null,
// 34
null,
// 35
null,
// 36
null,
// 37
"#,##0_);(#,##0)",
// 38
"#,##0_);[Red](#,##0)",
// 39
"#,##0.00_);(#,##0.00)",
// 40
"#,##0.00_);[Red](#,##0.00)",
// 41
"_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)",
// 42
"_(\"\"* #,##0_);_(\"\"* (#,##0);_(\"\"* \"-\"_);_(@_)",
// 43
"_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)",
// 44
"_(\"\"* #,##0.00_);_(\"\"* (#,##0.00);_(\"\"* \"-\"??_);_(@_)",
// 45
"mm:ss",
// 46
"[h]:mm:ss",
// 47
"mm:ss.0",
// 48
"##0.0E+0",
// 49
"@",
};

public static final String[] BUILTIN_FORMATS_CN = {
// 0
"General",
Expand Down Expand Up @@ -371,8 +480,26 @@ public class BuiltinFormats {
public static final short MIN_CUSTOM_DATA_FORMAT_INDEX = 82;

public static String getBuiltinFormat(Short index, String defaultFormat, Locale locale) {
if (index == null || index <= 0) {
return defaultFormat;
}

// Give priority to checking if it is the default value for all languages
if (index < BUILTIN_FORMATS_ALL_LANGUAGES.length) {
String format = BUILTIN_FORMATS_ALL_LANGUAGES[index];
if (format != null) {
return format;
}
}

// In other cases, give priority to using the externally provided format
if (!StringUtils.isEmpty(defaultFormat) && !defaultFormat.startsWith(RESERVED)) {
return defaultFormat;
}

// Finally, try using the built-in format
String[] builtinFormat = switchBuiltinFormats(locale);
if (index == null || index < 0 || index >= builtinFormat.length) {
if (index >= builtinFormat.length) {
return defaultFormat;
}
return builtinFormat[index];
Expand Down
124 changes: 97 additions & 27 deletions easyexcel-core/src/main/java/com/alibaba/excel/util/DateUtils.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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() {}

/**
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -470,31 +561,10 @@ public static boolean isInternalDateFormat(short format) {
case 0x14:
case 0x15:
case 0x16:
// 27-36
case 0x1b:
case 0x1c:
case 0x1d:
case 0x1e:
case 0x1f:
case 0x20:
case 0x21:
case 0x22:
case 0x23:
case 0x24:
// 45-47
// 45-47
case 0x2d:
case 0x2e:
case 0x2f:
// 50-58
case 0x32:
case 0x33:
case 0x34:
case 0x35:
case 0x36:
case 0x37:
case 0x38:
case 0x39:
case 0x3a:
return true;
}
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -22,13 +24,16 @@
@Slf4j
public class DateFormatTest {

private static File file07V2;
private static File file07;
private static File file03;

@BeforeAll
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
Expand All @@ -43,6 +48,19 @@ 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));
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) {
List<DateFormatData> list =
EasyExcel.read(file, DateFormatData.class, null).locale(Locale.CHINA).sheet().doReadSync();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ public void test() throws Exception {
File file = new File("/Users/zhuangjiaju/IdeaProjects/easyexcel/src/test/resources/converter/converter07.xlsx");

List<Object> list = EasyExcel.read(
"/Users/zhuangjiaju/IdeaProjects/easyexcel/easyexcel-test/target/test-classes"
+ "/simpleWrite1674051907397.xlsx")
"/Users/zhuangjiaju/Downloads/证券投资基金估值表_外贸信托-稳盈淳享37号集合资金信托计划_2024-07-23(1).xls")
//.useDefaultListener(false)
.sheet(0)
.headRowNumber(0).doReadSync();
Expand Down
Loading

0 comments on commit 31151af

Please sign in to comment.