Java实现周易六爻自动排盘:根据卜卦的时间推算出天干地支

干支,是中国古代用来纪年、纪月、纪日、纪时的一套符号系统,由"天干"和"地支"两部分组成,合称"干支"。六爻卜卦中需要用到天干和地支来装五行和六神!


一、天干(共10个):

甲、乙、丙、丁、戊、己、庚、辛、壬、癸

二、地支(共12个):

子、丑、寅、卯、辰、巳、午、未、申、酉、戌、亥


三、干支组合方式:

天干与地支按固定顺序两两相配,形成 60个不同的组合 ,称为"六十甲子"或"六十花甲"。

组合规则是:从"甲子"开始,天干循环10次,地支循环12次,最小公倍数为60,所以每60年(或日、时)循环一次。

例如前几个组合为:

  • 甲子
  • 乙丑
  • 丙寅
  • 丁卯
    ......
  • 癸亥(第60位)

四、干支的用途:

  1. 纪年:如2024年是甲辰年,2025年是乙巳年。
  2. 纪月:配合节气用于农历月份标记。
  3. 纪日:古代历法中每日都有干支,如"戊戌变法"中的"戊戌"即指日期。
  4. 纪时:一天分为12个时辰,每个时辰对应一个地支,并配以天干,用于传统命理学(如八字)。

五、举例说明:

  • 公元2025年是农历乙巳年(天干"乙" + 地支"巳")。
  • 今天是2025年12月9日,根据万年历,这一天的干支日是己未日
  • 如果某人出生在乙巳年、某月某日某时,这四个干支就构成了其"生辰八字"。

六、代码实现:

java 复制代码
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

public class GanZhiCalendar {

    // 已知锚点:1900年1月31日 是 庚子年 丁丑月 甲辰日
    private static final LocalDate ANCHOR_DATE = LocalDate.of(1900, 1, 31);
    // 十天干
    private static final String[] TIANGAN = {"甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"};
    // 十二地支
    private static final String[] DIZHI = {"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"};

    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now(); // 可替换为任意时间
        System.out.println(toGanZhi(now));
    }

    public static String toDayGan(LocalDateTime date) {
        int ganIndex =getDayGanIndex(date); // 防止负数
        return TIANGAN[ganIndex];
    }

    public static int getDayGanIndex(LocalDateTime date) {
        long daysBetween = ChronoUnit.DAYS.between(ANCHOR_DATE, date);
        return (int) (daysBetween % 10);
    }

    public static String toGanZhi(LocalDateTime date) {
        String ganZhiYear = getGanZhiYear(date);
        String ganZhiMonth = getGanZhiMonth(date);
        String ganZhiDay = getGanZhiDay(date);
        String ganZhiHour = getGanZhiHour(date);
        return ganZhiYear + "年 " + ganZhiMonth + "月 " + ganZhiDay + "日 " + ganZhiHour + "时";
    }


    private static String getGanZhiYear(LocalDateTime date) {
        long yearsBetween = ChronoUnit.YEARS.between(ANCHOR_DATE, date);
        int ganIndex = (int) ((yearsBetween+6)  % 10);
        int zhiIndex = (int) (yearsBetween % 12);
        return TIANGAN[ganIndex] + DIZHI[zhiIndex];
    }

    public static int getYearGanIndex(LocalDateTime date) {
        long yearsBetween = ChronoUnit.YEARS.between(ANCHOR_DATE, date);
        return  (int) ((yearsBetween+6)  % 10);
    }

    // 需要用到是节气月
    private static String getGanZhiMonth(LocalDateTime date) {
        int month=SolarTermsCalculator.getSolarTermMonth(date.toLocalDate());
        int zhiIndex = (month+1)  % 12; // 因为正月是寅月,寅是下标是2,所以 (1+1)%12=2
        if (zhiIndex == 0) zhiIndex = 11;
       // zhiIndex--;
        int yearGanIndex = getYearGanIndex(date);
        // 五鼠遁口诀:
        // 甲己还加甲,乙庚丙作初,
        // 丙辛从戊起,丁壬庚子居,
        // 戊癸何方发,壬子是真途。
        int ziShiGanIndex = switch (yearGanIndex) {
            case 0, 5 -> // 甲、己
                    2; // 丙
            case 1, 6 -> // 乙、庚
                    4; // 戊
            case 2, 7 -> // 丙、辛
                    6; // 庚
            case 3, 8 -> // 丁、壬
                    8; // 壬
            case 4, 9 -> // 戊、癸
                    0; // 甲
            default -> 0;
        };
        int ganIndex = (ziShiGanIndex + (month - 1)) % 10;
        return TIANGAN[ganIndex] + DIZHI[zhiIndex];
    }

    // 日干支:使用已知公式(适用于1900 - 2099)
    // 来自《日干支计算公式》:对于公历日期 year-month-day
    private static String getGanZhiDay(LocalDateTime date) {
        long daysBetween = ChronoUnit.DAYS.between(ANCHOR_DATE, date);
        int ganIndex = (int) (daysBetween % 10) ;
        int zhiIndex = (int) ((daysBetween+4) % 12);
        return TIANGAN[ganIndex] + DIZHI[zhiIndex];
    }

    private static String getGanZhiHour(LocalDateTime date) {
        int hour=date.getHour();
        int shichen = (hour + 1) / 2 % 12; // 0=子,1=丑,...,11=亥
        if (hour == 23) shichen = 0; // 特殊处理23点属于子时
        int dayGanIndex = getDayGanIndex(date);
        // 五鼠遁口诀:
        // 甲己还加甲,乙庚丙作初,
        // 丙辛从戊起,丁壬庚子居,
        // 戊癸何方发,壬子是真途。
        int ziShiGanIndex = switch (dayGanIndex) {
            case 0, 5 -> // 甲、己
                    0; // 甲
            case 1, 6 -> // 乙、庚
                    2; // 丙
            case 2, 7 -> // 丙、辛
                    4; // 戊
            case 3, 8 -> // 丁、壬
                    6; // 庚
            case 4, 9 -> // 戊、癸
                    8; // 壬
            default -> 0;
        };
        int ganIndex = (ziShiGanIndex + shichen) % 10;
        return TIANGAN[ganIndex] + DIZHI[shichen];
    }


}

这是一个将公历日期时间转换为中国传统干支历(天干地支)的Java程序。下面我将从原理、代码逻辑、潜在问题等方面进行详细解读。

一、核心原理

干支历是中国传统历法,由十天干十二地支组合而成,用于纪年、纪月、纪日、纪时:

  • 天干:甲、乙、丙、丁、戊、己、庚、辛、壬、癸(10个)
  • 地支:子、丑、寅、卯、辰、巳、午、未、申、酉、戌、亥(12个)

干支组合形成60甲子(60年为一个周期),是中国传统文化中重要的时间表示方法。

二、代码结构与功能
1. 基准锚点
java 复制代码
private static final LocalDate ANCHOR_DATE = LocalDate.of(1900, 1, 31);
  • 1900年1月31日被指定为计算基准(庚子年丁丑月甲辰日)
  • 以此为基准,计算其他日期与它的天数/年数差
2. 天干地支数组
java 复制代码
private static final String[] TIANGAN = {"甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"};
private static final String[] DIZHI = {"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"};
3. 核心转换方法
(1) 干支年计算
java 复制代码
private static String getGanZhiYear(LocalDateTime date) {
    long yearsBetween = ChronoUnit.YEARS.between(ANCHOR_DATE, date);
    int ganIndex = (int) ((yearsBetween+6) % 10);
    int zhiIndex = (int) (yearsBetween % 12);
    return TIANGAN[ganIndex] + DIZHI[zhiIndex];
}
  • 原理:从1900年1月31日起,年数差 + 6 后对10取模得天干,年数差对12取模得地支
  • 示例 :1900年是庚子年,1900年与锚点年数差为0,ganIndex=(0+6)%10=6(庚),zhiIndex=0%12=0(子)
(2) 干支月计算
java 复制代码
private static String getGanZhiMonth(LocalDateTime date) {
    int month = SolarTermsCalculator.getSolarTermMonth(date.toLocalDate());
    int zhiIndex = (month + 1) % 12;
    if (zhiIndex == 0) zhiIndex = 11;
    
    int yearGanIndex = getYearGanIndex(date);
    // 五鼠遁口诀:甲己还加甲,乙庚丙作初...
    int ziShiGanIndex = switch (yearGanIndex) {
        case 0, 5 -> 2; // 甲、己 → 丙
        case 1, 6 -> 4; // 乙、庚 → 戊
        case 2, 7 -> 6; // 丙、辛 → 庚
        case 3, 8 -> 8; // 丁、壬 → 壬
        case 4, 9 -> 0; // 戊、癸 → 甲
        default -> 0;
    };
    
    int ganIndex = (ziShiGanIndex + (month - 1)) % 10;
    return TIANGAN[ganIndex] + DIZHI[zhiIndex];
}
  • 关键点:使用节气划分月份(非公历月份),例如"立春"是正月开始
  • 五鼠遁 :根据年干确定月干
    • 甲年/己年:正月是甲子月(天干甲,地支寅)
    • 乙年/庚年:正月是丙寅月(天干丙,地支寅)
    • 以此类推
