This commit is contained in:
Looly 2021-12-25 01:31:03 +08:00
parent f8988acc88
commit 4f683f6445
5 changed files with 120 additions and 72 deletions

View File

@ -3,7 +3,7 @@
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.7.18 (2021-12-24) # 5.7.18 (2021-12-25)
### 🐣新特性 ### 🐣新特性
* 【core 】 新增CollStreamUtil.groupKeyValuepr#479@Gitee * 【core 】 新增CollStreamUtil.groupKeyValuepr#479@Gitee
@ -27,6 +27,7 @@
* 【core 】 修复UserAgentUtil解析EdgA无法识别问题issue#I4MCBP@Gitee * 【core 】 修复UserAgentUtil解析EdgA无法识别问题issue#I4MCBP@Gitee
* 【extra 】 修复Archiver路径前带/问题issue#I4NS0F@Gitee * 【extra 】 修复Archiver路径前带/问题issue#I4NS0F@Gitee
* 【extra 】 修复getMainColor方法中参数rgbFilters无效问题pr#2034@Github * 【extra 】 修复getMainColor方法中参数rgbFilters无效问题pr#2034@Github
* 【core 】 修复ChineseDate无法区分闰月问题issue#I4NQQW@Gitee
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.7.17 (2021-12-09) # 5.7.17 (2021-12-09)

View File

