我们常说的生辰八字,是用天干地支表示人出生的年、月、日、时,合起来是八个字。
十天干,甲乙丙丁午己庚辛壬癸。
十二地支,子丑寅卯辰巳午未申酉戌亥。
十天干和十二地支依次相配,如“甲子”、“乙丑”,两者按固定的顺序相互配合一共组成六十个基本单位:
甲子、乙丑、丙寅、丁卯、戊辰、已巳、庚午、辛未、壬申、癸酉、
甲戌、乙亥、丙子、丁丑、戊寅、已卯、庚辰、辛巳、壬午、癸未、
甲申、乙酉、丙戌、丁亥、戊子、已丑、庚寅、辛卯、壬辰、癸巳、
甲午、乙未、丙申、丁酉、戊戌、已亥、庚子、辛丑、壬寅、癸卯、
甲辰、乙巳、丙午、丁未、戊申、已酉、庚戌、辛亥、壬子、癸丑、
甲寅、乙卯、丙辰、丁巳、戊午、已未、庚申、辛酉、壬戌、癸亥。
快速知道自己的生辰八字。
正常万年历上都会显示到年月日的干支。比如说2021年9月21就是辛丑年丁酉月壬申日,需要自己计算的只剩下具体的时辰了。
关于时辰的计算,分为天干的计算以及地支的计算,都比较简单。首先时辰的地支有直接的对应关系。
0-11-33-55-77-99-1-1717-1919-2121-2323-0
丑时
寅时
卯时
辰时
巳时
午时
未时
申时
酉时
戌时
亥时
子时
其次要定位时辰的干支需要根据当日的干支来判断,也就是日上起时法,具体是做法如下。
甲己还加甲——逢日干是甲或己的日子,子时的时干从甲上起
乙庚丙作初——逢日干是乙或庚的日子,子时的时干从丙上起
丙辛从戊起——逢日干是丙或辛的日子,子时的时干从戊上起
丁壬庚子居——逢日干是丁或壬的日子,子时的时干从庚上起
戊癸何方发,壬子是真途
当换成表格描述如下
日干甲乙丙丁戊
己
庚
辛
壬
癸
子时起
甲子
丙子
戊子
庚子
壬子
比如说今天是壬申日,日干支为壬,从上面的丁壬庚子居这句庚申丁亥癸丑,那么可以得出今天的0点到1点为庚子时,接下来1点到3点是辛丑时,以此类推,壬寅,癸卯,甲辰,乙巳,丙午,丁未,戊申,己酉,庚戌,辛亥,到最后的23点又回到子时,不过此时已经是壬子了,正应了戊癸何方发,壬子是真途那句,因为当前壬申日接下来第二天是癸酉日,刚好以壬子起时。
以上,可以快速的得出自己的生辰八字。如果只是想了解下自己的八字,这就足够了。以上是时辰的推导过程,下面会讲一些年月日的推导规则,想了解的可以继续往下阅读。
干支纪年
前面说过十天干和十二地支依次相配,可以组成六十个基本单位。所以每六十年一个甲子轮回,而其中,每十年一个天干轮回,
可以挑一个最近的甲子年1984作为基准,用计算的年份-1984,然后对结果除以60取余数,从甲子往后推这个余数对应的干支即可。
当然更方便的是根据年份尾数直接推算天干,如下对应:
庚
辛
壬
癸
甲
乙
丙
丁
戊
己
年份÷12取余数,然后从子往后推余数次就是对应的地支。
例如,计算2021年的年干支,尾数为1,那么年干为辛,(2021-1984)÷12余数是1,子往后一个是丑,所以2021是辛丑年。
干支纪月
月份的地支也是固定的,每年的正月是寅月开始,二月是卯月,以此类推。
月份的干支计算,之前计算时辰的时候我们已经用到了日上起时法,此处我们同样要用到类似的年上起月法。
甲己之年丙作首,乙庚之岁戊为头。
丙辛岁首寻庚起,丁壬壬位顺行流。
若言戊癸何方求,甲寅之上好追求。
换成表格表述如下。
年干甲乙丙丁戊
己
庚
辛
壬
癸
正月起
丙寅
戊寅
庚寅
壬寅
甲寅
2021年是辛丑年,那么正月是庚寅月,二月是辛卯月,以此类推,三月壬辰,四月癸巳,五月甲午,六月乙未,七月丙申,八月丁酉,九月戊戌,十月己亥,十一月庚子,十二月辛丑。来年壬寅年对应的正月刚好是壬寅月。
需要注意的是,这里说的月份皆是阴历。
干支纪日
正常情况下,日干支是最难算的,如果一个月固定三十天,那正好两月一个轮回,主要是考虑大小润月的问题,这里有一个公历计算的公式
已知日期计算干支纪日的公式为:
g = 4c + [c / 4] + 5y + [y / 4] + [3 * (m + 1) / 5] + d - 3
z = 8c + [c / 4] + 5y + [y / 4] + [3 * (m + 1) / 5] + d + 7 + i
其中 c 是世纪数减一,y 是年份后两位(若为1月2月则当前年份减1),m 是月份,d 是日数。1月和2月按上一年的13月和14月来算。奇数月i=0,偶数月i=6。g 除以10的余数是天干,z 除以12的余数是地支。 计算时带[ ]的数表示取整。
例如:查2021年9月21日的干支日。 将数值代入计算公式。 g =4*20 + [20 / 4] + 5*21 + [21 / 4] + [3 * (9 + 1) / 5] + 21 - 3 =219 除以10 余数为 9 ,天干的第9位是‘壬’。 z =8*20 + [20 / 4] + 5*21 + [21 / 4] + [3 * (9 + 1) / 5] + 21 + 7 + 0 =309 除以12 余数为 9 ,地支的第9位是‘申’,所以这一天是壬申日。
又如:查2021年1月1日的干支日。
世纪数c是20,y本来是21,因为1月所以减为20,m本来是1,因为是1月所以变为13,d是1,i是0.
将数值代入计算公式。 g =4*20 + [20 / 4] + 5*20 + [20 / 4] + [3 * (13 + 1) / 5] + 1- 3 =215除以10 余数为 6 ,天干的第6位是‘己’。 z =8*20 + [20 / 4] + 5*20 + [20 / 4] + [3 * (13 + 1) / 5] +1+ 7 + 0 =286 除以12 余数为 10 ,地支的第10位是‘酉’,所以这一天是己酉日。
规则讲完了,如果要用代码要怎么实现呢?
java实现
首先定义一个干支对象
public static class GanZhi {
/**
* 天干序号
*/
int tianGan;
/**
* 地支序号
*/
int diZhi;
public GanZhi() {
}
public GanZhi(int tianGan, int diZhi) {
this.tianGan = tianGan;
this.diZhi = diZhi;
}
}
再定义一些辅助的变量
// 第一个甲子年
private final static int FIRST_YEAR = -2697;
// 十天干
private final static String[] tianGanArray = {"甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"};
// 十二地支
private final static String[] diZhiArray = {"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"};
// 年上起月,key为年天干序号,value为对应的月天干序号
private final static Map yearMonthMap = new HashMap<>(4);
// 日上起时,key为日天干序号,value为对应的时天干序号
private final static Map dayHourMap = new HashMap<>(4);
static {
/**
* 年上起月法:
* 甲己之年丙作首.
* 乙庚之岁戊为头.
* 丙辛之岁寻庚上.
* 丁壬壬寅顺水顺.
* 若问戊癸何处起.
* 甲寅之上好追求
*/
yearMonthMap.put(0, 2);
yearMonthMap.put(1, 4);
yearMonthMap.put(2, 6);
yearMonthMap.put(3, 8);
yearMonthMap.put(4, 0);
yearMonthMap.put(5, 2);
yearMonthMap.put(6, 4);
yearMonthMap.put(7, 6);
yearMonthMap.put(8, 8);
yearMonthMap.put(9, 0);
/**
* 甲己还加甲
* 乙庚丙作初
* 丙辛从戊起
* 丁壬庚子居
* 戊癸何方发,壬子是真途
*/
dayHourMap.put(0, 0);
dayHourMap.put(1, 2);
dayHourMap.put(2, 4);
dayHourMap.put(3, 6);
dayHourMap.put(4, 8);
dayHourMap.put(5, 0);
dayHourMap.put(6, 2);
dayHourMap.put(7, 4);
dayHourMap.put(8, 6);
dayHourMap.put(9, 8);
}
下面是相关信息
/**
* 阴历日日期
*/
private Integer[] realBirth;
/**
* 阳历日期
*/
private Integer[] yangbirths;
/**
* 年干支
*/
private GanZhi yearGanZhi = null;
/**
* 月干支
*/
private GanZhi monthGanZhi = null;
/**
* 日干支
*/
private GanZhi dayGanZhi = null;
/**
* 时干支
*/
private GanZhi hourGanZhi = null;
纪年
计算年份的干支方法,用年份减去目前已确定的第一个甲子年,也就是公元前求2697年求余数。year为正数表示公元xx年,为负数表示公元前xx年。由于不存在公元0年,假设-1年为甲子年,按照纯数字的推导庚申丁亥癸丑,接下来应该是0是乙丑年,1是丙寅年。但是这个0是不存在的,1才应该是乙丑年。也就是说正数序列都要往前挪一位。所以year>0时,多减了1。当year为负数时,不需要多减1,但是需要取余数的绝对值。
public void evalYear(int year) throws Exception {
if (year == 0) {
throw new Exception("非法的年份");
}
int yeanGan = 0, yearZhi = 0;
if (year > 0) {
yeanGan = (year - FIRST_YEAR - 1) % 10;
yearZhi = (year - FIRST_YEAR - 1) % 12;
} else if (year < 0) {
yeanGan = Math.abs((year - FIRST_YEAR) % 10);
yearZhi = Math.abs((year - FIRST_YEAR)) % 12;
}
this.setYearGanZhi(new GanZhi(yeanGan, yearZhi));
}
纪月
年上起月,从映射关系里,根据年天干获取到正月的月天干。正月地支初始化为寅,然后依次找到对应月份的干支。
public void evalMonth(int month) throws Exception {
if (month < 1 || month > 12) {
throw new Exception("非法的月份");
}
// 月份的起始干支(*寅)
Integer monthGanInit = yearMonthMap.get(this.getYearGanZhi().getTianGan());
Integer monthZhiInit = 2;
for (int i = 1; i < month; i++) {
monthGanInit = (monthGanInit + 1) % 10;
monthZhiInit = (monthZhiInit + 1) % 12;
}
this.setMonthGanZhi(new GanZhi(monthGanInit, monthZhiInit));
}
纪日
代公式即可。
这个地方有一个疑惑点,就是计算2000年1月1日的这种日子,按照前面的说法,y 是年份后两位(若为1月2月则当前年份减1),这块的减1是对2000减1还是对余数0减一。翻了下日历,用余数减1的值匹配的上,不过感觉这个描述怪怪的。
public void evalDay(int day) throws Exception {
int C = this.yangbirths[0] / 100;
int y = this.yangbirths[1] > 2 ? this.yangbirths[0] % 100 : this.yangbirths[0] % 100 - 1;
int M = this.yangbirths[1] > 2 ? this.yangbirths[1] : this.yangbirths[1] + 12;
int d = this.yangbirths[2];
int i = this.yangbirths[1] % 2 == 0 ? 6 : 0;
// 月份的起始干支(*寅)
Integer monthGanInit = (4 * C + (C / 4) + 5 * y + (y / 4) + (3 * (M + 1) / 5) + d - 3 - 1) % 10;
Integer monthZhiInit = (8 * C + (C / 4) + 5 * y + (y / 4) + (3 * (M + 1) / 5) + d + 7 + i - 1) % 12;
this.setDayGanZhi(new GanZhi(monthGanInit, monthZhiInit));
}
计时
日上起时,两个小时为一个时辰,所以每循环一次,i要加2
public void evalHour(int hour) throws Exception {
if (hour < 0 || hour > 24) {
throw new Exception("非法的小时");
}
// 月份的起始干支(*寅)
Integer hourGanInit = dayHourMap.get(this.getDayGanZhi().getTianGan());
Integer hourZhiInit = 0;
for (int i = 1; i <= hour; i = i + 2) {
hourGanInit = (hourGanInit + 1) % 10;
hourZhiInit = (hourZhiInit + 1) % 12;
}
this.setHourGanZhi(new GanZhi(hourGanInit, hourZhiInit));
}