(3) 干支日计算
java 复制代码
private static String getGanZhiDay(LocalDateTime date) {
    long daysBetween = ChronoUnit.DAYS.between(ANCHOR_DATE, date);
    int ganIndex = (int) (daysBetween % 10);
    int zhiIndex = (int) ((daysBetween + 4) % 12);
    return TIANGAN[ganIndex] + DIZHI[zhiIndex];
}
  • 原理:从锚点日(1900-01-31)起,天数差对10取模得天干,(天数差+4)对12取模得地支
  • 验证 :1900-01-31是甲辰日(天干0,地支4),daysBetween=0ganIndex=0%10=0zhiIndex=(0+4)%12=4,符合
(4) 干支时计算
java 复制代码
private static String getGanZhiHour(LocalDateTime date) {
    int hour = date.getHour();
    int shichen = (hour + 1) / 2 % 12; // 0=子,1=丑,...,11=亥
    if (hour == 23) shichen = 0; // 23点属于子时
    
    int dayGanIndex = getDayGanIndex(date);
    // 五鼠遁:甲己还加甲,乙庚丙作初...
    int ziShiGanIndex = switch (dayGanIndex) {
        case 0, 5 -> 0; // 甲、己 → 甲
        case 1, 6 -> 2; // 乙、庚 → 丙
        case 2, 7 -> 4; // 丙、辛 → 戊
        case 3, 8 -> 6; // 丁、壬 → 庚
        case 4, 9 -> 8; // 戊、癸 → 壬
        default -> 0;
    };
    
    int ganIndex = (ziShiGanIndex + shichen) % 10;
    return TIANGAN[ganIndex] + DIZHI[shichen];
}
  • 时辰划分:每2小时为一个时辰(子时23-1点,丑时1-3点,以此类推)
  • 五鼠遁:根据日干确定时干
六、总结

这是一个实现干支历转换的Java程序,核心在于:

  1. 使用1900年1月31日作为基准点
  2. 通过模运算计算天干地支
  3. 应用"五鼠遁"口诀确定月干和时干
  4. 使用节气划分月份(符合传统历法)

代码整体逻辑清晰,但需要确保SolarTermsCalculator的正确实现。如果实现得当,这将是一个准确、实用的干支历转换工具。

📌 小知识:干支历中,"甲子"是第一个组合,"癸亥"是最后一个,60个组合循环往复。1900年1月31日是"庚子年"(干支历的第61个年),所以"庚"在天干中排第7位(0:甲, 1:乙, 2:丙, 3:丁, 4:戊, 5:己, 6:庚)。

该代码中的节气计算类SolarTermsCalculator缺失,等讲到节气推算章节时再补充

相关推荐
Tony Bai3 小时前
高并发后端:坚守 Go,还是拥抱 Rust?
开发语言·后端·golang·rust
wjs20243 小时前
Swift 类型转换
开发语言
没有bug.的程序员3 小时前
服务安全:内部服务如何防止“裸奔”?
java·网络安全·云原生安全·服务安全·零信任架构·微服务安全·内部鉴权
一线大码4 小时前
SpringBoot 3 和 4 的版本新特性和升级要点
java·spring boot·后端
秃了也弱了。4 小时前
python实现定时任务:schedule库、APScheduler库
开发语言·python
weixin_440730504 小时前
java数组整理笔记
java·开发语言·笔记
weixin_425023004 小时前
Spring Boot 实用核心技巧汇总:日期格式化、线程管控、MCP服务、AOP进阶等
java·spring boot·后端
一线大码4 小时前
Java 8-25 各个版本新特性总结
java·后端
Thera7774 小时前
状态机(State Machine)详解:原理、优缺点与 C++ 实战示例
开发语言·c++
2501_906150564 小时前
私有部署问卷系统操作实战记录-DWSurvey
java·运维·服务器·spring·开源