首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

中西曆轉換算法Java實現:農曆節氣與干支計算

     編輯:Java 相關知識

農曆(陰曆)轉換涉及複雜的天文算法,本文提供基於觀測數據表的精確轉換實現,支持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]; // 需校準偏移量
}

現代替代:Java 8+ Time API


// 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()); // 甲辰年(龍年)

注意事項

  • 算法基於紫金山天文台歷史數據,1936年前/2030年後需擴展數據表
  • 農曆定閏規則複雜(無中氣置閏),數據表法避免了實時天文計算
  • 干支計算需精確基準日,建議對接權威萬年曆庫驗證
  • 現代項目優先使用java.time.chrono標準庫
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved