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
@ -27,6 +27,7 @@
* 【core 】 修复UserAgentUtil解析EdgA无法识别问题issue#I4MCBP@Gitee
* 【extra 】 修复Archiver路径前带/问题issue#I4NS0F@Gitee
* 【extra 】 修复getMainColor方法中参数rgbFilters无效问题pr#2034@Github
* 【core 】 修复ChineseDate无法区分闰月问题issue#I4NQQW@Gitee
-------------------------------------------------------------------------------------------------------------
# 5.7.17 (2021-12-09)

View File

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

View File

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

View File

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

View File

@ -55,6 +55,9 @@ public class ChineseDateTest {
Assert.assertEquals("六月", chineseDate.getChineseMonth());
chineseDate = new ChineseDate(2020,4,15);
Assert.assertEquals("四月", chineseDate.getChineseMonth());
chineseDate = new ChineseDate(2020,5,15);
Assert.assertEquals("闰四月", chineseDate.getChineseMonth());
}
@ -77,7 +80,29 @@ public class ChineseDateTest {
@Test
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());
}
@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());
}
}