From c4afdb811bbbae544e9fd740f68a188b50278e7c Mon Sep 17 00:00:00 2001 From: jie65535 Date: Mon, 26 Jan 2026 17:42:46 +0800 Subject: [PATCH] Add Lunar calendar context --- .../heqiao2010/lunar/LunarCalendar.java | 497 ++++++++++++++++++ .../github/heqiao2010/lunar/LunarCodes.java | 157 ++++++ .../github/heqiao2010/lunar/LunarData.java | 423 +++++++++++++++ .../github/heqiao2010/lunar/LunarUtils.java | 98 ++++ src/main/kotlin/JChatGPT.kt | 5 +- src/main/kotlin/util/LunarDateUtil.kt | 163 ++++++ 6 files changed, 1342 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/github/heqiao2010/lunar/LunarCalendar.java create mode 100644 src/main/java/com/github/heqiao2010/lunar/LunarCodes.java create mode 100644 src/main/java/com/github/heqiao2010/lunar/LunarData.java create mode 100644 src/main/java/com/github/heqiao2010/lunar/LunarUtils.java create mode 100644 src/main/kotlin/util/LunarDateUtil.kt diff --git a/src/main/java/com/github/heqiao2010/lunar/LunarCalendar.java b/src/main/java/com/github/heqiao2010/lunar/LunarCalendar.java new file mode 100644 index 0000000..05c62e8 --- /dev/null +++ b/src/main/java/com/github/heqiao2010/lunar/LunarCalendar.java @@ -0,0 +1,497 @@ +package com.github.heqiao2010.lunar; + +import java.util.*; + +/** + * 中国农历 + * Created by joel on 2019/3/31. + * + * @author joel + */ +public class LunarCalendar extends GregorianCalendar { + + /** + * serialVersionUID + */ + private static final long serialVersionUID = 7241031233810655166L; + + // ------------------------ 农历相关成员变量 -------------------------------- + + // 农历年,和公历可能不一样 + private int lunarYear; + // 农历月(范围1-12和公历不一样) + private int lunarMonth; + // 农历日期 + private int dayOfLunarMonth; + // 是否为闰月日期 + private boolean isLeapMonth = false; + // 农历这年闰月,如果不闰月,默认为0 + private int leapMonth = 0; + + // ------------------------ 构造方法 -------------------------------- + + public LunarCalendar() { + super(); + computeBySolarDate(get(Calendar.YEAR), get(Calendar.MONTH), get(Calendar.DATE)); + } + + public LunarCalendar(TimeZone zone) { + super(zone); + computeBySolarDate(get(Calendar.YEAR), get(Calendar.MONTH), get(Calendar.DATE)); + } + + public LunarCalendar(Locale aLocale) { + super(aLocale); + computeBySolarDate(get(Calendar.YEAR), get(Calendar.MONTH), get(Calendar.DATE)); + } + + public LunarCalendar(TimeZone zone, Locale aLocale) { + super(zone, aLocale); + computeBySolarDate(get(Calendar.YEAR), get(Calendar.MONTH), get(Calendar.DATE)); + } + + /** + * 通过公历年、月、日构造 + * @param year 公历年 + * @param month 公历月 + * @param dayOfMonth 公历日 + */ + public LunarCalendar(int year, int month, int dayOfMonth) { + super(year, month, dayOfMonth); + computeBySolarDate(get(Calendar.YEAR), get(Calendar.MONTH), get(Calendar.DATE)); + } + + public LunarCalendar(int year, int month, int dayOfMonth, int hourOfDay, int minute) { + super(year, month, dayOfMonth, hourOfDay, minute); + computeBySolarDate(get(Calendar.YEAR), get(Calendar.MONTH), get(Calendar.DATE)); + } + + public LunarCalendar(int year, int month, int dayOfMonth, int hourOfDay, int minute, int second) { + super(year, month, dayOfMonth, hourOfDay, minute, second); + computeBySolarDate(get(Calendar.YEAR), get(Calendar.MONTH), get(Calendar.DATE)); + } + + /** + * 通过农历年、月、日构造 + * + * @param lunarYear 农历年 + * @param lunarMonth 农历月份,范围1-12 + * @param dayOfLunarMonth 农历日 + * @param isLeapMonth 是否闰月 + */ + public LunarCalendar(int lunarYear, int lunarMonth, int dayOfLunarMonth, boolean isLeapMonth) { + computeByLunarDate(lunarYear, lunarMonth, dayOfLunarMonth, isLeapMonth); + } + + /** + * 通过公历构造 + * + * @param calendar  公历日期 + */ + public LunarCalendar(Calendar calendar) { + super(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), + calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), calendar.get(Calendar.SECOND)); + computeBySolarDate(get(Calendar.YEAR), get(Calendar.MONTH), get(Calendar.DATE)); + } + + // ------------------------ 静态方法 -------------------------------- + + /** + * 公历转农历 + * + * @param solar  公历日期 + * @return 农历日期 + */ + public static LunarCalendar solar2Lunar(Calendar solar) { + return new LunarCalendar(solar); + } + + /** + * 农历转公历 + * + * @param lunarYear  农历年 + * @param lunarMonth  农历月,从1开始 + * @param LunarDate  农历日 + * @param isLeapMonth  是否润月 + * @return 公历日期 + */ + public static Calendar lunar2Solar(int lunarYear, int lunarMonth, int LunarDate, boolean isLeapMonth) { + LunarCalendar ret = new LunarCalendar(); + ret.computeByLunarDate(lunarYear, lunarMonth, LunarDate, isLeapMonth); + return ret; + } + + // ------------------------ 成员方法 -------------------------------- + + /** + * 公历上的操作,加减均是公历上的“一年”,“一个月” + * @param field {@link java.util.Calendar} YEAR/MONTH/DATE + * @param amount 数量,可正可负 + */ + @Override + public void add(int field, int amount) { + super.add(field, amount); + computeBySolarDate(get(Calendar.YEAR), get(Calendar.MONTH), get(Calendar.DATE)); + } + + /** + * 农历上的年月日,加减均是农历上的“一年”,“一个月” + * @param field {@link java.util.Calendar} YEAR/MONTH/DATE + * @param amount 数量,可正可负 + */ + public void addByLunar(int field, int amount) { + switch (field) { + case Calendar.DATE: + super.add(Calendar.DATE, amount); + computeBySolarDate(get(Calendar.YEAR), get(Calendar.MONTH), get(Calendar.DATE)); + break; + case Calendar.MONTH: + addLunarMonths(amount); + break; + case Calendar.YEAR: + // 增加一个农历年,保持月/日不变,清空闰月状态 + checkComputeLunarDate(lunarYear + amount, lunarMonth, dayOfLunarMonth, false); + break; + default: + throw new IllegalArgumentException(String.format("unsupported field: %d", field)); + } + } + + /** + * 计算月份加减 + * + * @param amount 数量 + */ + public void addLunarMonths(int amount) { + int y = lunarYear; + int m = -1; + int index = LunarCodes.monthIndex(y, lunarMonth, isLeapMonth); + boolean isLeapMonth = false; + int sum = index + amount; + if (amount > 0) { + for (int _y = lunarYear; _y < LunarData.MAX_YEAR; _y++) { + final short[] a = LunarCodes.monthCodes(_y); + int lunarMonths = a.length - 1; + sum -= lunarMonths; + if (sum > 0) { + y++; + } + if (sum <= 0) { + if (sum == 0) m = lunarMonths; + else m = lunarMonths + sum; + isLeapMonth = a[0] > 0 && a[0] + 1 == m; + if (isLeapMonth || a[0] > 0 && a[0] < m) { + m--; + } + break; + } + } + if (sum > 0) { + throw new IllegalArgumentException(String.format("add of month out of range: %d", amount)); + } + } else if (amount < 0) { + if (sum > 0) { + m = sum; + } else if (sum == 0) { + Map.Entry en = LunarCodes.month(--y, -1); + m = en.getKey(); + isLeapMonth = en.getValue(); + } else { + for (int i = lunarYear - 1; i > LunarData.MINI_YEAR; i--) { + int lunarMonths = LunarCodes.monthCodes(i).length - 1; + sum += lunarMonths; + y--; + if (sum >= 0) { + Map.Entry en; + if (sum == 0) { + en = LunarCodes.month(--y, -1); + } else { + en = LunarCodes.month(y, sum + 1); + } + m = en.getKey(); + isLeapMonth = en.getValue(); + break; + } + } + } + if (sum < 0) { + throw new IllegalArgumentException(String.format("add of month out of range: %d", amount)); + } + } + checkComputeLunarDate(y, m, dayOfLunarMonth, isLeapMonth); + } + + /** + * 校验 day of month 是否是合法的,如果越限则从30号减到29号 + * + * @param y lunar year + * @param m lunar month + * @param d lunar day of month + * @param isLeap 闰月 + */ + private void checkComputeLunarDate(int y, int m, int d, boolean isLeap) { + int days = d; + if (d > 29 && d > LunarUtils.lengthOfMonth(y, m, isLeap)) { + days--; + } + computeByLunarDate(y, m, days, isLeap); + } + + @Override + public void set(int field, int value) { + super.set(field, value); + computeBySolarDate(get(Calendar.YEAR), get(Calendar.MONTH), get(Calendar.DATE)); + } + + @Override + public void roll(int field, int amount) { + super.roll(field, amount); + computeBySolarDate(get(Calendar.YEAR), get(Calendar.MONTH), get(Calendar.DATE)); + } + + @Override + public String toString() { + if (this.lunarYear < LunarData.MINI_YEAR || this.lunarYear > LunarData.MAX_YEAR || this.lunarMonth < 1 + || this.lunarMonth > 12 || this.dayOfLunarMonth < 1 + || this.dayOfLunarMonth > 30) { + return String.format("Wrong lunar date: %d %d %d", lunarYear, lunarMonth, dayOfLunarMonth); + } + return String.format("%s年%s%s月%s", LunarData.getYearName(this.lunarYear), this.isLeapMonth() ? "闰" : "", + LunarData.getMonthName(this.lunarMonth), LunarData.getDayName(this.dayOfLunarMonth)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof LunarCalendar)) return false; + if (!super.equals(o)) return false; + LunarCalendar that = (LunarCalendar) o; + return lunarYear == that.lunarYear && + lunarMonth == that.lunarMonth && + dayOfLunarMonth == that.dayOfLunarMonth && + isLeapMonth == that.isLeapMonth && + leapMonth == that.leapMonth; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + lunarYear; + result = 31 * result + lunarMonth; + result = 31 * result + dayOfLunarMonth; + result = 31 * result + leapMonth; + result = 31 * result + (isLeapMonth ? 1 : 0); + return result; + } + + @Override + public Object clone() { + LunarCalendar other = (LunarCalendar) super.clone(); + other.lunarYear = getLunarYear(); + other.lunarMonth = getLunarMonth(); + other.dayOfLunarMonth = getDayOfLunarMonth(); + other.leapMonth = getLeapMonth(); + other.isLeapMonth = isLeapMonth(); + return other; + } + + /** + * 返回农历日期,不包含年份 + * + * @param showLeap  是否显示闰月的闰字 + * @return 农历日期 + */ + public String getLunar(boolean showLeap) { + if (this.lunarMonth < 1 || this.lunarMonth > 12 || this.dayOfLunarMonth < 1 + || this.dayOfLunarMonth > 30) { + throw new IllegalArgumentException(String.format("Wrong lunar dayOfLunarMonth: %d %d", lunarMonth, dayOfLunarMonth)); + } + if (showLeap) { + return String.format("%s%s月%s", this.isLeapMonth() ? "闰" : "", LunarData.getMonthName(this.lunarMonth), + LunarData.getDayName(this.dayOfLunarMonth)); + } else { + return String.format("%s月%s", LunarData.getMonthName(this.lunarMonth), + LunarData.getDayName(this.dayOfLunarMonth)); + } + } + + /** + * 返回中国农历的全名 + * + * @return String + */ + public String getFullLunarName() { + return String.format("%s %s %s", this, LunarData.getTraditionalYearName(this.lunarYear), + LunarData.getAnimalYearName(this.lunarYear)); + } + + /** + * 创建LunarInfo中某一年的一列公历日历编码
+ * 公历日历编码:年份+月份+天,用于查询某个公历日期在某个LunarInfo列的哪一个区间
+ * + * @param solarYear 年份 + * @return 公历日历编码 + */ + private int[] builderSolarCodes(int solarYear) { + if (solarYear < LunarData.MINI_YEAR || solarYear > LunarData.MAX_YEAR) { + throw new IllegalArgumentException("Illegal solar year: " + solarYear); + } + int lunarIndex = solarYear - LunarData.MINI_YEAR; + int[] solarCodes = new int[LunarData.LUNAR_INFO[lunarIndex].length]; + for (int i = 0; i < solarCodes.length; i++) { + if (0 == i) { // 第一个数表示闰月,不用更改 + solarCodes[i] = LunarData.LUNAR_INFO[lunarIndex][i]; + } else if (1 == i) { + if (LunarData.LUNAR_INFO[lunarIndex][1] > 999) { + // 这年农历一月一日对应的公历实际是上一年的 + solarCodes[i] = (solarYear - 1) * 10000 + LunarData.LUNAR_INFO[lunarIndex][i]; + } else { + solarCodes[i] = solarYear * 10000 + LunarData.LUNAR_INFO[lunarIndex][i]; + } + } else { + solarCodes[i] = solarYear * 10000 + LunarData.LUNAR_INFO[lunarIndex][i]; + } + } + return solarCodes; + } + + /** + * 通过给定的农历日期,计算公历日期 + * + * @param lunarYear  农历年 + * @param lunarMonth  农历月,从1开始 + * @param lunarDate  农历日期 + * @param isLeapMonth  是否为闰月 + */ + private void computeByLunarDate(final int lunarYear, final int lunarMonth, final int lunarDate, + final boolean isLeapMonth) { + if (lunarYear < LunarData.MINI_YEAR || lunarYear > LunarData.MAX_YEAR) { + throw new IllegalArgumentException(String.format("LunarYear must in (%d, %d)", LunarData.MINI_YEAR, + LunarData.MAX_YEAR)); + } + this.lunarYear = lunarYear; + this.lunarMonth = lunarMonth; + this.dayOfLunarMonth = lunarDate; + this.isLeapMonth = isLeapMonth; + short code = LunarCodes.lunarMonthCode(lunarYear, lunarMonth, isLeapMonth); + + // 对设置的day of month 进行检查 + if (lunarDate == 30) { + long length = LunarCodes.lengthOfMonth(lunarYear, lunarMonth, code); + if (length != 30) { + throw new IllegalArgumentException(String.format("农历%d年%d月, 闰月=%s,月天数为%d < %d", lunarYear, + lunarMonth, isLeapMonth, length, lunarDate)); + } + } + + super.set(Calendar.YEAR, lunarYear + LunarCodes.codeYear(code)); + super.set(Calendar.MONTH, LunarCodes.codeMonth(code) - 1); + super.set(Calendar.DATE, LunarCodes.codeDay(code)); + super.add(Calendar.DATE, lunarDate - 1); + } + + /** + * 通过给定公历日期,计算农历日期各个域值 + *
+ * 这个方法可能会被调用多次,后续看能否再做优化 + *
+ * + * @param solarYear 公历年 + * @param solarMonth 公历月,0-11 + * @param solarDate 公历日 + */ + private void computeBySolarDate(final int solarYear, final int solarMonth, final int solarDate) { + if (solarYear < LunarData.MINI_YEAR + || (solarYear == LunarData.MINI_YEAR && solarMonth < LunarData.MINI_MONTH) + || (solarYear == LunarData.MINI_YEAR && solarMonth == LunarData.MINI_MONTH && solarDate < LunarData.MINI_DATE) + || solarYear > LunarData.MAX_YEAR + || (solarYear == LunarData.MAX_YEAR && solarMonth > LunarData.MAX_MONTH) + || (solarYear == LunarData.MAX_YEAR && solarMonth == LunarData.MAX_MONTH && solarDate > LunarData.MAX_DATE) + ) { + // 有些中间过程日期会超出可计算范围 + // throw new IllegalArgumentException("Illegal solar year: " + solarYear); + return; + } + int solarCode = solarYear * 10000 + 100 * (1 + solarMonth) + solarDate; // 公历码 + leapMonth = LunarData.LUNAR_INFO[solarYear - LunarData.MINI_YEAR][0]; + int[] solarCodes = builderSolarCodes(solarYear); + int newMonth = LunarUtils.binSearch(solarCodes, solarCode); + if (-1 == newMonth) { + throw new IllegalArgumentException("No lunarInfo found by solarCode: " + solarCode); + } + int xDate = Long.valueOf(LunarCodes.solarDateCodesDiff(solarCode, solarCodes[newMonth], Calendar.DATE)).intValue(); + if (0 == newMonth) {// 在上一年 + int preYear = solarYear - 1; + leapMonth = LunarData.LUNAR_INFO[preYear - LunarData.MINI_YEAR][0]; + short[] preSolarCodes = LunarData.LUNAR_INFO[preYear - LunarData.MINI_YEAR]; + // 取上年农历12月1号公历日期码 + int nearSolarCode = preSolarCodes[preSolarCodes.length - 1]; // 上一年12月1号 + // 下一年公历1月表示为了13月,这里做翻译,并计算出日期码 + nearSolarCode = (nearSolarCode / 100 == 13 ? preYear + 1 : preYear) * 10000 + + (nearSolarCode / 100 == 13 ? nearSolarCode - 1200 : nearSolarCode); + if (nearSolarCode > solarCode) {// 此公历日期在上一年农历12月1号,之前,即在上年农历11月内 + newMonth = 11; + // 取农历11月的公历码 + nearSolarCode = preYear * 10000 + preSolarCodes[preSolarCodes.length - 2]; + } else {// 此公历日期在上一年农历12月内 + newMonth = 12; + } + xDate = Long.valueOf(LunarCodes.solarDateCodesDiff(solarCode, nearSolarCode, Calendar.DATE)).intValue(); + if (xDate < 0) { + throw new IllegalArgumentException("Wrong solarCode: " + solarCode); + } + this.dayOfLunarMonth = 1 + xDate; + this.lunarYear = preYear; + this.lunarMonth = newMonth; + this.isLeapMonth = 0 != leapMonth && (leapMonth == newMonth); + } else if (solarCodes.length == newMonth + 1 && xDate >= 30) {// 在下一年(公历12月只有30天) + newMonth = 1; // 农历肯定是1月 + // 取下一年的公历日期码 + short[] nextSolarCodes = LunarData.LUNAR_INFO[solarYear + 1 - LunarData.MINI_YEAR]; + // 取下一年农历1月1号公历日期码 + int nearSolarCode = solarYear * 10000 + nextSolarCodes[1]; // 下一年农历1月1号公历日期码 + xDate = Long.valueOf(LunarCodes.solarDateCodesDiff(solarCode, nearSolarCode, Calendar.DATE)).intValue(); + if (xDate < 0) { + throw new IllegalArgumentException("Wrong solarCode: " + solarCode); + } + this.dayOfLunarMonth = 1 + xDate; + this.lunarYear = solarYear + 1; // 农历年到了下一年 + this.lunarMonth = newMonth; + this.isLeapMonth = false; // 农历1月不可能为闰月 + } else { + if (xDate < 0) { + throw new IllegalArgumentException("Wrong solarCode: " + solarCode); + } + this.dayOfLunarMonth = 1 + xDate; + this.lunarYear = solarYear; + this.isLeapMonth = 0 != leapMonth && (leapMonth + 1 == newMonth); + if (0 != leapMonth && leapMonth < newMonth) { + this.lunarMonth = newMonth - 1; + } else { + this.lunarMonth = newMonth; + } + } + } + + // ------------------------ getter and setter -------------------------------- + + public int getLunarYear() { + return lunarYear; + } + + public int getLunarMonth() { + return lunarMonth; + } + + public int getDayOfLunarMonth() { + return dayOfLunarMonth; + } + + public int getLeapMonth() { + return leapMonth; + } + + public boolean isLeapMonth() { + return isLeapMonth; + } +} diff --git a/src/main/java/com/github/heqiao2010/lunar/LunarCodes.java b/src/main/java/com/github/heqiao2010/lunar/LunarCodes.java new file mode 100644 index 0000000..ad5c737 --- /dev/null +++ b/src/main/java/com/github/heqiao2010/lunar/LunarCodes.java @@ -0,0 +1,157 @@ +package com.github.heqiao2010.lunar; + +import java.util.AbstractMap; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.Map; + +import static com.github.heqiao2010.lunar.LunarData.LUNAR_INFO; + +/** + * 农历/公历对照代码工具方法集合 + */ +public class LunarCodes { + + /** + * 农历年的代码数组 + * @param year 农历年 + * @return 代码数组 + */ + public static short[] monthCodes(int year) { + return LUNAR_INFO[year - LunarData.MINI_YEAR]; + } + + /** + * 从代码中获取年份,大于12时表示下一年 + * @param code 代码 + * @return 0/1 今年或者下一年 + */ + public static int codeYear(int code) { + return code / 100 > 12 ? 1 : 0; + } + + /** + * 从代码中获取农历月初一在公历中的月份 + * @param code 代码 + * @return 公历月份 + */ + public static int codeMonth(int code) { + int m = code / 100; + if (m > 12) m -= 12; + return m; + } + + /** + * 从代码中获取农历日在公历中的日 (day of month) + * @param code 代码 + * @return 公历日 + */ + public static int codeDay(int code) { + return code % 100; + } + + /** + * 求一个农历月的天数 + * @param lunarYear 农历年 + * @param month 农历月 + * @param code 农历月有日期,Mdd 表示 + * @return 月的天数 + */ + public static long lengthOfMonth(int lunarYear, int month, short code) { + short md2; + short[] starts = monthCodes(lunarYear); + int y2 = lunarYear; + if (month + 1 < starts.length && starts[month] == code) { + md2 = starts[month + 1]; + } else if (month + 2 < starts.length && starts[month + 1] == code) { + md2 = starts[month + 2]; + } else if (lunarYear - LunarData.MINI_YEAR + 1 < LUNAR_INFO.length) { + md2 = monthCodes(lunarYear + 1)[1]; + y2 ++; + } else { + throw new IllegalArgumentException("lunar date out of range"); + } + + int y1 = lunarYear + codeYear(code); + int m1 = codeMonth(code); + int d1 = codeDay(code); + + y2 += codeYear(md2); + int m2 = codeMonth(md2); + int d2 = codeDay(md2); + + Calendar c1 = Calendar.getInstance(); + c1.set(y1, m1 - 1, d1); + Calendar c2 = Calendar.getInstance(); + c2.set(y2, m2 - 1, d2); + + return LunarUtils.solarDiff(c2, c1, Calendar.DATE); + } + + /** + * 根据农历年和 LUNAR_INFO 中的下标来确定月份和闰月 + * + * @param year 农历年 + * @param index LUNAR_INFO 月份数组中的下标 + * @return 月, 闰月 + */ + public static Map.Entry month(int year, int index) { + short[] a = monthCodes(year); + int i = index; + if (index == -1) { + i = a.length - 1; + } + boolean isLeap = a[0] > 0 && a[0] + 1 == i; + int month = isLeap || a[0] > 0 && a[0] < i ? i - 1 : i; + return new AbstractMap.SimpleImmutableEntry(month, isLeap); + } + + /** + * 计算月份 Mdd 代码在数组中的位置 + * + * @param year 农历年 + * @param month 农历月 + * @param isLeapMonth 闰月 + * @return 月所在的下标 + */ + public static int monthIndex(int year, int month, boolean isLeapMonth) { + short[] a = monthCodes(year); + if (a[0] > 0 && a[0] < month || a[0] == month && isLeapMonth) { + return month + 1; + } + return month; + } + + /** + * 判断两个整数所代表公历日期的差值
+ * 一年按365天计算,一个月按30天计算
+ * + * @param solarCode1  农历日期代码 + * @param solarCode2  农历日期代码 + * @param field  差值单位 + * @return 差值 + */ + public static long solarDateCodesDiff(int solarCode1, int solarCode2, int field) { + GregorianCalendar c1 = new GregorianCalendar(solarCode1 / 10000, solarCode1 % 10000 / 100 - 1, + solarCode1 % 10000 % 100); + GregorianCalendar c2 = new GregorianCalendar(solarCode2 / 10000, solarCode2 % 10000 / 100 - 1, + solarCode2 % 10000 % 100); + return LunarUtils.solarDiff(c1, c2, field); + } + + /** + * 农历月的代码 + * @param lunarYear 农历月 + * @param lunarMonth 农历月 + * @param isLeapMonth 闰月 + * @return 代码 + */ + public static short lunarMonthCode(int lunarYear, int lunarMonth, boolean isLeapMonth) { + short[] codes = monthCodes(lunarYear); + int index = lunarMonth; + if (codes[0] > 0 && codes[0] < lunarMonth || codes[0] == lunarMonth && isLeapMonth) { + index++; + } + return codes[index]; + } +} diff --git a/src/main/java/com/github/heqiao2010/lunar/LunarData.java b/src/main/java/com/github/heqiao2010/lunar/LunarData.java new file mode 100644 index 0000000..9d490a1 --- /dev/null +++ b/src/main/java/com/github/heqiao2010/lunar/LunarData.java @@ -0,0 +1,423 @@ +package com.github.heqiao2010.lunar; + +public class LunarData { + /** + * 支持的最小日期1850-02-12 + */ + public final static int MINI_YEAR = 1850; + public final static int MINI_MONTH = 1; + public final static int MINI_DATE = 12; + /** + * 支持的最大日期2150-12-31 + */ + public final static int MAX_YEAR = 2150; + public final static int MAX_MONTH = 11; + public final static int MAX_DATE = 31; + /** + * 10天干 + * '甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸' + */ + static final char[] LunarGan = {'\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', + '\u8f9b', '\u58ec', '\u7678'}; + /** + * 12地支 + * '子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥' + */ + static final char[] LunarZhi = {'\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', + '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5'}; + /** + * 12生肖 + * '鼠', '牛', '虎', '兔', '龍', '蛇', '馬', '羊', '猴', '雞', '犬', '豬' + */ + static final char[] LunarAnimalName = {'\u9f20', '\u725b', '\u864e', '\u5154', '\u9f8d', '\u86c7', + '\u99ac', '\u7f8a', '\u7334', '\u96de', '\u72ac', '\u8c6c'}; + /** + * 农历年份名 + * '〇', '一', '二', '三', '四', '五', '六', '七', '八', '九' + */ + static final char[] LunarYearName = {'\u3007', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', + '\u516d', '\u4e03', '\u516b', '\u4e5d'}; + /** + * 农历月份名 + * '正', '二', '三', '四', '五', '六', '七', '八', '九', '十', '冬', '腊' + */ + static final char[] LunarMonthName = {'\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', + '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a'}; + /** + * 农历日期名 + * "初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", + * "初十", "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十", "廿一", "廿二", + * "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十" + */ + static final String[] LunarDayName = {"\u521d\u4e00", "\u521d\u4e8c", "\u521d\u4e09", "\u521d\u56db", + "\u521d\u4e94", "\u521d\u516d", "\u521d\u4e03", "\u521d\u516b", "\u521d\u4e5d", "\u521d\u5341", + "\u5341\u4e00", "\u5341\u4e8c", "\u5341\u4e09", "\u5341\u56db", "\u5341\u4e94", "\u5341\u516d", + "\u5341\u4e03", "\u5341\u516b", "\u5341\u4e5d", "\u4e8c\u5341", "\u5eff\u4e00", "\u5eff\u4e8c", + "\u5eff\u4e09", "\u5eff\u56db", "\u5eff\u4e94", "\u5eff\u516d", "\u5eff\u4e03", "\u5eff\u516b", + "\u5eff\u4e5d", "\u4e09\u5341"}; + /** + * 农历信息.
+ * 每个数组的第一个数表示该年闰月月份,为0表示不闰月
+ * 数组中其他数表示该月初一对应的公历日期
+ */ + final static short[][] LUNAR_INFO = { + {0, 212, 314, 412, 512, 610, 709, 808, 906, 1005, 1104, 1204, 1302}, // 1850 + {8, 201, 303, 402, 501, 531, 629, 728, 827, 925, 1024, 1123, 1222, 1321}, // 1851 + {0, 220, 321, 331, 419, 519, 618, 717, 815, 914, 1013, 1112, 1211, 1309}, // 1852 + {0, 208, 310, 408, 508, 607, 706, 805, 903, 1003, 1101, 1201, 1230}, // 1853 + {7, 129, 227, 329, 427, 527, 625, 725, 824, 922, 1022, 1120, 1220, 1318}, // 1854 + {0, 217, 318, 416, 516, 614, 714, 813, 911, 1011, 1110, 1209, 1308}, // 1855 + {0, 206, 307, 405, 504, 603, 702, 801, 830, 929, 1029, 1128, 1227}, // 1856 + {5, 126, 224, 326, 424, 523, 622, 721, 820, 918, 1018, 1116, 1216, 1315}, // 1857 + {0, 214, 315, 414, 513, 611, 711, 809, 907, 1007, 1106, 1205, 1304}, // 1858 + {0, 203, 305, 403, 503, 601, 630, 730, 828, 926, 1026, 1124, 1224}, // 1859 + {3, 123, 222, 322, 421, 521, 619, 718, 817, 915, 1014, 1113, 1212, 1311}, // 1860 + {0, 210, 311, 410, 510, 608, 708, 806, 905, 1004, 1103, 1202, 1231}, // 1861 + {8, 130, 301, 330, 429, 528, 627, 727, 825, 924, 1023, 1122, 1221, 1319}, // 1862 + {0, 218, 319, 418, 518, 616, 716, 814, 913, 1013, 1111, 1211, 1309}, // 1863 + {0, 208, 308, 406, 506, 604, 704, 802, 901, 1001, 1030, 1129, 1229, 1327}, // 1864 + {6, 127, 226, 327, 425, 525, 623, 723, 821, 920, 1020, 1118, 1218, 1317}, // 1865 + {0, 215, 317, 415, 514, 613, 712, 810, 909, 1009, 1107, 1207, 1306}, // 1866 + {0, 205, 306, 405, 504, 602, 702, 731, 829, 928, 1027, 1126, 1226}, // 1867 + {4, 125, 223, 324, 423, 522, 620, 720, 818, 916, 1016, 1114, 1214, 1313}, // 1868 + {0, 211, 313, 412, 512, 610, 709, 808, 906, 1005, 1104, 1203, 1302}, // 1869 + {10, 131, 302, 401, 501, 530, 629, 728, 827, 925, 1024, 1123, 1222, 1321}, // 1870 + {0, 219, 321, 420, 519, 618, 718, 816, 915, 1014, 1113, 1212, 1310}, // 1871 + {0, 209, 309, 408, 507, 606, 706, 804, 903, 1002, 1101, 1201, 1230}, // 1872 + {6, 129, 227, 328, 427, 526, 625, 724, 823, 922, 1021, 1120, 1220, 1318}, // 1873 + {0, 217, 318, 416, 516, 614, 714, 812, 911, 1010, 1109, 1209, 1308}, // 1874 + {0, 206, 308, 406, 505, 604, 703, 801, 831, 929, 1029, 1128, 1228}, // 1875 + {5, 126, 225, 326, 424, 523, 622, 721, 819, 918, 1017, 1116, 1216, 1314}, // 1876 + {0, 213, 315, 414, 513, 611, 711, 809, 907, 1007, 1105, 1205, 1303}, // 1877 + {0, 202, 304, 403, 502, 601, 630, 730, 828, 926, 1026, 1124, 1224}, // 1878 + {3, 122, 221, 323, 421, 521, 620, 719, 818, 916, 1015, 1114, 1213, 1312}, // 1879 + {0, 210, 311, 409, 509, 608, 707, 806, 905, 1004, 1103, 1202, 1231}, // 1880 + {7, 130, 228, 330, 428, 528, 626, 726, 825, 923, 1023, 1122, 1221, 1320}, // 1881 + {0, 218, 319, 418, 517, 616, 715, 814, 912, 1012, 1111, 1210, 1309}, // 1882 + {0, 208, 309, 407, 507, 605, 704, 803, 901, 1001, 1031, 1130, 1229}, // 1883 + {5, 128, 227, 327, 425, 525, 623, 722, 821, 919, 1019, 1118, 1217, 1316}, // 1884 + {0, 215, 317, 415, 514, 613, 712, 810, 909, 1008, 1107, 1206, 1305}, // 1885 + {0, 204, 306, 404, 504, 602, 702, 731, 829, 928, 1027, 1126, 1225}, // 1886 + {4, 124, 223, 325, 423, 523, 621, 721, 819, 917, 1017, 1115, 1215, 1313}, // 1887 + {0, 212, 313, 411, 511, 610, 709, 808, 906, 1005, 1104, 1203, 1302}, // 1888 + {12, 131, 302, 331, 430, 530, 628, 728, 826, 925, 1024, 1123, 1222, 1321}, // 1889 + {0, 219, 321, 419, 519, 617, 717, 816, 914, 1014, 1112, 1212, 1310}, // 1890 + {0, 209, 310, 409, 508, 607, 706, 805, 903, 1003, 1102, 1201, 1231}, // 1891 + {6, 130, 228, 328, 427, 526, 624, 724, 822, 921, 1021, 1119, 1219, 1318}, // 1892 + {0, 217, 318, 416, 516, 614, 713, 812, 910, 1010, 1108, 1208, 1307}, // 1893 + {0, 206, 307, 406, 505, 604, 703, 801, 831, 929, 1029, 1127, 1227}, // 1894 + {5, 126, 225, 326, 425, 524, 623, 722, 820, 919, 1018, 1117, 1216, 1315}, // 1895 + {0, 214, 314, 413, 513, 611, 711, 809, 907, 1007, 1105, 1205, 1303}, // 1896 + {0, 202, 303, 402, 502, 531, 630, 730, 828, 926, 1026, 1124, 1224}, // 1897 + {3, 122, 221, 322, 421, 520, 619, 719, 817, 916, 1015, 1114, 1213, 1312}, // 1898 + {0, 210, 312, 410, 510, 608, 708, 806, 905, 1005, 1103, 1203, 1301}, // 1899 + {8, 131, 301, 331, 429, 528, 627, 726, 825, 924, 1023, 1122, 1222, 1320}, // 1900 + {0, 219, 320, 419, 518, 616, 716, 814, 913, 1012, 1111, 1211, 1310}, // 1901 + {0, 208, 310, 408, 508, 606, 705, 804, 902, 1002, 1031, 1130, 1230}, // 1902 + {5, 129, 227, 329, 427, 527, 625, 724, 823, 921, 1020, 1119, 1219, 1317}, // 1903 + {0, 216, 317, 416, 515, 614, 713, 811, 910, 1009, 1107, 1207, 1306}, // 1904 + {0, 204, 306, 405, 504, 603, 703, 801, 830, 929, 1028, 1127, 1226}, // 1905 + {4, 125, 223, 325, 424, 523, 622, 721, 820, 918, 1018, 1116, 1216, 1314}, // 1906 + {0, 213, 314, 413, 512, 611, 710, 809, 908, 1007, 1106, 1205, 1304}, // 1907 + {0, 202, 303, 401, 430, 530, 629, 728, 827, 925, 1025, 1124, 1223}, // 1908 + {2, 122, 220, 322, 420, 519, 618, 717, 816, 914, 1014, 1113, 1213, 1311}, // 1909 + {0, 210, 311, 410, 509, 607, 707, 805, 904, 1003, 1102, 1202, 1301}, // 1910 + {6, 130, 301, 330, 429, 528, 626, 726, 824, 922, 1022, 1121, 1220, 1319}, // 1911 + {0, 218, 319, 417, 517, 615, 714, 813, 911, 1010, 1109, 1209, 1307}, // 1912 + {0, 206, 308, 407, 506, 605, 704, 802, 901, 930, 1029, 1128, 1227}, // 1913 + {5, 126, 225, 327, 425, 525, 623, 723, 821, 920, 1019, 1117, 1217, 1315}, // 1914 + {0, 214, 316, 414, 514, 613, 712, 811, 909, 1009, 1107, 1207, 1305}, // 1915 + {0, 203, 304, 403, 502, 601, 630, 730, 829, 927, 1027, 1125, 1225}, // 1916 + {2, 123, 222, 323, 421, 521, 619, 719, 818, 916, 1016, 1115, 1214, 1313}, // 1917 + {0, 211, 313, 411, 510, 609, 708, 807, 905, 1005, 1104, 1203, 1302}, // 1918 + {7, 201, 302, 401, 430, 529, 628, 727, 825, 924, 1024, 1122, 1222, 1321}, // 1919 + {0, 220, 320, 419, 518, 616, 716, 814, 912, 1012, 1110, 1210, 1309}, // 1920 + {0, 208, 310, 408, 508, 606, 705, 804, 902, 1001, 1031, 1129, 1229}, // 1921 + {5, 128, 227, 328, 427, 527, 625, 724, 823, 921, 1020, 1119, 1218, 1317}, // 1922 + {0, 216, 317, 416, 516, 614, 714, 812, 911, 1010, 1108, 1208, 1306}, // 1923 + {0, 205, 305, 404, 504, 602, 702, 801, 830, 929, 1028, 1127, 1226}, // 1924 + {4, 124, 223, 324, 423, 522, 621, 721, 819, 918, 1018, 1116, 1216, 1314}, // 1925 + {0, 213, 314, 412, 512, 610, 710, 808, 907, 1007, 1105, 1205, 1304}, // 1926 + {0, 202, 304, 402, 501, 531, 629, 729, 827, 926, 1025, 1124, 1224}, // 1927 + {2, 123, 221, 322, 420, 519, 618, 717, 815, 914, 1013, 1112, 1212, 1311}, // 1928 + {0, 210, 311, 410, 509, 607, 707, 805, 903, 1003, 1101, 1201, 1231}, // 1929 + {6, 130, 228, 330, 429, 528, 626, 726, 824, 922, 1022, 1120, 1220, 1319}, // 1930 + {0, 217, 319, 418, 517, 616, 715, 814, 912, 1011, 1110, 1209, 1308}, // 1931 + {0, 206, 307, 406, 506, 604, 704, 802, 901, 930, 1029, 1128, 1227}, // 1932 + {5, 126, 224, 326, 425, 524, 623, 723, 821, 920, 1019, 1118, 1217, 1315}, // 1933 + {0, 214, 315, 414, 513, 612, 712, 810, 909, 1008, 1107, 1207, 1305}, // 1934 + {0, 204, 305, 403, 503, 601, 701, 730, 829, 928, 1027, 1126, 1226}, // 1935 + {3, 124, 223, 323, 421, 521, 619, 718, 817, 916, 1015, 1114, 1214, 1313}, // 1936 + {0, 211, 313, 411, 510, 609, 708, 806, 905, 1004, 1103, 1203, 1302}, // 1937 + {7, 131, 302, 401, 430, 529, 628, 727, 825, 924, 1023, 1122, 1222, 1320}, // 1938 + {0, 219, 321, 420, 519, 617, 717, 815, 913, 1013, 1111, 1211, 1309}, // 1939 + {0, 208, 309, 408, 507, 606, 705, 804, 902, 1001, 1031, 1129, 1229}, // 1940 + {6, 127, 226, 328, 426, 526, 625, 724, 823, 921, 1020, 1119, 1218, 1317}, // 1941 + {0, 215, 317, 415, 515, 614, 713, 812, 910, 1010, 1108, 1208, 1306}, // 1942 + {0, 205, 306, 405, 504, 603, 702, 801, 831, 929, 1029, 1127, 1227}, // 1943 + {4, 125, 224, 324, 423, 522, 621, 720, 819, 917, 1017, 1116, 1215, 1314}, // 1944 + {0, 213, 314, 412, 512, 610, 709, 808, 906, 1006, 1105, 1205, 1303}, // 1945 + {0, 202, 304, 402, 501, 531, 629, 728, 827, 925, 1025, 1124, 1223}, // 1946 + {2, 122, 221, 323, 421, 520, 619, 718, 816, 915, 1014, 1113, 1212, 1311}, // 1947 + {0, 210, 311, 409, 509, 607, 707, 805, 903, 1003, 1101, 1201, 1230}, // 1948 + {7, 129, 228, 329, 428, 528, 626, 726, 824, 922, 1022, 1120, 1220, 1318}, // 1949 + {0, 217, 318, 417, 517, 615, 715, 814, 912, 1011, 1110, 1209, 1308}, // 1950 + {0, 206, 308, 406, 506, 605, 704, 803, 901, 1001, 1030, 1129, 1228}, // 1951 + {5, 127, 225, 326, 424, 524, 622, 722, 820, 919, 1019, 1117, 1217, 1315}, // 1952 + {0, 214, 315, 414, 513, 611, 711, 810, 908, 1008, 1107, 1206, 1305}, // 1953 + {0, 203, 305, 403, 503, 601, 630, 730, 828, 927, 1027, 1125, 1225}, // 1954 + {3, 124, 222, 324, 422, 522, 620, 719, 818, 916, 1016, 1114, 1214, 1313}, // 1955 + {0, 212, 312, 411, 510, 609, 708, 806, 905, 1004, 1103, 1202, 1301}, // 1956 + {8, 131, 302, 331, 430, 529, 628, 727, 825, 924, 1023, 1122, 1221, 1320}, // 1957 + {0, 218, 320, 419, 519, 617, 717, 815, 913, 1013, 1111, 1211, 1309}, // 1958 + {0, 208, 309, 408, 508, 606, 706, 804, 903, 1002, 1101, 1130, 1230}, // 1959 + {6, 128, 227, 327, 426, 525, 624, 724, 822, 921, 1020, 1119, 1218, 1317}, // 1960 + {0, 215, 317, 415, 515, 613, 713, 811, 910, 1010, 1108, 1208, 1306}, // 1961 + {0, 205, 306, 405, 504, 602, 702, 731, 830, 929, 1028, 1127, 1227}, // 1962 + {4, 125, 224, 325, 424, 523, 621, 721, 819, 918, 1017, 1116, 1216, 1315}, // 1963 + {0, 213, 314, 412, 512, 610, 709, 808, 906, 1006, 1104, 1204, 1303}, // 1964 + {0, 202, 303, 402, 501, 531, 629, 728, 827, 925, 1024, 1123, 1223}, // 1965 + {3, 121, 220, 322, 421, 520, 619, 718, 816, 915, 1014, 1112, 1212, 1311}, // 1966 + {0, 209, 311, 410, 509, 608, 708, 806, 904, 1004, 1102, 1202, 1231}, // 1967 + {7, 130, 228, 329, 427, 527, 626, 725, 824, 922, 1022, 1120, 1220, 1318}, // 1968 + {0, 217, 318, 417, 516, 615, 714, 813, 912, 1011, 1110, 1209, 1308}, // 1969 + {0, 206, 308, 406, 505, 604, 703, 802, 901, 930, 1030, 1129, 1228}, // 1970 + {5, 127, 225, 327, 425, 524, 623, 722, 821, 919, 1019, 1118, 1218, 1316}, // 1971 + {0, 215, 315, 414, 513, 611, 711, 809, 908, 1007, 1106, 1206, 1304}, // 1972 + {0, 203, 305, 403, 503, 601, 630, 730, 828, 926, 1026, 1125, 1224}, // 1973 + {4, 123, 222, 324, 422, 522, 620, 719, 818, 916, 1015, 1114, 1214, 1312}, // 1974 + {0, 211, 313, 412, 511, 610, 709, 807, 906, 1005, 1103, 1203, 1301}, // 1975 + {8, 131, 301, 331, 429, 529, 627, 727, 825, 924, 1023, 1121, 1221, 1319}, // 1976 + {0, 218, 320, 418, 518, 617, 716, 815, 913, 1013, 1111, 1211, 1309}, // 1977 + {0, 207, 309, 407, 507, 606, 705, 804, 903, 1002, 1101, 1130, 1230}, // 1978 + {6, 128, 227, 328, 426, 526, 624, 724, 823, 921, 1021, 1120, 1219, 1318}, // 1979 + {0, 216, 317, 415, 514, 613, 712, 811, 909, 1009, 1108, 1207, 1306}, // 1980 + {0, 205, 306, 405, 504, 602, 702, 731, 829, 928, 1028, 1126, 1226}, // 1981 + {4, 125, 224, 325, 424, 523, 621, 721, 819, 917, 1017, 1115, 1215, 1314}, // 1982 + {0, 213, 315, 413, 513, 611, 710, 809, 907, 1006, 1105, 1204, 1303}, // 1983 + {10, 202, 303, 401, 501, 531, 629, 728, 827, 925, 1024, 1123, 1222, 1321}, // 1984 + {0, 220, 321, 420, 520, 618, 718, 816, 915, 1014, 1112, 1212, 1310}, // 1985 + {0, 209, 310, 409, 509, 607, 707, 806, 904, 1004, 1102, 1202, 1231}, // 1986 + {6, 129, 228, 329, 428, 527, 626, 726, 824, 923, 1023, 1121, 1221, 1319}, // 1987 + {0, 217, 318, 416, 516, 614, 714, 812, 911, 1011, 1109, 1209, 1308}, // 1988 + {0, 206, 308, 406, 505, 604, 703, 802, 831, 930, 1029, 1128, 1228}, // 1989 + {5, 127, 225, 327, 425, 524, 623, 722, 820, 919, 1018, 1117, 1217, 1316}, // 1990 + {0, 215, 316, 415, 514, 612, 712, 810, 908, 1008, 1106, 1206, 1305}, // 1991 + {0, 204, 304, 403, 503, 601, 630, 730, 828, 926, 1026, 1124, 1224}, // 1992 + {3, 123, 221, 323, 422, 521, 620, 719, 818, 916, 1015, 1114, 1213, 1312}, // 1993 + {0, 210, 312, 411, 511, 609, 709, 807, 906, 1005, 1103, 1203, 1301}, // 1994 + {8, 131, 301, 331, 430, 529, 628, 727, 826, 925, 1024, 1122, 1222, 1320}, // 1995 + {0, 219, 319, 418, 517, 616, 716, 814, 913, 1012, 1111, 1211, 1309}, // 1996 + {0, 207, 309, 407, 507, 605, 705, 803, 902, 1002, 1031, 1130, 1230}, // 1997 + {5, 128, 227, 328, 426, 526, 624, 723, 822, 921, 1020, 1119, 1219, 1317}, // 1998 + {0, 216, 318, 416, 515, 614, 713, 811, 910, 1009, 1108, 1208, 1307}, // 1999 + {0, 205, 306, 405, 504, 602, 702, 731, 829, 928, 1027, 1126, 1226}, // 2000 + {4, 124, 223, 325, 423, 523, 621, 721, 819, 917, 1017, 1115, 1215, 1313}, // 2001 + {0, 212, 314, 413, 512, 611, 710, 809, 907, 1006, 1105, 1204, 1303}, // 2002 + {0, 201, 303, 402, 501, 531, 630, 729, 828, 926, 1025, 1124, 1223}, // 2003 + {2, 122, 220, 321, 419, 519, 618, 717, 816, 914, 1014, 1112, 1212, 1310}, // 2004 + {0, 209, 310, 409, 508, 607, 706, 805, 904, 1003, 1102, 1201, 1231}, // 2005 + {7, 129, 228, 329, 428, 527, 626, 725, 824, 922, 1022, 1121, 1220, 1319}, // 2006 + {0, 218, 319, 417, 517, 615, 714, 813, 911, 1011, 1110, 1210, 1308}, // 2007 + {0, 207, 308, 406, 505, 604, 703, 801, 831, 929, 1029, 1128, 1227}, // 2008 + {5, 126, 225, 327, 425, 524, 623, 722, 820, 919, 1018, 1117, 1216, 1315}, // 2009 + {0, 214, 316, 414, 514, 612, 712, 810, 908, 1008, 1106, 1206, 1304}, // 2010 + {0, 203, 305, 403, 503, 602, 701, 731, 829, 927, 1027, 1125, 1225}, // 2011 + {4, 123, 222, 322, 421, 521, 619, 719, 817, 916, 1015, 1114, 1213, 1312}, // 2012 + {0, 210, 312, 410, 510, 608, 708, 807, 905, 1005, 1103, 1203, 1301}, // 2013 + {9, 131, 301, 331, 429, 529, 627, 727, 825, 924, 1024, 1122, 1222, 1320}, // 2014 + {0, 219, 320, 419, 518, 616, 716, 814, 913, 1013, 1112, 1211, 1310}, // 2015 + {0, 208, 309, 407, 507, 605, 704, 803, 901, 1001, 1031, 1129, 1229}, // 2016 + {6, 128, 226, 328, 426, 526, 624, 723, 822, 920, 1020, 1118, 1218, 1317}, // 2017 + {0, 216, 317, 416, 515, 614, 713, 811, 910, 1009, 1108, 1207, 1306}, // 2018 + {0, 205, 307, 405, 505, 603, 703, 801, 830, 929, 1028, 1126, 1226}, // 2019 + {4, 125, 223, 324, 423, 523, 621, 721, 819, 917, 1017, 1115, 1215, 1313}, // 2020 + {0, 212, 313, 412, 512, 610, 710, 808, 907, 1006, 1105, 1204, 1303}, // 2021 + {0, 201, 303, 401, 501, 530, 629, 729, 827, 926, 1025, 1124, 1223}, // 2022 + {2, 122, 220, 322, 420, 519, 618, 718, 816, 915, 1015, 1113, 1213, 1311}, // 2023 + {0, 210, 310, 409, 508, 606, 706, 804, 903, 1003, 1101, 1201, 1231}, // 2024 + {6, 129, 228, 329, 428, 527, 625, 725, 823, 922, 1021, 1120, 1220, 1319}, // 2025 + {0, 217, 319, 417, 517, 615, 714, 813, 911, 1010, 1109, 1209, 1308}, // 2026 + {0, 206, 308, 407, 506, 605, 704, 802, 901, 930, 1029, 1128, 1228}, // 2027 + {5, 126, 225, 326, 425, 524, 623, 722, 820, 919, 1018, 1116, 1216, 1315}, // 2028 + {0, 213, 315, 414, 513, 612, 711, 810, 908, 1008, 1106, 1205, 1304}, // 2029 + {0, 203, 304, 403, 502, 601, 701, 730, 829, 927, 1027, 1125, 1225}, // 2030 + {3, 123, 221, 323, 422, 521, 620, 719, 818, 917, 1016, 1115, 1214, 1313}, // 2031 + {0, 211, 312, 410, 509, 608, 707, 806, 905, 1004, 1103, 1203, 1301}, // 2032 + {11, 131, 301, 331, 429, 528, 627, 726, 825, 923, 1023, 1122, 1222, 1320}, // 2033 + {0, 219, 320, 419, 518, 616, 716, 814, 913, 1012, 1111, 1211, 1309}, // 2034 + {0, 208, 310, 408, 508, 606, 705, 804, 902, 1001, 1031, 1130, 1229}, // 2035 + {6, 128, 227, 328, 426, 526, 624, 723, 822, 920, 1019, 1118, 1217, 1316}, // 2036 + {0, 215, 317, 416, 515, 614, 713, 811, 910, 1009, 1107, 1207, 1305}, // 2037 + {0, 204, 306, 405, 504, 603, 702, 801, 830, 929, 1028, 1126, 1226}, // 2038 + {5, 124, 223, 325, 423, 523, 622, 721, 820, 918, 1018, 1116, 1216, 1314}, // 2039 + {0, 212, 313, 411, 511, 610, 709, 808, 906, 1006, 1105, 1204, 1303}, // 2040 + {0, 201, 302, 401, 430, 530, 628, 728, 827, 925, 1025, 1124, 1223}, // 2041 + {2, 122, 220, 322, 420, 519, 618, 717, 816, 914, 1014, 1113, 1212, 1311}, // 2042 + {0, 210, 311, 410, 509, 607, 707, 805, 903, 1003, 1102, 1201, 1231}, // 2043 + {7, 130, 229, 329, 428, 527, 625, 725, 823, 921, 1021, 1119, 1219, 1318}, // 2044 + {0, 217, 319, 417, 517, 615, 714, 813, 911, 1010, 1109, 1208, 1307}, // 2045 + {0, 206, 308, 406, 506, 604, 704, 802, 901, 930, 1029, 1128, 1227}, // 2046 + {5, 126, 225, 326, 425, 525, 623, 723, 821, 920, 1019, 1117, 1217, 1315}, // 2047 + {0, 214, 314, 413, 513, 611, 711, 810, 908, 1008, 1106, 1205, 1304}, // 2048 + {0, 202, 304, 402, 502, 531, 630, 730, 828, 927, 1027, 1125, 1225}, // 2049 + {3, 123, 221, 323, 421, 521, 619, 719, 817, 916, 1016, 1114, 1214, 1313}, // 2050 + {0, 211, 313, 411, 510, 609, 708, 806, 905, 1005, 1103, 1203, 1302}, // 2051 + {8, 201, 301, 331, 429, 528, 627, 726, 824, 923, 1022, 1121, 1221, 1320}, // 2052 + {0, 219, 320, 419, 518, 616, 716, 814, 912, 1012, 1110, 1210, 1309}, // 2053 + {0, 208, 309, 408, 508, 606, 705, 804, 902, 1001, 1031, 1129, 1229}, // 2054 + {6, 128, 226, 328, 427, 526, 625, 724, 823, 921, 1020, 1119, 1218, 1317}, // 2055 + {0, 215, 316, 415, 515, 613, 713, 811, 910, 1009, 1107, 1207, 1305}, // 2056 + {0, 204, 305, 404, 504, 602, 702, 731, 830, 928, 1028, 1126, 1226}, // 2057 + {4, 124, 223, 324, 423, 522, 621, 720, 819, 918, 1017, 1116, 1216, 1314}, // 2058 + {0, 212, 314, 412, 512, 610, 710, 808, 907, 1006, 1105, 1205, 1304}, // 2059 + {0, 202, 303, 401, 430, 530, 628, 727, 826, 924, 1024, 1123, 1223}, // 2060 + {3, 121, 220, 322, 420, 519, 618, 717, 815, 914, 1013, 1112, 1212, 1311}, // 2061 + {0, 209, 311, 410, 509, 607, 707, 805, 903, 1003, 1101, 1201, 1231}, // 2062 + {7, 129, 228, 330, 428, 528, 626, 726, 824, 922, 1022, 1120, 1220, 1318}, // 2063 + {0, 217, 318, 417, 516, 615, 714, 813, 911, 1010, 1109, 1208, 1307}, // 2064 + {0, 205, 307, 406, 505, 604, 704, 802, 901, 930, 1029, 1128, 1227}, // 2065 + {5, 126, 224, 326, 424, 524, 623, 722, 821, 919, 1019, 1117, 1217, 1315}, // 2066 + {0, 214, 315, 414, 513, 612, 711, 810, 909, 1008, 1107, 1206, 1305}, // 2067 + {0, 203, 304, 402, 502, 531, 629, 729, 828, 926, 1026, 1125, 1224}, // 2068 + {4, 123, 221, 323, 421, 521, 619, 718, 817, 915, 1015, 1114, 1214, 1312}, // 2069 + {0, 211, 312, 411, 510, 609, 708, 806, 905, 1004, 1103, 1203, 1301}, // 2070 + {8, 131, 302, 331, 430, 529, 628, 727, 825, 924, 1023, 1122, 1221, 1320}, // 2071 + {0, 219, 320, 418, 518, 616, 716, 814, 912, 1012, 1110, 1210, 1308}, // 2072 + {0, 207, 309, 407, 507, 606, 705, 804, 902, 1001, 1031, 1129, 1229}, // 2073 + {6, 127, 226, 327, 426, 526, 624, 724, 822, 921, 1020, 1119, 1218, 1317}, // 2074 + {0, 215, 317, 415, 515, 613, 713, 812, 910, 1010, 1108, 1208, 1306}, // 2075 + {0, 205, 305, 404, 503, 602, 701, 731, 829, 928, 1028, 1126, 1226}, // 2076 + {4, 124, 223, 324, 423, 522, 620, 720, 818, 917, 1017, 1116, 1215, 1314}, // 2077 + {0, 212, 314, 412, 512, 610, 709, 808, 906, 1006, 1105, 1204, 1303}, // 2078 + {0, 202, 303, 402, 501, 531, 629, 728, 827, 925, 1025, 1123, 1223}, // 2079 + {3, 122, 221, 321, 420, 519, 618, 717, 815, 914, 1013, 1111, 1211, 1310}, // 2080 + {0, 209, 310, 409, 509, 607, 707, 805, 903, 1003, 1101, 1130, 1230}, // 2081 + {7, 129, 227, 329, 428, 528, 626, 725, 824, 922, 1022, 1120, 1219, 1318}, // 2082 + {0, 217, 318, 417, 517, 615, 715, 813, 912, 1011, 1110, 1209, 1308}, // 2083 + {0, 206, 307, 405, 505, 603, 703, 802, 831, 930, 1029, 1128, 1227}, // 2084 + {5, 126, 224, 326, 424, 523, 622, 722, 820, 919, 1019, 1117, 1217, 1315}, // 2085 + {0, 214, 315, 414, 513, 611, 711, 809, 908, 1008, 1106, 1206, 1305}, // 2086 + {0, 203, 305, 403, 503, 601, 630, 730, 828, 927, 1026, 1125, 1225}, // 2087 + {4, 124, 222, 323, 421, 521, 619, 718, 817, 915, 1014, 1113, 1213, 1312}, // 2088 + {0, 210, 312, 411, 510, 609, 708, 806, 904, 1004, 1102, 1202, 1301}, // 2089 + {8, 130, 301, 331, 430, 529, 628, 727, 825, 924, 1023, 1121, 1221, 1320}, // 2090 + {0, 218, 320, 419, 518, 617, 716, 815, 913, 1013, 1111, 1210, 1309}, // 2091 + {0, 207, 308, 407, 506, 605, 705, 803, 902, 1001, 1031, 1129, 1229}, // 2092 + {6, 127, 225, 327, 426, 525, 624, 723, 822, 921, 1020, 1119, 1218, 1317}, // 2093 + {0, 215, 316, 415, 514, 613, 712, 811, 910, 1009, 1108, 1208, 1306}, // 2094 + {0, 205, 306, 405, 504, 602, 702, 731, 830, 928, 1028, 1127, 1227}, // 2095 + {4, 125, 224, 324, 423, 522, 620, 720, 818, 916, 1016, 1115, 1215, 1313}, // 2096 + {0, 212, 314, 412, 512, 610, 709, 807, 906, 1005, 1104, 1204, 1302}, // 2097 + {0, 201, 303, 402, 501, 531, 629, 728, 826, 925, 1024, 1123, 1222}, // 2098 + {2, 121, 220, 322, 420, 520, 619, 718, 816, 915, 1014, 1112, 1212, 1310}, // 2099 + {0, 209, 311, 410, 509, 608, 707, 806, 904, 1004, 1102, 1201, 1231}, // 2010 + {7, 129, 228, 330, 428, 528, 626, 726, 825, 923, 1023, 1121, 1220, 1319}, //2101 + {0, 217, 319, 417, 517, 616, 715, 814, 912, 1012, 1111, 1210, 1309}, //2102 + {0, 207, 308, 407, 506, 605, 704, 803, 901, 1001, 1031, 1130, 1229}, //2103 + {5, 128, 226, 327, 425, 524, 623, 722, 821, 919, 1019, 1118, 1217, 1316}, //2104 + {0, 215, 316, 415, 514, 612, 712, 810, 908, 1008, 1107, 1206, 1305}, //2105 + {0, 204, 306, 404, 504, 602, 701, 731, 829, 927, 1027, 1125, 1225}, //2106 + {4, 124, 223, 325, 423, 523, 621, 720, 819, 917, 1016, 1115, 1214, 1313}, //2107 + {0, 212, 313, 411, 511, 609, 709, 807, 906, 1005, 1103, 1203, 1301}, //2108 + {9, 131, 302, 331, 430, 530, 628, 728, 826, 925, 1024, 1122, 1222, 1320}, //2109 + {0, 219, 320, 419, 519, 617, 717, 816, 914, 1014, 1112, 1211, 1310}, //2110 + {0, 208, 310, 408, 508, 606, 706, 805, 903, 1003, 1101, 1201, 1231}, //2111 + {6, 129, 227, 328, 426, 526, 624, 724, 822, 921, 1021, 1119, 1219, 1318}, //2112 + {0, 216, 318, 416, 515, 614, 713, 811, 910, 1010, 1108, 1208, 1307}, //2113 + {0, 206, 307, 406, 505, 603, 703, 801, 830, 929, 1028, 1127, 1227}, //2114 + {4, 126, 225, 326, 425, 524, 622, 722, 820, 918, 1018, 1116, 1216, 1315}, //2115 + {0, 214, 314, 413, 512, 611, 710, 809, 907, 1006, 1105, 1204, 1303}, //2116 + {0, 202, 303, 402, 502, 531, 630, 729, 828, 926, 1025, 1124, 1223}, //2117 + {3, 122, 220, 322, 421, 520, 619, 719, 817, 916, 1015, 1113, 1213, 1311}, //2118 + {0, 210, 311, 410, 509, 608, 708, 806, 905, 1004, 1103, 1202, 1301}, //2119 + {7, 130, 229, 329, 428, 527, 626, 725, 824, 923, 1022, 1121, 1220, 1319}, //2120 + {0, 217, 319, 417, 517, 615, 715, 813, 912, 1011, 1110, 1210, 1309}, //2121 + {0, 207, 308, 407, 506, 605, 704, 802, 901, 930, 1030, 1129, 1229}, //2122 + {5, 127, 226, 328, 426, 525, 624, 723, 821, 920, 1019, 1118, 1218, 1317}, //2123 + {0, 215, 316, 414, 514, 612, 712, 810, 908, 1008, 1106, 1206, 1305}, //2124 + {0, 203, 305, 404, 503, 602, 701, 731, 829, 927, 1027, 1125, 1225}, //2125 + {4, 123, 222, 324, 423, 522, 621, 720, 819, 917, 1016, 1115, 1214, 1313}, //2126 + {0, 211, 313, 412, 511, 610, 710, 808, 906, 1006, 1104, 1204, 1302}, //2127 + {11, 201, 301, 331, 429, 529, 628, 727, 826, 924, 1024, 1122, 1222, 1320}, //2128 + {0, 219, 320, 419, 518, 617, 716, 815, 914, 1013, 1112, 1211, 1310}, //2129 + {0, 208, 310, 408, 508, 606, 705, 804, 903, 1002, 1101, 1201, 1230}, //2130 + {6, 129, 227, 329, 427, 527, 625, 724, 823, 921, 1021, 1120, 1220, 1318}, //2131 + {0, 217, 317, 416, 515, 614, 713, 811, 910, 1009, 1108, 1208, 1306}, //2132 + {0, 205, 307, 405, 505, 603, 703, 801, 830, 928, 1028, 1127, 1226}, //2133 + {5, 125, 224, 326, 424, 524, 622, 722, 820, 918, 1018, 1116, 1216, 1314}, //2134 + {0, 213, 315, 413, 513, 612, 711, 809, 908, 1007, 1106, 1205, 1304}, //2135 + {0, 202, 303, 401, 501, 531, 629, 729, 827, 926, 1025, 1124, 1223}, //2136 + {2, 122, 220, 322, 420, 520, 618, 718, 817, 915, 1015, 1113, 1213, 1311}, //2137 + {0, 210, 311, 410, 509, 608, 707, 806, 904, 1004, 1103, 1202, 1301}, //2138 + {7, 130, 301, 330, 429, 528, 626, 726, 824, 923, 1023, 1122, 1221, 1320}, //2139 + {0, 218, 319, 417, 517, 615, 714, 813, 911, 1011, 1110, 1209, 1308}, //2140 + {0, 207, 308, 407, 506, 605, 704, 802, 901, 930, 1030, 1128, 1228}, //2141 + {5, 127, 226, 327, 426, 525, 624, 723, 821, 919, 1019, 1117, 1217, 1316}, //2142 + {0, 215, 316, 415, 515, 613, 713, 811, 909, 1008, 1107, 1206, 1305}, //2143 + {0, 204, 304, 403, 503, 602, 701, 730, 829, 927, 1027, 1125, 1224}, //2144 + {4, 123, 222, 323, 422, 522, 620, 720, 818, 917, 1016, 1115, 1214, 1313}, //2145 + {0, 211, 312, 411, 511, 609, 709, 807, 906, 1006, 1104, 1204, 1302}, //2146 + {0, 201, 302, 331, 430, 529, 628, 728, 826, 925, 1025, 1123, 1223}, //2147 + {1, 121, 220, 320, 419, 518, 616, 716, 814, 913, 1013, 1111, 1211, 1310}, //2148 + {0, 208, 310, 408, 508, 606, 705, 804, 902, 1002, 1031, 1130, 1230}, //2149 + {6, 129, 227, 329, 427, 527, 625, 724, 822, 921, 1020, 1119, 1219, 1318}, //2150 + }; + + /** + * 获取农历日的表示 + * + * @param lunarDay  农历日数值表示 + * @return 农历日传统字符表示 + */ + public static String getDayName(int lunarDay) { + return LunarDayName[lunarDay - 1]; + } + + /** + * 获取农历月份 + * + * @param lunarMonth  农历月数值表示 + * @return 农历月传统字符表示 + */ + public static char getMonthName(int lunarMonth) { + return LunarMonthName[lunarMonth - 1]; + } + + /** + * 获取农历年份 + * + * @param lunarYear  农历年数值表示 + * @return 农历年传统字符表示 + */ + public static String getYearName(int lunarYear) { + StringBuilder sb = new StringBuilder(); + sb.append(LunarYearName[lunarYear / 1000]); + sb.append(LunarYearName[lunarYear % 1000 / 100]); + sb.append(LunarYearName[lunarYear % 100 / 10]); + sb.append(LunarYearName[lunarYear % 10]); + return sb.toString(); + } + + /** + * 返回传统天干地支年名称 + * + * @param y 农历年 + * @return 传统农历年份的表示 + */ + public static String getTraditionalYearName(int y) { + // 1804年是甲子年 + y = y - 1804; + return ("" + LunarGan[y % 10] + LunarZhi[y % 12] + "年"); + } + + /** + * 获取生肖名 + * + * @param y  农历年 + * @return 生肖名 + */ + public static char getAnimalYearName(int y) { + return LunarAnimalName[(y - 4) % 12]; + } +} diff --git a/src/main/java/com/github/heqiao2010/lunar/LunarUtils.java b/src/main/java/com/github/heqiao2010/lunar/LunarUtils.java new file mode 100644 index 0000000..306c390 --- /dev/null +++ b/src/main/java/com/github/heqiao2010/lunar/LunarUtils.java @@ -0,0 +1,98 @@ +package com.github.heqiao2010.lunar; + +import java.util.Calendar; + +public class LunarUtils { + /** + * 计算两个农历日期之差 + * + * @param lc1  农历1 + * @param lc2  农历2 + * @param field  计算的维度,比如按月,天等 + * @return 具体的差值 + */ + public static long luanrDiff(LunarCalendar lc1, LunarCalendar lc2, int field) { + return solarDiff(lc1, lc2, field); + } + + /** + * 求两个公历日期之差,field可以为年月日,时分秒
+ * 一年按365天计算,一个月按30天计算
+ * + * @param solar1  历日期 + * @param solar2  历日期 + * @param field 差值单位 + * @return 差值 + */ + public static long solarDiff(Calendar solar1, Calendar solar2, int field) { + long t1 = solar1.getTimeInMillis(); + long t2 = solar2.getTimeInMillis(); + switch (field) { + case Calendar.SECOND: + return (long) Math.rint((t1 - t2) / 1000.0); + case Calendar.MINUTE: + return (long) Math.rint((t1 - t2) / 60000.0); // 60 * 1000 + case Calendar.HOUR: + return (long) Math.rint((t1 - t2) / 3600000.0); //3600 * 1000 + case Calendar.DATE: + return (long) Math.rint((t1 - t2) / 86400000.0); // 24 * 3600 * 1000 + case Calendar.MONTH: + return (long) Math.rint((t1 - t2) / 2592000000.0); // 30 * 24 * 3600 * 1000 + case Calendar.YEAR: + return (long) Math.rint((t1 - t2) / 31536000000.0); // 365 * 24 * 3600 * 1000 + default: + return -1; + } + } + + /** + * 农历月的天数 + * + * @param lunarYear 农历年 + * @param month 农历月 + * @param isLeapMonth 闰月 + * @return 天数,29或者30 + */ + public static long lengthOfMonth(int lunarYear, int month, boolean isLeapMonth) { + short[] codes = LunarCodes.monthCodes(lunarYear); + int i = isLeapMonth ? month + 1 : month; + if (codes[0] > 0 && month > codes[0]) i++; + return LunarCodes.lengthOfMonth(lunarYear, month, codes[i]); + } + + /** + * 一个简单的二分查找,返回查找到的元素坐标,用于查找农历二维数组信息 + * + * @param array  数组 + * @param n  待查询数字 + * @return 查到的坐标 + */ + public static int binSearch(int[] array, int n) { + if (null == array || array.length == 0) { + return -1; + } + int min = 0, max = array.length - 1; + if (n <= array[min]) { + return min; + } else if (n >= array[max]) { + return max; + } + while (max - min > 1) { + int newIndex = (max + min) / 2; // 二分 + if (array[newIndex] > n) { // 取小区间 + max = newIndex; + } else if (array[newIndex] < n) {// 取大区间 + min = newIndex; + } else { // 相等,直接返回下标 + return newIndex; + } + } + if (array[max] == n) { + return max; + } else if (array[min] == n) { + return min; + } else { + return min; // 返回 较小的一个 + } + } +} diff --git a/src/main/kotlin/JChatGPT.kt b/src/main/kotlin/JChatGPT.kt index 86e35d6..d1b4508 100644 --- a/src/main/kotlin/JChatGPT.kt +++ b/src/main/kotlin/JChatGPT.kt @@ -31,6 +31,7 @@ import net.mamoe.mirai.message.data.* import net.mamoe.mirai.message.data.Image.Key.queryUrl import net.mamoe.mirai.utils.info import top.jie65535.mirai.tools.* +import util.LunarDateUtil import xyz.cssxsh.mirai.hibernate.MiraiHibernateRecorder import xyz.cssxsh.mirai.hibernate.entry.MessageRecord import java.io.File @@ -207,7 +208,9 @@ object JChatGPT : KotlinPlugin( } replace("{time}") { - dateTimeFormatter.format(now) + val solarTime = dateTimeFormatter.format(now) + val lunarInfo = LunarDateUtil.getFormattedLunarAndHoliday(now) + "$solarTime\n农历$lunarInfo" } replace("{subject}") { diff --git a/src/main/kotlin/util/LunarDateUtil.kt b/src/main/kotlin/util/LunarDateUtil.kt new file mode 100644 index 0000000..23e2881 --- /dev/null +++ b/src/main/kotlin/util/LunarDateUtil.kt @@ -0,0 +1,163 @@ +package util + +import com.github.heqiao2010.lunar.LunarCalendar +import com.github.heqiao2010.lunar.LunarCalendar.solar2Lunar +import java.time.OffsetDateTime +import java.util.Calendar + +/** + * 农历日期工具类 + */ +object LunarDateUtil { + + /** + * 获取农历日期字符串 + * @param offsetDateTime 公历日期时间 + * @return 农历日期字符串,格式如:甲辰年(龙)十二月廿七 + */ + fun getLunarDateString(offsetDateTime: OffsetDateTime): String { + val calendar = Calendar.getInstance() + calendar.set( + offsetDateTime.year, + offsetDateTime.monthValue - 1, + offsetDateTime.dayOfMonth + ) + val lunar = solar2Lunar(calendar) + return lunar.toString() + } + + /** + * 获取农历信息(包含年份和生肖) + * @param offsetDateTime 公历日期时间 + * @return 农历信息字符串 + */ + fun getLunarInfo(offsetDateTime: OffsetDateTime): String { + val calendar = Calendar.getInstance() + calendar.set( + offsetDateTime.year, + offsetDateTime.monthValue - 1, + offsetDateTime.dayOfMonth + ) + val lunar = solar2Lunar(calendar) + return lunar.getFullLunarName() + } + + /** + * 获取当前日期的节假日信息 + * @param offsetDateTime 公历日期时间 + * @return 节假日名称,如果不是节假日则返回null + */ + fun getHoliday(offsetDateTime: OffsetDateTime): String? { + val month = offsetDateTime.monthValue + val day = offsetDateTime.dayOfMonth + val lunar = getLunarCalendar(offsetDateTime) + + // 公历节日 + when (month) { + 1 -> { + if (day == 1) return "元旦" + } + 2 -> { + if (day == 14) return "情人节" + } + 3 -> { + if (day == 8) return "妇女节" + if (day == 12) return "植树节" + if (day == 15) return "消费者权益日" + } + 4 -> { + if (day == 1) return "愚人节" + if (day == 4) return "清明节" + } + 5 -> { + if (day == 1) return "劳动节" + if (day == 4) return "青年节" + } + 6 -> { + if (day == 1) return "儿童节" + } + 7 -> { + if (day == 1) return "建党节" + } + 8 -> { + if (day == 1) return "建军节" + } + 9 -> { + if (day == 10) return "教师节" + } + 10 -> { + if (day == 1) return "国庆节" + } + 12 -> { + if (day == 24) return "平安夜" + if (day == 25) return "圣诞节" + } + } + + // 农历节日 + val lunarMonth = lunar.lunarMonth + val lunarDay = lunar.dayOfLunarMonth + + when (lunarMonth) { + 1 -> { + if (lunarDay == 1) return "春节" + if (lunarDay == 15) return "元宵节" + } + 2 -> { + if (lunarDay == 2) return "龙抬头" + } + 5 -> { + if (lunarDay == 5) return "端午节" + } + 7 -> { + if (lunarDay == 7) return "七夕节" + } + 8 -> { + if (lunarDay == 15) return "中秋节" + } + 9 -> { + if (lunarDay == 9) return "重阳节" + } + 12 -> { + if (lunarDay == 8) return "腊八节" + if (lunarDay == 23) return "小年" // 北方小年 + if (lunarDay == 24) return "小年" // 南方小年 + } + } + + // 二十四节气(简化版,只判断几个主要的) + // 注意:这里使用简化的判断,实际节气计算比较复杂 + // 可以使用更精确的节气计算库 + + return null + } + + /** + * 获取LunarCalendar对象 + */ + private fun getLunarCalendar(offsetDateTime: OffsetDateTime): LunarCalendar { + val calendar = Calendar.getInstance() + calendar.set( + offsetDateTime.year, + offsetDateTime.monthValue - 1, + offsetDateTime.dayOfMonth + ) + return solar2Lunar(calendar) + } + + /** + * 获取格式化的农历和节假日信息 + * @param offsetDateTime 公历日期时间 + * @return 格式化的字符串,如:农历甲辰年(龙)十二月廿七 春节 + */ + fun getFormattedLunarAndHoliday(offsetDateTime: OffsetDateTime): String { + val lunarInfo = getLunarInfo(offsetDateTime) + val holiday = getHoliday(offsetDateTime) + + return if (holiday != null) { + "$lunarInfo $holiday" + } else { + lunarInfo + } + } +}