@ -13,7 +13,7 @@ import java.util.Date;
/** /**
* 农历日期工具最大支持到2055支持 * 农历日期工具最大支持到2099支持
* *
* <ul> * <ul>
* <li>通过公历日期构造获取对应农历</li> * <li>通过公历日期构造获取对应农历</li>
@ -27,34 +27,39 @@ public class ChineseDate {
//农历年 //农历年
private final int year; private final int year;
//农历月 //农历月润N月这个值就是N+1其他月按照显示月份赋值
private final int month; private final int month;
// 当前月份是否闰月
private final boolean isLeapMonth;
//农历日 //农历日
private final int day; private final int day;
//公历年 //公历年
private final int gyear; private final int gyear;
//公历月 //公历月从1开始计数
private final int gmonth; private final int gmonthBase1;
//公历日 //公历日
private final int gday; private final int gday;
//是否闰年
private boolean leap;
/** /**
* 通过公历日期构造 * 通过公历日期构造
* *
* @param date 公历日期 * @param date 公历日期
*/ */
public ChineseDate(Date date) { public ChineseDate(Date date) {
// 公历
final DateTime dt = DateUtil.beginOfDay(date);
gyear = dt.year();
gmonthBase1 = dt.month() + 1;
gday = dt.dayOfMonth();
// 求出和1900年1月31日相差的天数 // 求出和1900年1月31日相差的天数
int offset = (int) ((DateUtil.beginOfDay(date).getTime() / DateUnit.DAY.getMillis()) - LunarInfo.BASE_DAY); int offset = (int) ((dt.getTime() / DateUnit.DAY.getMillis()) - LunarInfo.BASE_DAY);
// 计算农历年份 // 计算农历年份
// 用offset减去每农历年的天数计算当天是农历第几天offset是当年的第几天 // 用offset减去每农历年的天数计算当天是农历第几天offset是当年的第几天
int daysOfYear; int daysOfYear;
int iYear = LunarInfo.BASE_YEAR; int iYear;
for (; iYear <= LunarInfo.MAX_YEAR; iYear++) { for (iYear = LunarInfo.BASE_YEAR; iYear <= LunarInfo.MAX_YEAR; iYear++) {
daysOfYear = LunarInfo.yearDays(iYear); daysOfYear = LunarInfo.yearDays(iYear);
if (offset < daysOfYear) { if (offset < daysOfYear) {
break; break;
@ -66,48 +71,34 @@ public class ChineseDate {
// 计算农历月份 // 计算农历月份
int leapMonth = LunarInfo.leapMonth(iYear); // 闰哪个月,1-12 int leapMonth = LunarInfo.leapMonth(iYear); // 闰哪个月,1-12
// 用当年的天数offset,逐个减去每月农历的天数求出当天是本月的第几天 // 用当年的天数offset,逐个减去每月农历的天数求出当天是本月的第几天
int iMonth; int month;
int daysOfMonth = 0; int daysOfMonth;
for (iMonth = 1; iMonth < 13 && offset > 0; iMonth++) { boolean hasLeapMonth = false;
// 闰月 for (month = 1; month < 13; month++) {
if (leapMonth > 0 && iMonth == (leapMonth + 1) && false == leap) { // 闰月如润的是五月则5表示五月6表示润五月
--iMonth; if (leapMonth > 0 && month == (leapMonth + 1)) {
leap = true;
daysOfMonth = LunarInfo.leapDays(year); daysOfMonth = LunarInfo.leapDays(year);
hasLeapMonth = true;
} else { } else {
daysOfMonth = LunarInfo.monthDays(year, iMonth); // 普通月当前面的月份存在闰月时普通月份要-1递补闰月的数字
// 如2月是闰月此时3月实际是第四个月
daysOfMonth = LunarInfo.monthDays(year, hasLeapMonth ? month - 1 : month);
} }
if (offset < daysOfMonth) {
// offset不足月结束
break;
}
offset -= daysOfMonth; offset -= daysOfMonth;
// 解除闰月
if (leap && iMonth == (leapMonth + 1)) {
leap = false;
}
} }
// offset为0时并且刚才计算的月份是闰月要校正 this.isLeapMonth = month == (leapMonth + 1);
if (offset == 0 && leapMonth > 0 && iMonth == leapMonth + 1) { if (hasLeapMonth && false == this.isLeapMonth) {
if (leap) { // 当前月份前有闰月则月份显示要-1除非当前月份就是润月
leap = false; month--;
} else {
leap = true;
--iMonth;
} }
} this.month = month;
// offset小于0时也要校正 this.day = offset + 1;
if (offset < 0) {
offset += daysOfMonth;
--iMonth;
}
month = iMonth;
day = offset + 1;
// 公历
final DateTime dt = DateUtil.date(date);
gyear = dt.year();
gmonth = dt.month() + 1;
gday = dt.dayOfMonth();
} }
/** /**
@ -119,10 +110,24 @@ public class ChineseDate {
* @since 5.2.4 * @since 5.2.4
*/ */
public ChineseDate(int chineseYear, int chineseMonth, int chineseDay) { public ChineseDate(int chineseYear, int chineseMonth, int chineseDay) {
this(chineseYear, chineseMonth, chineseDay, chineseMonth == LunarInfo.leapMonth(chineseYear) + 1);
}
/**
* 构造方法传入日期
*
* @param chineseYear 农历年
* @param chineseMonth 农历月1表示一月正月
* @param chineseDay 农历日1表示初一
* @param isLeapMonth 当前月份是否闰月
* @since 5.7.18
*/
public ChineseDate(int chineseYear, int chineseMonth, int chineseDay, boolean isLeapMonth) {
this.day = chineseDay; this.day = chineseDay;
this.month = chineseMonth; this.month = chineseMonth;
// 当月是闰月的后边的月定义为闰月如润的是五月则5表示五月6表示润五月
this.isLeapMonth = isLeapMonth;
this.year = chineseYear; this.year = chineseYear;
this.leap = DateUtil.isLeapYear(chineseYear);
//先判断传入的月份是不是闰月 //先判断传入的月份是不是闰月
int leapMonth = LunarInfo.leapMonth(chineseYear); int leapMonth = LunarInfo.leapMonth(chineseYear);
@ -131,14 +136,14 @@ public class ChineseDate {
//初始化公历年 //初始化公历年
this.gday = dateTime.dayOfMonth(); this.gday = dateTime.dayOfMonth();
//初始化公历月 //初始化公历月
this.gmonth = dateTime.month() + 1; this.gmonthBase1 = dateTime.month() + 1;
//初始化公历日 //初始化公历日
this.gyear = dateTime.year(); this.gyear = dateTime.year();
} else { } else {
//初始化公历年 //初始化公历年
this.gday = -1; this.gday = -1;
//初始化公历月 //初始化公历月
this.gmonth = -1; this.gmonthBase1 = -1;
//初始化公历日 //初始化公历日
this.gyear = -1; this.gyear = -1;
} }
@ -164,7 +169,8 @@ public class ChineseDate {
} }
/** /**
* 获取农历的月从1开始计数 * 获取农历的月从1开始计数<br>
* 此方法返回实际的月序号如一月是闰月则一月返回1润一月返回2
* *
* @return 农历的月 * @return 农历的月
* @since 5.2.4 * @since 5.2.4
@ -180,7 +186,7 @@ public class ChineseDate {
* @since 5.6.1 * @since 5.6.1
*/ */
public int getGregorianMonthBase1() { public int getGregorianMonthBase1() {
return this.gmonth; return this.gmonthBase1;
} }
/** /**
@ -190,7 +196,7 @@ public class ChineseDate {
* @since 5.6.1 * @since 5.6.1
*/ */
public int getGregorianMonth() { public int getGregorianMonth() {
return this.gmonth -1; return this.gmonthBase1 - 1;
} }
/** /**
@ -200,7 +206,7 @@ public class ChineseDate {
* @since 5.4.2 * @since 5.4.2
*/ */
public boolean isLeapMonth() { public boolean isLeapMonth() {
return ChineseMonth.isLeapMonth(this.year, this.month); return this.isLeapMonth;
} }
@ -210,7 +216,7 @@ public class ChineseDate {
* @return 返回农历月份 * @return 返回农历月份
*/ */
public String getChineseMonth() { public String getChineseMonth() {
return ChineseMonth.getChineseMonthName(isLeapMonth(), this.month, false); return getChineseMonth(false);
} }
/** /**
@ -219,7 +225,19 @@ public class ChineseDate {
* @return 返回农历月份称呼 * @return 返回农历月份称呼
*/ */
public String getChineseMonthName() { public String getChineseMonthName() {
return ChineseMonth.getChineseMonthName(isLeapMonth(), this.month, true); return getChineseMonth(true);
}
/**
* 获得农历月份中文例如二月十二月或者润一月
*
* @param isTraditional 是否传统表示例如一月传统表示为正月
* @return 返回农历月份
* @since 5.7.18
*/
public String getChineseMonth(boolean isTraditional) {
return ChineseMonth.getChineseMonthName(isLeapMonth(),
isLeapMonth() ? this.month - 1 : this.month, isTraditional);
} }
/** /**
@ -289,7 +307,7 @@ public class ChineseDate {
} }
/** /**
* 获得节日 * 获得节日闰月不计入节日中
* *
* @return 获得农历节日 * @return 获得农历节日
*/ */
@ -322,8 +340,8 @@ public class ChineseDate {
* @return 获得天干地支的年月日信息 * @return 获得天干地支的年月日信息
*/ */
public String getCyclicalYMD() { public String getCyclicalYMD() {
if (gyear >= LunarInfo.BASE_YEAR && gmonth > 0 && gday > 0) { if (gyear >= LunarInfo.BASE_YEAR && gmonthBase1 > 0 && gday > 0) {
return cyclicalm(gyear, gmonth, gday); return cyclicalm(gyear, gmonthBase1, gday);
} }
return null; return null;
} }
@ -331,21 +349,24 @@ public class ChineseDate {
/** /**
* 获得节气 * 获得节气
*
* @return 获得节气 * @return 获得节气
* @since 5.6.3 * @since 5.6.3
*/ */
public String getTerm() { public String getTerm() {
return SolarTerms.getTerm(gyear, gmonth, gday); return SolarTerms.getTerm(gyear, gmonthBase1, gday);
} }
/** /**
* 转换为标准的日期格式来表示农历日期例如2020-01-13 * 转换为标准的日期格式来表示农历日期例如2020-01-13<br>
* 如果存在闰月显示闰月月份如润二月显示2
* *
* @return 标准的日期格式 * @return 标准的日期格式
* @since 5.2.4 * @since 5.2.4
*/ */
public String toStringNormal() { public String toStringNormal() {
return String.format("%04d-%02d-%02d", this.year, this.month, this.day); return String.format("%04d-%02d-%02d", this.year,
isLeapMonth() ? this.month - 1 : this.month, this.day);
} }
@Override @Override

View File

@ -29,7 +29,7 @@ public class ChineseMonth {
* 当为非传统表示时二月十二月或者润一月等 * 当为非传统表示时二月十二月或者润一月等
* *
* @param isLeapMonth 是否闰月 * @param isLeapMonth 是否闰月
* @param month 月份从1开始 * @param month 月份从1开始如果是闰月应传入需要显示的月份
* @param isTraditional 是否传统表示例如一月传统表示为正月 * @param isTraditional 是否传统表示例如一月传统表示为正月
* @return 返回农历月份称呼 * @return 返回农历月份称呼
*/ */

View File

@ -66,9 +66,9 @@ public class LunarInfo {
} }
/** /**
* 传回农历 y年闰月的天数 * 传回农历 y年闰月的天数如果本年无闰月返回0区分大小月
* *
* @param y * @param y 农历
* @return 闰月的天数 * @return 闰月的天数
*/ */
public static int leapDays(int y) { public static int leapDays(int y) {
@ -80,7 +80,7 @@ public class LunarInfo {
} }
/** /**
* 传回农历 y年m月的总天数 * 传回农历 y年m月的总天数区分大小月
* *
* @param y * @param y
* @param m * @param m
@ -91,7 +91,8 @@ public class LunarInfo {
} }
/** /**
* 传回农历 y年闰哪个月 1-12 , 没闰传回 0 * 传回农历 y年闰哪个月 1-12 , 没闰传回 0<br>
* 此方法会返回润N月中的N如二月闰二月都返回2
* *
* @param y * @param y
* @return 润的月, 没闰传回 0 * @return 润的月, 没闰传回 0

View File

@ -55,6 +55,9 @@ public class ChineseDateTest {
Assert.assertEquals("六月", chineseDate.getChineseMonth()); Assert.assertEquals("六月", chineseDate.getChineseMonth());
chineseDate = new ChineseDate(2020,4,15); chineseDate = new ChineseDate(2020,4,15);
Assert.assertEquals("四月", chineseDate.getChineseMonth());
chineseDate = new ChineseDate(2020,5,15);
Assert.assertEquals("闰四月", chineseDate.getChineseMonth()); Assert.assertEquals("闰四月", chineseDate.getChineseMonth());
} }
@ -77,7 +80,29 @@ public class ChineseDateTest {
@Test @Test
public void dateTest2(){ public void dateTest2(){
ChineseDate date = new ChineseDate(DateUtil.parse("2020-10-19 11:12:23")); ChineseDate date = new ChineseDate(DateUtil.parse("2020-10-19"));
Assert.assertEquals("庚子鼠年 九月初三", date.toString()); Assert.assertEquals("庚子鼠年 九月初三", date.toString());
} }
@Test
public void dateTest2_2(){
ChineseDate date = new ChineseDate(DateUtil.parse("2020-07-20"));
Assert.assertEquals("庚子鼠年 五月三十", date.toString());
}
@Test
public void dateTest3(){
// 初一offset为0测试
ChineseDate date = new ChineseDate(DateUtil.parse("2099-03-22"));
Assert.assertEquals("己未羊年 闰二月初一", date.toString());
}
@Test
public void leapMonthTest(){
final ChineseDate c1 = new ChineseDate(DateUtil.parse("2028-05-28"));
final ChineseDate c2 = new ChineseDate(DateUtil.parse("2028-06-27"));
Assert.assertEquals("戊申猴年 五月初五", c1.toString());
Assert.assertEquals("戊申猴年 闰五月初五", c2.toString());
}
} }