新增根据日期获取节气

This commit is contained in:
Zhu Kaixiao 2021-04-02 15:15:46 +08:00
parent 47134c0536
commit 6e6aa91a90
3 changed files with 288 additions and 6 deletions

View File

@ -1,10 +1,7 @@
package cn.hutool.core.date; package cn.hutool.core.date;
import cn.hutool.core.convert.NumberChineseFormatter; import cn.hutool.core.convert.NumberChineseFormatter;
import cn.hutool.core.date.chinese.ChineseMonth; import cn.hutool.core.date.chinese.*;
import cn.hutool.core.date.chinese.GanZhi;
import cn.hutool.core.date.chinese.LunarFestival;
import cn.hutool.core.date.chinese.LunarInfo;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import java.util.Date; import java.util.Date;
@ -264,6 +261,15 @@ public class ChineseDate {
return null; return null;
} }
/**
* 获得节气
* @return 获得节气
*/
public String getTerm() {
return SolarTerms.getTerm(gyear, gmonth, gday);
}
/** /**
* 转换为标准的日期格式来表示农历日期例如2020-01-13 * 转换为标准的日期格式来表示农历日期例如2020-01-13
* *
@ -347,4 +353,4 @@ public class ChineseDate {
// ------------------------------------------------------- private method end // ------------------------------------------------------- private method end
} }

View File

@ -1,15 +1,132 @@
package cn.hutool.core.date.chinese; package cn.hutool.core.date.chinese;
import cn.hutool.core.date.ChineseDate;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.NumberUtil;
import java.time.LocalDate;
import java.util.Date;
/** /**
* 24节气相关信息 * 24节气相关信息
* *
* @author looly * @author looly, zak
* @since 5.4.1 * @since 5.4.1
*/ */
public class SolarTerms { public class SolarTerms {
/**
* 24节气
*/
public static final String[] TERMS = {
"小寒", "大寒", "立春", "雨水", "惊蛰", "春分",
"清明", "谷雨", "立夏", "小满", "芒种", "夏至",
"小暑", "大暑", "立秋", "处暑", "白露", "秋分",
"寒露", "霜降", "立冬", "小雪", "大雪", "冬至"
};
/**
* 小寒
*/
public static final String XIAO_HAN = TERMS[0];
/**
* 大寒
*/
public static final String DA_HAN = TERMS[1];
/**
* 立春
*/
public static final String LI_CHUN = TERMS[2];
/**
* 雨水
*/
public static final String YU_SHUI = TERMS[3];
/**
* 惊蛰
*/
public static final String JING_ZHE = TERMS[4];
/**
* 春分
*/
public static final String CHUN_FEN = TERMS[5];
/**
* 清明
*/
public static final String QING_MING = TERMS[6];
/**
* 谷雨
*/
public static final String GU_YU = TERMS[7];
/**
* 立夏
*/
public static final String LI_XIA = TERMS[8];
/**
* 小满
*/
public static final String XIAO_MAN = TERMS[9];
/**
* 芒种
*/
public static final String MANG_ZHONG = TERMS[10];
/**
* 夏至
*/
public static final String XIA_ZHI = TERMS[11];
/**
* 小暑
*/
public static final String XIAO_SHU = TERMS[12];
/**
* 大暑
*/
public static final String DA_SHU = TERMS[13];
/**
* 立秋
*/
public static final String LI_QIU = TERMS[14];
/**
* 处暑
*/
public static final String CHU_SHU = TERMS[15];
/**
* 白露
*/
public static final String BAI_LU = TERMS[16];
/**
* 秋分
*/
public static final String QIU_FEN = TERMS[17];
/**
* 寒露
*/
public static final String HAN_LU = TERMS[18];
/**
* 霜降
*/
public static final String SHUANG_JIANG = TERMS[19];
/**
* 立冬
*/
public static final String LI_DONG = TERMS[20];
/**
* 小雪
*/
public static final String XIAO_XUE = TERMS[21];
/**
* 大雪
*/
public static final String DA_XUE = TERMS[22];
/**
* 冬至
*/
public static final String DONG_ZHI = TERMS[23];
/** /**
* 根据节气修正干支月 * 根据节气修正干支月
* *
@ -40,6 +157,85 @@ public class SolarTerms {
return NumberUtil.parseInt(_calday[n - 1]); return NumberUtil.parseInt(_calday[n - 1]);
} }
/**
* 根据日期获取节气
* @param date 日期
* @return 返回指定日期所处的节气
*/
public static String getTerm(Date date) {
final DateTime dt = DateUtil.date(date);
return getTerm(dt.year(), dt.month() + 1, dt.dayOfMonth());
}
/**
* 根据农历日期获取节气
* @param chineseDate 农历日期
* @return 返回指定日期所处的节气
*/
public static String getTerm(ChineseDate chineseDate) {
return chineseDate.getTerm();
}
/**
* 根据日期获取节气
* @param date 日期
* @return 返回指定日期所处的节气
*/
public static String getTerm(LocalDate date) {
return getTerm0(date.getYear(), date.getMonthValue(), date.getDayOfMonth());
}
/**
* 根据年月日获取节气
* @param year
* @param mouth
* @param day
* @return 返回指定年月日所处的节气
*/
public static String getTerm(int year, int mouth, int day) {
return getTerm(LocalDate.of(year, mouth, day));
}
/**
* 根据年月日获取节气, 内部方法不对月和日做有效校验
* @param year
* @param mouth
* @param day
* @return 返回指定年月日所处的节气
*/
static String getTerm0(int year, int mouth, int day) {
if (year < 1900 || year > 2100) {
throw new IllegalArgumentException("只支持1900-2100之间的日期获取节气");
}
String termTable = S_TERM_INFO[year - 1900];
// 节气速查表中每5个字符含有4个节气通过月份直接计算偏移
int segment = (mouth + 1) / 2 - 1;
int termInfo = NumberUtil.parseInt("0x" + termTable.substring(segment * 5, (segment + 1) * 5));
String[] segmentTable = new String[24];
segmentTable[0] = String.valueOf(termInfo).substring(0, 1);
segmentTable[1] = String.valueOf(termInfo).substring(1, 3);
segmentTable[2] = String.valueOf(termInfo).substring(3, 4);
segmentTable[3] = String.valueOf(termInfo).substring(4, 6);
// 奇数月份的节气在前2个偶数月份的节气在后两个
int segmentOffset = (mouth & 1) == 1 ? 0 : 2;
if (day < NumberUtil.parseInt(segmentTable[segmentOffset])) {
int idx = segment * 4 + segmentOffset - 1;
return TERMS[idx < 0 ? 23 : idx];
}
if(day >= NumberUtil.parseInt(segmentTable[segmentOffset + 1])) {
return TERMS[segment * 4 + segmentOffset + 1];
}
return TERMS[segment * 4 + segmentOffset];
}
/** /**
* 1900-2100各年的24节气日期速查表 * 1900-2100各年的24节气日期速查表
* 此表来自https://github.com/jjonline/calendar.js/blob/master/calendar.js * 此表来自https://github.com/jjonline/calendar.js/blob/master/calendar.js

View File

@ -0,0 +1,80 @@
package cn.hutool.core.date.chinese;
import cn.hutool.core.date.ChineseDate;
import cn.hutool.core.date.DateUtil;
import org.junit.Assert;
import org.junit.Test;
import java.util.Date;
import static org.junit.Assert.*;
public class SolarTermsTest {
@Test
public void getTermTest() {
Assert.assertEquals(SolarTerms.DONG_ZHI, SolarTerms.getTerm(2021, 1, 4));
Assert.assertEquals(SolarTerms.XIAO_HAN, SolarTerms.getTerm(2021, 1, 5));
Assert.assertEquals(SolarTerms.XIAO_HAN, SolarTerms.getTerm(2021, 1, 19));
Assert.assertEquals(SolarTerms.DA_HAN, SolarTerms.getTerm(2021, 1, 20));
Assert.assertEquals(SolarTerms.DA_HAN, SolarTerms.getTerm(2021, 2, 2));
Assert.assertEquals(SolarTerms.LI_CHUN, SolarTerms.getTerm(2021, 2, 3));
Assert.assertEquals(SolarTerms.LI_CHUN, SolarTerms.getTerm(2021, 2, 17));
Assert.assertEquals(SolarTerms.YU_SHUI, SolarTerms.getTerm(2021, 2, 18));
Assert.assertEquals(SolarTerms.YU_SHUI, SolarTerms.getTerm(2021, 3, 4));
Assert.assertEquals(SolarTerms.JING_ZHE, SolarTerms.getTerm(2021, 3, 5));
Assert.assertEquals(SolarTerms.JING_ZHE, SolarTerms.getTerm(2021, 3, 19));
Assert.assertEquals(SolarTerms.CHUN_FEN, SolarTerms.getTerm(2021, 3, 20));
Assert.assertEquals(SolarTerms.CHUN_FEN, SolarTerms.getTerm(2021, 4, 3));
Assert.assertEquals(SolarTerms.QING_MING, SolarTerms.getTerm(2021, 4, 4));
Assert.assertEquals(SolarTerms.QING_MING, SolarTerms.getTerm(2021, 4, 10));
Assert.assertEquals(SolarTerms.QING_MING, SolarTerms.getTerm(2021, 4, 19));
Assert.assertEquals(SolarTerms.GU_YU, SolarTerms.getTerm(2021, 4, 20));
Assert.assertEquals(SolarTerms.GU_YU, SolarTerms.getTerm(2021, 4, 29));
Assert.assertEquals(SolarTerms.GU_YU, SolarTerms.getTerm(2021, 5, 4));
Assert.assertEquals(SolarTerms.LI_XIA, SolarTerms.getTerm(2021, 5, 5));
Assert.assertEquals(SolarTerms.LI_XIA, SolarTerms.getTerm(2021, 5, 9));
Assert.assertEquals(SolarTerms.LI_XIA, SolarTerms.getTerm(2021, 5, 20));
Assert.assertEquals(SolarTerms.XIAO_MAN, SolarTerms.getTerm(2021, 5, 21));
Assert.assertEquals(SolarTerms.XIAO_MAN, SolarTerms.getTerm(2021, 6, 4));
Assert.assertEquals(SolarTerms.MANG_ZHONG, SolarTerms.getTerm(2021, 6, 5));
Assert.assertEquals(SolarTerms.MANG_ZHONG, SolarTerms.getTerm(2021, 6, 20));
Assert.assertEquals(SolarTerms.XIA_ZHI, SolarTerms.getTerm(2021, 6, 21));
Assert.assertEquals(SolarTerms.XIA_ZHI, SolarTerms.getTerm(2021, 7, 6));
Assert.assertEquals(SolarTerms.XIAO_SHU, SolarTerms.getTerm(2021, 7, 7));
Assert.assertEquals(SolarTerms.XIAO_SHU, SolarTerms.getTerm(2021, 7, 21));
Assert.assertEquals(SolarTerms.DA_SHU, SolarTerms.getTerm(2021, 7, 22));
Assert.assertEquals(SolarTerms.DA_SHU, SolarTerms.getTerm(2021, 8, 6));
Assert.assertEquals(SolarTerms.LI_QIU, SolarTerms.getTerm(2021, 8, 7));
Assert.assertEquals(SolarTerms.CHU_SHU, SolarTerms.getTerm(2021, 8, 23));
Assert.assertEquals(SolarTerms.CHU_SHU, SolarTerms.getTerm(2021, 9, 6));
Assert.assertEquals(SolarTerms.BAI_LU, SolarTerms.getTerm(2021, 9, 7));
Assert.assertEquals(SolarTerms.BAI_LU, SolarTerms.getTerm(2021, 9, 22));
Assert.assertEquals(SolarTerms.QIU_FEN, SolarTerms.getTerm(2021, 9, 23));
Assert.assertEquals(SolarTerms.QIU_FEN, SolarTerms.getTerm(2021, 10, 7));
Assert.assertEquals(SolarTerms.HAN_LU, SolarTerms.getTerm(2021, 10, 8));
Assert.assertEquals(SolarTerms.HAN_LU, SolarTerms.getTerm(2021, 10, 22));
Assert.assertEquals(SolarTerms.SHUANG_JIANG, SolarTerms.getTerm(2021, 10, 23));
Assert.assertEquals(SolarTerms.SHUANG_JIANG, SolarTerms.getTerm(2021, 11, 6));
Assert.assertEquals(SolarTerms.LI_DONG, SolarTerms.getTerm(2021, 11, 7));
Assert.assertEquals(SolarTerms.LI_DONG, SolarTerms.getTerm(2021, 11, 21));
Assert.assertEquals(SolarTerms.XIAO_XUE, SolarTerms.getTerm(2021, 11, 22));
Assert.assertEquals(SolarTerms.XIAO_XUE, SolarTerms.getTerm(2021, 12, 6));
Assert.assertEquals(SolarTerms.DA_XUE, SolarTerms.getTerm(2021, 12, 7));
Assert.assertEquals(SolarTerms.DA_XUE, SolarTerms.getTerm(2021, 12, 20));
Assert.assertEquals(SolarTerms.DONG_ZHI, SolarTerms.getTerm(2021, 12, 21));
}
@Test
public void getTermByDateTest() {
Assert.assertEquals(SolarTerms.CHUN_FEN, SolarTerms.getTerm(DateUtil.parseDate("2021-04-02")));
}
@Test
public void getTermByChineseDateTest() {
Assert.assertEquals(SolarTerms.QING_MING, SolarTerms.getTerm(new ChineseDate(2021, 2, 25)));
}
}