干支,是中国古代用来纪年、纪月、纪日、纪时的一套符号系统,由"天干"和"地支"两部分组成,合称"干支"。六爻卜卦中需要用到天干和地支来装五行和六神!
一、天干(共10个):
甲、乙、丙、丁、戊、己、庚、辛、壬、癸
二、地支(共12个):
子、丑、寅、卯、辰、巳、午、未、申、酉、戌、亥
三、干支组合方式:
天干与地支按固定顺序两两相配,形成 60个不同的组合 ,称为"六十甲子"或"六十花甲"。
组合规则是:从"甲子"开始,天干循环10次,地支循环12次,最小公倍数为60,所以每60年(或日、时)循环一次。
例如前几个组合为:
- 甲子
- 乙丑
- 丙寅
- 丁卯
...... - 癸亥(第60位)
四、干支的用途:
- 纪年:如2024年是甲辰年,2025年是乙巳年。
- 纪月:配合节气用于农历月份标记。
- 纪日:古代历法中每日都有干支,如"戊戌变法"中的"戊戌"即指日期。
- 纪时:一天分为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=0,ganIndex=0%10=0,zhiIndex=(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程序,核心在于:
- 使用1900年1月31日作为基准点
- 通过模运算计算天干地支
- 应用"五鼠遁"口诀确定月干和时干
- 使用节气划分月份(符合传统历法)
代码整体逻辑清晰,但需要确保SolarTermsCalculator的正确实现。如果实现得当,这将是一个准确、实用的干支历转换工具。
📌 小知识:干支历中,"甲子"是第一个组合,"癸亥"是最后一个,60个组合循环往复。1900年1月31日是"庚子年"(干支历的第61个年),所以"庚"在天干中排第7位(0:甲, 1:乙, 2:丙, 3:丁, 4:戊, 5:己, 6:庚)。
该代码中的节气计算类SolarTermsCalculator缺失,等讲到节气推算章节时再补充