農曆(陰曆)轉換涉及複雜的天文算法,本文提供基於觀測數據表的精確轉換實現,支持1936-2030年範圍,含節氣、干支、生肖計算。
// 農曆年基礎數據(1936-2030)
static final int[] LUNAR_BASE_DAYS = { 23, 41, 30, 49, 38, ... }; // 正月初一距1月1日天數
static final int[] LEAP_MONTHS = { 3, 0, 7, 0, 0, 6, ... }; // 閏月月份(0=無閏月)
static final int[][] MONTH_DAYS = { // 各月大小月(1=30天,0=29天)
{1,0,0,1,0,0,1,1,0,1,1,1,0}, // 1936
{1,0,0,1,0,1,1,1,0,1,0,1,0}, // 1937
...
};
// 陽曆累積天數
static final int[][] SOLAR_CUMULATIVE = {
{0,31,59,90,120,151,181,212,243,273,304,334,365,396}, // 平年
{0,31,60,91,121,152,182,213,244,274,305,335,366,397} // 閏年
};
public static LunarDate solarToLunar(int y, int m, int d) {
// 1. 計算該日期是當年第幾天
int dayOfYear = SOLAR_CUMULATIVE[isLeap(y)?1:0][m-1] + d;
// 2. 確定農曆年(可能屬於上一年)
int lunarYear = y;
if (dayOfYear <= LUNAR_BASE_DAYS[y - 1936]) {
lunarYear = y - 1;
dayOfYear += isLeap(lunarYear) ? 366 : 365;
}
// 3. 遍歷農曆月確定月份日期
int base = LUNAR_BASE_DAYS[lunarYear - 1936];
int leapMonth = LEAP_MONTHS[lunarYear - 1936];
int month = 1;
for (; month <= 13; month++) {
int monthLen = 29 + MONTH_DAYS[lunarYear - 1936][month-1];
if (dayOfYear <= base + monthLen) break;
base += monthLen;
}
// 4. 處理閏月邏輯
boolean isLeapMonth = false;
if (leapMonth != 0 && month > leapMonth) {
month--;
if (month == leapMonth) isLeapMonth = true;
}
return new LunarDate(lunarYear, month, dayOfYear - base, isLeapMonth);
}
public static SolarDate lunarToSolar(int lunarYear, int month, int day, boolean isLeapMonth) {
// 1. 計算農曆年首日距1月1日天數
int base = LUNAR_BASE_DAYS[lunarYear - 1936];
// 2. 累加前置月天數
int leapMonth = LEAP_MONTHS[lunarYear - 1936];
int adjMonth = month;
if (leapMonth != 0) {
if (isLeapMonth) adjMonth = leapMonth + 1;
else if (month > leapMonth) adjMonth++;
}
for (int i = 1; i < adjMonth; i++) {
base += 29 + MONTH_DAYS[lunarYear - 1936][i-1];
}
base += day;
// 3. 反推陽曆日期
int solarYear = lunarYear;
int[] cum = SOLAR_CUMULATIVE[isLeap(solarYear)?1:0];
for (int m = 12; m >= 0; m--) {
if (base > cum[m]) {
if (m == 12) { solarYear++; m = 0; }
return new SolarDate(solarYear, m+1, base - cum[m]);
}
}
return null; // 錯誤
}
// 十天干
static final String[] GAN = {"甲","乙","丙","丁","戊","己","庚","辛","壬","癸"};
// 十二地支
static final String[] ZHI = {"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"};
public static String getGanZhi(int year, int month, int day) {
// 參考基準:1900年1月31日甲戌日
int days = daysBetween(1900,1,31, year,month,day);
return GAN[(days + 0) % 10] + ZHI[(days + 10) % 12]; // 需校準偏移量
}
// JDK 8內建支持
import java.time.chrono.ChineseChronology;
import java.time.chrono.ChineseDate;
import java.time.LocalDate;
ChineseDate cd = ChineseDate.from(LocalDate.of(2024, 2, 10));
System.out.println("農曆: " + cd.getYear() + "年 " + cd.getMonth() + "月 " + cd.getDayOfMonth() + "日");
System.out.println("生肖: " + cd.getEra()); // 甲辰年(龍年)
java.time.chrono標準庫