From 9701a9619c200437e8666828a117c8de36074d54 Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 19 Dec 2020 01:03:04 +0800 Subject: [PATCH] fix date --- CHANGELOG.md | 1 + .../cn/hutool/poi/excel/ExcelDateUtil.java | 70 +++++++++++++++++++ .../cn/hutool/poi/excel/cell/CellUtil.java | 51 ++++---------- .../cn/hutool/poi/excel/sax/ExcelSaxUtil.java | 11 +-- .../cn/hutool/poi/excel/ExcelSaxReadTest.java | 8 +++ 5 files changed, 94 insertions(+), 47 deletions(-) create mode 100644 hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelDateUtil.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e3286739..775181bd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * 【core 】 PathUtil增加isSub和toAbsNormal方法 * 【db 】 RedisDS实现序列化接口(pr#1323@Github) * 【poi 】 StyleUtil增加getFormat方法(pr#235@Gitee) +* 【poi 】 增加ExcelDateUtil更多日期格式支持(issue#1316@Github) ### Bug修复 * 【core 】 FileUtil.isSub相对路径判断问题(pr#1315@Github) diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelDateUtil.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelDateUtil.java new file mode 100644 index 000000000..fb6349036 --- /dev/null +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelDateUtil.java @@ -0,0 +1,70 @@ +package cn.hutool.poi.excel; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import org.apache.poi.ss.formula.ConditionalFormattingEvaluator; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.ExcelNumberFormat; + +/** + * Excel中日期判断、读取、处理等补充工具类 + * + * @author looly + * @since 5.5.5 + */ +public class ExcelDateUtil { + + /** + * 某些特殊的自定义日期格式 + */ + private static final int[] customFormats = new int[]{28, 30, 31, 32, 33, 55, 56, 57, 58}; + + public static boolean isDateFormat(Cell cell){ + return isDateFormat(cell, null); + } + + /** + * 判断是否日期格式 + * @param cell 单元格 + * @param cfEvaluator {@link ConditionalFormattingEvaluator} + * @return 是否日期格式 + */ + public static boolean isDateFormat(Cell cell, ConditionalFormattingEvaluator cfEvaluator){ + final ExcelNumberFormat nf = ExcelNumberFormat.from(cell, cfEvaluator); + return isDateFormat(nf); + } + + /** + * 判断是否日期格式 + * @param numFmt {@link ExcelNumberFormat} + * @return 是否日期格式 + */ + public static boolean isDateFormat(ExcelNumberFormat numFmt) { + return isDateFormat(numFmt.getIdx(), numFmt.getFormat()); + } + + /** + * 判断日期格式 + * + * @param formatIndex 格式索引,一般用于内建格式 + * @param formatString 格式字符串 + * @return 是否为日期格式 + * @since 5.5.3 + */ + public static boolean isDateFormat(int formatIndex, String formatString) { + // issue#1283@Github + if (ArrayUtil.contains(customFormats, formatIndex)) { + return true; + } + + // 自定义格式判断 + if (StrUtil.isNotEmpty(formatString) && + StrUtil.containsAny(formatString, "周", "星期", "aa")) { + // aa -> 周一 + // aaa -> 星期一 + return true; + } + + return org.apache.poi.ss.usermodel.DateUtil.isADateFormat(formatIndex, formatString); + } +} diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/CellUtil.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/CellUtil.java index 2b71e08aa..390e297f8 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/CellUtil.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/CellUtil.java @@ -3,6 +3,7 @@ package cn.hutool.poi.excel.cell; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.poi.excel.ExcelDateUtil; import cn.hutool.poi.excel.ExcelUtil; import cn.hutool.poi.excel.StyleSet; import cn.hutool.poi.excel.editors.TrimEditor; @@ -102,7 +103,7 @@ public class CellUtil { if (null == cell) { return null; } - if(cell instanceof NullCell){ + if (cell instanceof NullCell) { return null == cellEditor ? null : cellEditor.edit(cell, null); } if (null == cellType) { @@ -111,7 +112,7 @@ public class CellUtil { // 尝试获取合并单元格,如果是合并单元格,则重新获取单元格类型 final Cell mergedCell = getMergedRegionCell(cell); - if(mergedCell != cell){ + if (mergedCell != cell) { cell = mergedCell; cellType = cell.getCellTypeEnum(); } @@ -235,7 +236,7 @@ public class CellUtil { } /** - *获取单元格,如果单元格不存在,返回{@link NullCell} + * 获取单元格,如果单元格不存在,返回{@link NullCell} * * @param row Excel表的行 * @param cellIndex 列号 @@ -377,7 +378,7 @@ public class CellUtil { * @since 5.1.5 */ public static Cell getMergedRegionCell(Cell cell) { - if(null == cell){ + if (null == cell) { return null; } return ObjectUtil.defaultIfNull( @@ -404,10 +405,10 @@ public class CellUtil { /** * 为特定单元格添加批注 * - * @param cell 单元格 - * @param commentText 批注内容 + * @param cell 单元格 + * @param commentText 批注内容 * @param commentAuthor 作者 - * @param anchor 批注的位置、大小等信息,null表示使用默认 + * @param anchor 批注的位置、大小等信息,null表示使用默认 * @since 5.4.8 */ public static void setComment(Cell cell, String commentText, String commentAuthor, ClientAnchor anchor) { @@ -431,16 +432,16 @@ public class CellUtil { // -------------------------------------------------------------------------------------------------------------- Private method start /** - * 获取合并单元格,非合并单元格返回null
+ * 获取合并单元格,非合并单元格返回{@code null}
* 传入的x,y坐标(列行数)可以是合并单元格范围内的任意一个单元格 * * @param sheet {@link Sheet} * @param x 列号,从0开始,可以是合并单元格范围中的任意一列 * @param y 行号,从0开始,可以是合并单元格范围中的任意一行 - * @return 合并单元格,如果非合并单元格,返回null + * @return 合并单元格,如果非合并单元格,返回{@code null} * @since 5.4.5 */ - private static Cell getCellIfMergedRegion(Sheet sheet, int x, int y){ + private static Cell getCellIfMergedRegion(Sheet sheet, int x, int y) { final int sheetMergeCount = sheet.getNumMergedRegions(); CellRangeAddress ca; for (int i = 0; i < sheetMergeCount; i++) { @@ -463,9 +464,8 @@ public class CellUtil { final CellStyle style = cell.getCellStyle(); if (null != style) { - final short formatIndex = style.getDataFormat(); // 判断是否为日期 - if (isDateType(cell, formatIndex)) { + if (ExcelDateUtil.isDateFormat(cell)) { return DateUtil.date(cell.getDateCellValue());// 使用Hutool的DateTime包装 } @@ -483,32 +483,5 @@ public class CellUtil { // 某些Excel单元格值为double计算结果,可能导致精度问题,通过转换解决精度问题。 return Double.parseDouble(NumberToTextConverter.toText(value)); } - - /** - * 是否为日期格式
- * 判断方式: - * - *
-	 * 1、指定序号
-	 * 2、org.apache.poi.ss.usermodel.DateUtil.isADateFormat方法判定
-	 * 
- * - * @param cell 单元格 - * @param formatIndex 格式序号 - * @return 是否为日期格式 - */ - private static boolean isDateType(Cell cell, int formatIndex) { - // yyyy-MM-dd----- 14 - // yyyy年m月d日---- 31 - // yyyy年m月------- 57 - // m月d日 ---------- 58 - // HH:mm----------- 20 - // h时mm分 -------- 32 - if (formatIndex == 14 || formatIndex == 31 || formatIndex == 57 || formatIndex == 58 || formatIndex == 20 || formatIndex == 32) { - return true; - } - - return org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell); - } // -------------------------------------------------------------------------------------------------------------- Private method end } diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxUtil.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxUtil.java index 5f50f9c12..e92095674 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxUtil.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxUtil.java @@ -6,6 +6,7 @@ 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.ExcelDateUtil; import cn.hutool.poi.excel.sax.handler.RowHandler; import cn.hutool.poi.exceptions.POIException; import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; @@ -209,16 +210,10 @@ public class ExcelSaxUtil { * @param formatString 格式字符串 * @return 是否为日期格式 * @since 5.5.3 + * @see ExcelDateUtil#isDateFormat(int, String) */ public static boolean isDateFormat(int formatIndex, String formatString) { - // https://blog.csdn.net/u014342130/article/details/50619503 - // issue#1283@Github - if (formatIndex == 28 || formatIndex == 31) { - // 28 -> m月d日 - // 31 -> yyyy年m月d日 - return true; - } - return org.apache.poi.ss.usermodel.DateUtil.isADateFormat(formatIndex, formatString); + return ExcelDateUtil.isDateFormat(formatIndex, formatString); } /** diff --git a/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelSaxReadTest.java b/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelSaxReadTest.java index 4d5ef39f8..785eb2899 100644 --- a/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelSaxReadTest.java +++ b/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelSaxReadTest.java @@ -164,6 +164,14 @@ public class ExcelSaxReadTest { Assert.assertEquals("2012-12-21 00:00:00", rows.get(4)); } + @Test + @Ignore + public void dateReadXlsxTest2() { + ExcelUtil.readBySax("d:/test/custom_date_format2.xlsx", 0, + (i, i1, list) -> Console.log(list) + ); + } + @Test @Ignore public void readBlankTest() {