Browse Source

fix date read for sax bug

Looly 5 years ago
parent
commit
897dea0b30

+ 1 - 0
CHANGELOG.md

@@ -12,6 +12,7 @@
 
 ### Bug修复
 * 【cache  】     修复Cache中get重复misCount计数问题(issue#1281@Github)
+* 【poi    】     修复sax读取自定义格式单元格无法识别日期类型的问题(issue#1283@Github)
 
 -------------------------------------------------------------------------------------------------------------
 

+ 1 - 1
hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java

@@ -268,7 +268,7 @@ public class Excel03SaxReader implements HSSFListener, ExcelSaxReader<Excel03Sax
 				break;
 			case FormulaRecord.sid:
 				// 公式类型
-				FormulaRecord formulaRec = (FormulaRecord) record;
+				final FormulaRecord formulaRec = (FormulaRecord) record;
 				if (isOutputFormulaValues) {
 					if (Double.isNaN(formulaRec.getValue())) {
 						// Formula result is a string

+ 41 - 35
hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxUtil.java

@@ -4,6 +4,7 @@ import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.exceptions.DependencyException;
 import cn.hutool.core.io.IORuntimeException;
+import cn.hutool.core.util.CharUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.poi.excel.sax.handler.RowHandler;
 import cn.hutool.poi.exceptions.POIException;
@@ -35,6 +36,20 @@ public class ExcelSaxUtil {
 	public static final int MAX_CELL_BIT = 3;
 
 	/**
+	 * 创建 {@link ExcelSaxReader}
+	 *
+	 * @param isXlsx     是否为xlsx格式(07格式)
+	 * @param rowHandler 行处理器
+	 * @return {@link ExcelSaxReader}
+	 * @since 5.4.4
+	 */
+	public static ExcelSaxReader<?> createSaxReader(boolean isXlsx, RowHandler rowHandler) {
+		return isXlsx
+				? new Excel07SaxReader(rowHandler)
+				: new Excel03SaxReader(rowHandler);
+	}
+
+	/**
 	 * 根据数据类型获取数据
 	 *
 	 * @param cellDataType       数据类型枚举
@@ -175,12 +190,13 @@ public class ExcelSaxUtil {
 
 	/**
 	 * 判断数字Record中是否为日期格式
-	 * @param cell 单元格记录
+	 *
+	 * @param cell           单元格记录
 	 * @param formatListener {@link FormatTrackingHSSFListener}
 	 * @return 是否为日期格式
 	 * @since 5.4.8
 	 */
-	public static boolean isDateFormat(CellValueRecordInterface cell, FormatTrackingHSSFListener formatListener){
+	public static boolean isDateFormat(CellValueRecordInterface cell, FormatTrackingHSSFListener formatListener) {
 		final int formatIndex = formatListener.getFormatIndex(cell);
 		final String formatString = formatListener.getFormatString(cell);
 		return isDateFormat(formatIndex, formatString);
@@ -189,15 +205,15 @@ public class ExcelSaxUtil {
 	/**
 	 * 判断日期格式
 	 *
-	 * @param formatIndex 格式索引,一般用于内建格式
+	 * @param formatIndex  格式索引,一般用于内建格式
 	 * @param formatString 格式字符串
 	 * @return 是否为日期格式
 	 * @since 5.5.3
 	 */
-	public static boolean isDateFormat(int formatIndex, String formatString){
+	public static boolean isDateFormat(int formatIndex, String formatString) {
 		// https://blog.csdn.net/u014342130/article/details/50619503
 		// issue#1283@Github
-		if(formatIndex == 28 || formatIndex == 31){
+		if (formatIndex == 28 || formatIndex == 31) {
 			// 28 -> m月d日
 			// 31 -> yyyy年m月d日
 			return true;
@@ -228,42 +244,21 @@ public class ExcelSaxUtil {
 	}
 
 	/**
-	 * 创建 {@link ExcelSaxReader}
-	 *
-	 * @param isXlsx     是否为xlsx格式(07格式)
-	 * @param rowHandler 行处理器
-	 * @return {@link ExcelSaxReader}
-	 * @since 5.4.4
-	 */
-	public static ExcelSaxReader<?> createSaxReader(boolean isXlsx, RowHandler rowHandler) {
-		return isXlsx
-				? new Excel07SaxReader(rowHandler)
-				: new Excel03SaxReader(rowHandler);
-	}
-
-	/**
 	 * 在Excel03 sax读取中获取日期或数字类型的结果值
-	 * @param cell 记录单元格
-	 * @param value 值
+	 *
+	 * @param cell           记录单元格
+	 * @param value          值
 	 * @param formatListener {@link FormatTrackingHSSFListener}
 	 * @return 值,可能为Date或Double或Long
 	 * @since 5.5.0
 	 */
-	public static Object getNumberOrDateValue(CellValueRecordInterface cell, double value, FormatTrackingHSSFListener formatListener){
+	public static Object getNumberOrDateValue(CellValueRecordInterface cell, double value, FormatTrackingHSSFListener formatListener) {
 		Object result;
-		if(ExcelSaxUtil.isDateFormat(cell, formatListener)){
+		if (isDateFormat(cell, formatListener)) {
 			// 可能为日期格式
-			result = ExcelSaxUtil.getDateValue(value);
-		} else {
-			final long longPart = (long) value;
-			// 对于无小数部分的数字类型,转为Long,否则保留原数字
-			if (((double) longPart) == value) {
-				result = longPart;
-			} else {
-				result = value;
-			}
+			return getDateValue(value);
 		}
-		return result;
+		return getNumberValue(value, formatListener.getFormatString(cell));
 	}
 
 	/**
@@ -278,9 +273,20 @@ public class ExcelSaxUtil {
 		if (StrUtil.isBlank(value)) {
 			return null;
 		}
-		double numValue = Double.parseDouble(value);
+		return getNumberValue(Double.parseDouble(value), numFmtString);
+	}
+
+	/**
+	 * 获取数字类型值,除非格式中明确数字保留小数,否则无小数情况下按照long返回
+	 *
+	 * @param numValue     值
+	 * @param numFmtString 格式
+	 * @return 数字,可以是Double、Long
+	 * @since 5.5.3
+	 */
+	private static Number getNumberValue(double numValue, String numFmtString) {
 		// 普通数字
-		if (null != numFmtString && numFmtString.indexOf(StrUtil.C_DOT) < 0) {
+		if (null != numFmtString && false == StrUtil.contains(numFmtString, CharUtil.DOT)) {
 			final long longPart = (long) numValue;
 			//noinspection RedundantIfStatement
 			if (longPart == numValue) {

+ 4 - 7
hutool-poi/src/test/java/cn/hutool/poi/excel/BigExcelWriteTest.java

@@ -1,13 +1,10 @@
-package cn.hutool.poi.excel.test;
+package cn.hutool.poi.excel;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.poi.excel.BigExcelWriter;
-import cn.hutool.poi.excel.ExcelUtil;
-import cn.hutool.poi.excel.ExcelWriter;
 import cn.hutool.poi.excel.style.StyleUtil;
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.FillPatternType;
@@ -163,21 +160,21 @@ public class BigExcelWriteTest {
 	@Test
 	@Ignore
 	public void writeBeanTest() {
-		TestBean bean1 = new TestBean();
+		cn.hutool.poi.excel.TestBean bean1 = new cn.hutool.poi.excel.TestBean();
 		bean1.setName("张三");
 		bean1.setAge(22);
 		bean1.setPass(true);
 		bean1.setScore(66.30);
 		bean1.setExamDate(DateUtil.date());
 
-		TestBean bean2 = new TestBean();
+		cn.hutool.poi.excel.TestBean bean2 = new cn.hutool.poi.excel.TestBean();
 		bean2.setName("李四");
 		bean2.setAge(28);
 		bean2.setPass(false);
 		bean2.setScore(38.50);
 		bean2.setExamDate(DateUtil.date());
 
-		List<TestBean> rows = CollUtil.newArrayList(bean1, bean2);
+		List<cn.hutool.poi.excel.TestBean> rows = CollUtil.newArrayList(bean1, bean2);
 		// 通过工具类创建writer
 		String file = "e:/bigWriteBeanTest.xlsx";
 		FileUtil.del(file);

+ 1 - 1
hutool-poi/src/test/java/cn/hutool/poi/excel/CellUtilTest.java

@@ -1,4 +1,4 @@
-package cn.hutool.poi.excel.test;
+package cn.hutool.poi.excel;
 
 import org.apache.poi.ss.usermodel.BuiltinFormats;
 import org.junit.Ignore;

+ 1 - 3
hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelReadTest.java

@@ -1,11 +1,9 @@
-package cn.hutool.poi.excel.test;
+package cn.hutool.poi.excel;
 
 import cn.hutool.core.io.resource.ResourceUtil;
 import cn.hutool.core.lang.Console;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.poi.excel.ExcelReader;
-import cn.hutool.poi.excel.ExcelUtil;
 import lombok.Data;
 import org.junit.Assert;
 import org.junit.Ignore;

+ 23 - 6
hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelSaxReadTest.java

@@ -1,4 +1,4 @@
-package cn.hutool.poi.excel.test;
+package cn.hutool.poi.excel;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.convert.Convert;
@@ -6,7 +6,6 @@ import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.lang.Console;
 import cn.hutool.core.util.StrUtil;
-import cn.hutool.poi.excel.ExcelUtil;
 import cn.hutool.poi.excel.cell.FormulaCellValue;
 import cn.hutool.poi.excel.sax.Excel03SaxReader;
 import cn.hutool.poi.excel.sax.handler.RowHandler;
@@ -138,15 +137,33 @@ public class ExcelSaxReadTest {
 	}
 
 	@Test
-	public void dateReadTest() {
+	public void dateReadXlsTest() {
 		List<String> rows = new ArrayList<>();
-		ExcelUtil.readBySax("data_for_sax_test.xls", 0, (i, i1, list) ->
-				rows.add(StrUtil.toString(list.get(0))));
+		ExcelUtil.readBySax("data_for_sax_test.xls", 0,
+				(i, i1, list) ->{
+					rows.add(StrUtil.toString(list.get(0)));
+				}
+		);
+
+		Assert.assertEquals("2020-10-09 00:00:00", rows.get(1));
+		// 非日期格式不做转换
+		Assert.assertEquals("112233", rows.get(2));
+		Assert.assertEquals("1000.0", rows.get(3));
+		Assert.assertEquals("2012-12-21 00:00:00", rows.get(4));
+	}
+
+	@Test
+	public void dateReadXlsxTest() {
+		List<String> rows = new ArrayList<>();
+		ExcelUtil.readBySax("data_for_sax_test.xlsx", 0,
+				(i, i1, list) -> rows.add(StrUtil.toString(list.get(0)))
+		);
 
 		Assert.assertEquals("2020-10-09 00:00:00", rows.get(1));
 		// 非日期格式不做转换
 		Assert.assertEquals("112233", rows.get(2));
-		Assert.assertEquals("1000", rows.get(3));
+		Assert.assertEquals("1000.0", rows.get(3));
+		Assert.assertEquals("2012-12-21 00:00:00", rows.get(4));
 	}
 
 	@Test

+ 1 - 2
hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelUtilTest.java

@@ -1,6 +1,5 @@
-package cn.hutool.poi.excel.test;
+package cn.hutool.poi.excel;
 
-import cn.hutool.poi.excel.ExcelUtil;
 import cn.hutool.poi.excel.cell.CellLocation;
 import org.junit.Assert;
 import org.junit.Test;

+ 7 - 9
hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelWriteTest.java

@@ -1,4 +1,4 @@
-package cn.hutool.poi.excel.test;
+package cn.hutool.poi.excel;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateUtil;
@@ -6,8 +6,6 @@ import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.poi.excel.ExcelUtil;
-import cn.hutool.poi.excel.ExcelWriter;
 import cn.hutool.poi.excel.style.StyleUtil;
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.FillPatternType;
@@ -340,21 +338,21 @@ public class ExcelWriteTest {
 	@Test
 	@Ignore
 	public void writeBeanTest() {
-		TestBean bean1 = new TestBean();
+		cn.hutool.poi.excel.TestBean bean1 = new cn.hutool.poi.excel.TestBean();
 		bean1.setName("张三");
 		bean1.setAge(22);
 		bean1.setPass(true);
 		bean1.setScore(66.30);
 		bean1.setExamDate(DateUtil.date());
 
-		TestBean bean2 = new TestBean();
+		cn.hutool.poi.excel.TestBean bean2 = new cn.hutool.poi.excel.TestBean();
 		bean2.setName("李四");
 		bean2.setAge(28);
 		bean2.setPass(false);
 		bean2.setScore(38.50);
 		bean2.setExamDate(DateUtil.date());
 
-		List<TestBean> rows = CollUtil.newArrayList(bean1, bean2);
+		List<cn.hutool.poi.excel.TestBean> rows = CollUtil.newArrayList(bean1, bean2);
 		// 通过工具类创建writer
 		String file = "e:/writeBeanTest.xlsx";
 		FileUtil.del(file);
@@ -376,17 +374,17 @@ public class ExcelWriteTest {
 	@Test
 	@Ignore
 	public void writeBeanTest2() {
-		OrderExcel order1 = new OrderExcel();
+		cn.hutool.poi.excel.OrderExcel order1 = new cn.hutool.poi.excel.OrderExcel();
 		order1.setId("1");
 		order1.setNum("123");
 		order1.setBody("body1");
 
-		OrderExcel order2 = new OrderExcel();
+		cn.hutool.poi.excel.OrderExcel order2 = new cn.hutool.poi.excel.OrderExcel();
 		order1.setId("2");
 		order1.setNum("456");
 		order1.setBody("body2");
 
-		List<OrderExcel> rows = CollUtil.newArrayList(order1, order2);
+		List<cn.hutool.poi.excel.OrderExcel> rows = CollUtil.newArrayList(order1, order2);
 		// 通过工具类创建writer
 		String file = "f:/test/writeBeanTest2.xlsx";
 		FileUtil.del(file);

+ 1 - 1
hutool-poi/src/test/java/cn/hutool/poi/excel/OrderExcel.java

@@ -1,4 +1,4 @@
-package cn.hutool.poi.excel.test;
+package cn.hutool.poi.excel;
 
 import lombok.Data;
 

+ 1 - 1
hutool-poi/src/test/java/cn/hutool/poi/excel/TestBean.java

@@ -1,4 +1,4 @@
-package cn.hutool.poi.excel.test;
+package cn.hutool.poi.excel;
 
 import lombok.Data;
 

+ 1 - 1
hutool-poi/src/test/java/cn/hutool/poi/word/WordWriterTest.java

@@ -1,4 +1,4 @@
-package cn.hutool.poi.word.test;
+package cn.hutool.poi.word;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.io.FileUtil;

BIN
hutool-poi/src/test/resources/data_for_sax_test.xls


BIN
hutool-poi/src/test/resources/data_for_sax_test.xlsx