From 8e3a04bd56a6b41233eb23ff1843c44d2448f040 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 12 Jul 2020 12:12:48 +0800 Subject: [PATCH] fix ChineseDate bug --- CHANGELOG.md | 2 + .../java/cn/hutool/core/date/ChineseDate.java | 88 +++++++++---------- .../java/cn/hutool/poi/excel/ExcelWriter.java | 3 + .../hutool/poi/excel/test/ExcelWriteTest.java | 42 ++++----- 4 files changed, 69 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ced25ba0..b4dd80975 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * 【core 】 deprecate掉millsecond,改为millisecond(issue#I1M9P8@Gitee) * 【core 】 增加LocalDateTimeUtil(issue#I1KUVC@Gitee) * 【core 】 Month增加getLastDay方法 +* 【core 】 ChineseDate支持到2099年 ### Bug修复 * 【core 】 修复NumberUtil.partValue有余数问题(issue#I1KX66@Gitee) @@ -26,6 +27,7 @@ * 【core 】 修复DateUtil.endOfQuarter错误问题(issue#I1NGZ7@Gitee) * 【core 】 修复URL中有空格转为+问题(issue#I1NGW4@Gitee) * 【core 】 修复CollUtil.intersectionDistinct空集合结果错误问题 +* 【core 】 修复ChineseDate在1996年计算错误问题(issue#I1N96I@Gitee) ------------------------------------------------------------------------------------------------------------- ## 5.3.8 (2020-06-16) diff --git a/hutool-core/src/main/java/cn/hutool/core/date/ChineseDate.java b/hutool-core/src/main/java/cn/hutool/core/date/ChineseDate.java index 0b23ee484..db7424c91 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/ChineseDate.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/ChineseDate.java @@ -9,7 +9,7 @@ import java.util.List; /** - * 农历日期工具 + * 农历日期工具,最大支持到2055年 * * @author zjw, looly * @since 5.1.1 @@ -33,33 +33,35 @@ public class ChineseDate { private final String[] chineseNumber = {"一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"}; private final String[] chineseNumberName = {"正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "腊"}; /** + * 此表来自:https://github.com/jjonline/calendar.js/blob/master/calendar.js *农历表示: * 1. 表示当年有无闰年,有的话,为闰月的月份,没有的话,为0。 * 2-4.为除了闰月外的正常月份是大月还是小月,1为30天,0为29天。 * 5. 表示闰月是大月还是小月,仅当存在闰月的情况下有意义。 */ - private final long[] lunarInfo = new long[]{0x04bd8, 0x04ae0, 0x0a570, - 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, - 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, - 0x0ada2, 0x095b0, 0x14977, 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, - 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, 0x06566, - 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, - 0x1c8d7, 0x0c950, 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, - 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, 0x06ca0, 0x0b550, - 0x15355, 0x04da0, 0x0a5d0, 0x14573, 0x052d0, 0x0a9a8, 0x0e950, - 0x06aa0, 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, - 0x0f263, 0x0d950, 0x05b57, 0x056a0, 0x096d0, 0x04dd5, 0x04ad0, - 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6, - 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, - 0x0af46, 0x0ab60, 0x09570, 0x04af5, 0x04970, 0x064b0, 0x074a3, - 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0, 0x0c960, - 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, - 0x092d0, 0x0cab5, 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, - 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, 0x07954, 0x06aa0, - 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, - 0x0d530, 0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0, - 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, 0x0b5a0, 0x056d0, 0x055b2, - 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0}; + private final long[] lunarInfo = new long[]{ + 0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2,//1900-1909 + 0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977,//1910-1919 + 0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970,//1920-1929 + 0x06566,0x0d4a0,0x0ea50,0x16a95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950,//1930-1939 + 0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557,//1940-1949 + 0x06ca0,0x0b550,0x15355,0x04da0,0x0a5b0,0x14573,0x052b0,0x0a9a8,0x0e950,0x06aa0,//1950-1959 + 0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0,//1960-1969 + 0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b6a0,0x195a6,//1970-1979 + 0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570,//1980-1989 + 0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x05ac0,0x0ab60,0x096d5,0x092e0,//1990-1999 + 0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5,//2000-2009 + 0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930,//2010-2019 + 0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530,//2020-2029 + 0x05aa0,0x076a3,0x096d0,0x04afb,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45,//2030-2039 + 0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0,//2040-2049 + 0x14b63,0x09370,0x049f8,0x04970,0x064b0,0x168a6,0x0ea50, 0x06b20,0x1a6c4,0x0aae0,//2050-2059 + 0x092e0,0x0d2e3,0x0c960,0x0d557,0x0d4a0,0x0da50,0x05d55,0x056a0,0x0a6d0,0x055d4,//2060-2069 + 0x052d0,0x0a9b8,0x0a950,0x0b4a0,0x0b6a6,0x0ad50,0x055a0,0x0aba4,0x0a5b0,0x052b0,//2070-2079 + 0x0b273,0x06930,0x07337,0x06aa0,0x0ad50,0x14b55,0x04b60,0x0a570,0x054e4,0x0d160,//2080-2089 + 0x0e968,0x0d520,0x0daa0,0x16aa6,0x056d0,0x04ae0,0x0a9d4,0x0a2d0,0x0d150,0x0f252,//2090-2099 + }; + //农历节日 *表示放假日 private final String[] lFtv = new String[]{ "0101 春节", "0102 大年初二", "0103 大年初三", "0104 大年初四", @@ -76,48 +78,45 @@ public class ChineseDate { * @param date 日期 */ public ChineseDate(Date date) { - int yearCyl; - int monCyl; - int dayCyl; // 求出和1900年1月31日相差的天数 int offset = (int) ((date.getTime() - baseDate) / DateUnit.DAY.getMillis()); - monCyl = 14; - // 用offset减去每农历年的天数 - // 计算当天是农历第几天 - // i最终结果是农历的年份 - // offset是当年的第几天 - int iYear; + + // 计算农历年份 + // 用offset减去每农历年的天数,计算当天是农历第几天,offset是当年的第几天 int daysOfYear; - for (iYear = 1900; iYear < 2050; iYear++) { + int iYear = 1900; + final int maxYear = iYear + lunarInfo.length - 1; + for (; iYear <= maxYear; iYear++) { daysOfYear = yearDays(iYear); if (offset < daysOfYear) { break; } offset -= daysOfYear; - monCyl += 12; } - - // 农历年份 year = iYear; + + // 计算农历月份 int leapMonth = leapMonth(iYear); // 闰哪个月,1-12 - leap = false; // 用当年的天数offset,逐个减去每月(农历)的天数,求出当天是本月的第几天 - int iMonth, daysOfMonth = 0; + int iMonth; + int daysOfMonth = 0; for (iMonth = 1; iMonth < 13 && offset > 0; iMonth++) { // 闰月 - if (leapMonth > 0 && iMonth == (leapMonth + 1) && !leap) { + if (leapMonth > 0 && iMonth == (leapMonth + 1) && false == leap) { --iMonth; leap = true; daysOfMonth = leapDays(year); - } else + } else { daysOfMonth = monthDays(year, iMonth); + } + offset -= daysOfMonth; // 解除闰月 - if (leap && iMonth == (leapMonth + 1)) + if (leap && iMonth == (leapMonth + 1)){ leap = false; - if (!leap) - monCyl++; + } } + // offset为0时,并且刚才计算的月份是闰月,要校正 if (offset == 0 && leapMonth > 0 && iMonth == leapMonth + 1) { if (leap) { @@ -125,14 +124,13 @@ public class ChineseDate { } else { leap = true; --iMonth; - --monCyl; } } + // offset小于0时,也要校正 if (offset < 0) { offset += daysOfMonth; --iMonth; - --monCyl; } month = iMonth; day = offset + 1; diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelWriter.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelWriter.java index 3cec6ba4e..3764d5780 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelWriter.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelWriter.java @@ -326,6 +326,9 @@ public class ExcelWriter extends ExcelBase { * @return 单元格样式 */ public CellStyle getCellStyle() { + if(null == this.styleSet){ + return null; + } return this.styleSet.cellStyle; } diff --git a/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelWriteTest.java b/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelWriteTest.java index c192efdcc..17bc26ba7 100644 --- a/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelWriteTest.java +++ b/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelWriteTest.java @@ -27,7 +27,7 @@ import java.util.TreeMap; /** * 写出Excel单元测试 - * + * * @author looly */ public class ExcelWriteTest { @@ -211,7 +211,7 @@ public class ExcelWriteTest { // 关闭writer,释放内存 writer.close(); } - + @Test @Ignore public void writeMapWithStyleTest() { @@ -227,14 +227,14 @@ public class ExcelWriteTest { FileUtil.del(path); ExcelWriter writer = ExcelUtil.getWriter(path); writer.setStyleSet(null); - + // 一次性写出内容,使用默认样式 writer.writeRow(row1, true); - + // 设置某个单元格样式 CellStyle orCreateRowStyle = writer.getOrCreateCellStyle(0, 1); - StyleUtil.setColor(orCreateRowStyle,IndexedColors.RED.getIndex(),FillPatternType.SOLID_FOREGROUND ); - + StyleUtil.setColor(orCreateRowStyle, IndexedColors.RED.getIndex(), FillPatternType.SOLID_FOREGROUND); + // 关闭writer,释放内存 writer.close(); } @@ -306,7 +306,7 @@ public class ExcelWriteTest { // 关闭writer,释放内存 writer.close(); } - + @Test @Ignore public void writeMapOnlyAliasTest2() { @@ -409,7 +409,7 @@ public class ExcelWriteTest { writer.writeCellValue(3, 5, "aaa"); writer.close(); } - + @Test @Ignore public void addSelectTest() { @@ -440,7 +440,7 @@ public class ExcelWriteTest { @Test @Ignore - public void writeMultiSheetTest(){ + public void writeMultiSheetTest() { List> rows = new LinkedList<>(); for (int i = 0; i < 10; i++) { Map tempList = new TreeMap<>(); @@ -475,22 +475,22 @@ public class ExcelWriteTest { @Test @Ignore - public void writeMapsTest(){ - List> rows = new ArrayList<>(); + public void writeMapsTest() { + List> rows = new ArrayList<>(); Map map1 = new HashMap<>(); - map1.put("a",1); - map1.put("b",2); - map1.put("c",3); - map1.put("d",4); - map1.put("e",5); + map1.put("a", 1); + map1.put("b", 2); + map1.put("c", 3); + map1.put("d", 4); + map1.put("e", 5); Map map2 = new HashMap<>(); - map2.put("c",3); - map2.put("d",4); - map2.put("e",5); + map2.put("c", 3); + map2.put("d", 4); + map2.put("e", 5); Map map3 = new HashMap<>(); - map3.put("d",4); - map3.put("e",5); + map3.put("d", 4); + map3.put("e", 5); rows.add(map1); rows.add(map2);