一、前言
八字排盘是中国传统命理学的基础,也是起名、择日等应用的核心输入。市面上大多数起名工具(包括笔者开发的 529 宝宝起名网)的底层,都依赖一套准确的八字排盘算法。
然而网上关于八字排盘的代码实现非常零散,要么只讲理论不给代码,要么代码有 bug(比如节气边界处理错误、子时日柱混乱)。本文将从最基础的天干地支开始,一步步用 Python 实现一套完整的八字排盘 + 五行计算系统,并给出可直接运行的代码。
阅读本文你将获得:
- 八字四柱(年 / 月 / 日 / 时)的精确计算方法
- 天干地支五行属性映射与藏干处理
- 五行力量统计与喜用神判断思路
- 一套可直接复用的 Python 代码
二、八字排盘基础原理
八字,顾名思义就是八个字 —— 年柱、月柱、日柱、时柱,每柱由一个天干和一个地支组成,共八个字。
2.1 天干地支
天干共 10 个:甲、乙、丙、丁、戊、己、庚、辛、壬、癸 地支共 12 个:子、丑、寅、卯、辰、巳、午、未、申、酉、戌、亥
天干地支按顺序配对,60 年一个循环(甲子、乙丑、丙寅…… 癸亥)。
2.2 四柱的计算规则
表格
| 年柱 | 以立春为界,不是春节 | 立春前出生算上一年 |
| 月柱 | 以节气为界(立春 / 惊蛰 / 清明……),不是农历月份 | 节气交接时刻精确到分钟 |
| 日柱 | 以子时(23:00)为界,不是 0 点 | 23:00-00:00 属于第二天日柱 |
| 时柱 | 根据地干推算(五鼠遁) | 早子时 / 晚子时的时柱天干不同 |
三、核心模块实现
3.1 天干地支基础数据
# bazi_core.py
from datetime import datetime, timedelta
import math
# 天干地支
TIAN_GAN = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']
DI_ZHI = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']
# 天干五行
TIAN_GAN_WUXING = {
'甲': '木', '乙': '木',
'丙': '火', '丁': '火',
'戊': '土', '己': '土',
'庚': '金', '辛': '金',
'壬': '水', '癸': '水',
}
# 地支五行(主气)
DI_ZHI_WUXING = {
'子': '水', '丑': '土', '寅': '木', '卯': '木',
'辰': '土', '巳': '火', '午': '火', '未': '土',
'申': '金', '酉': '金', '戌': '土', '亥': '水',
}
# 地支藏干(主气、中气、余气,带权重)
DI_ZHI_CANG_GAN = {
'子': [('癸', 1.0)],
'丑': [('己', 0.6), ('癸', 0.3), ('辛', 0.1)],
'寅': [('甲', 0.6), ('丙', 0.3), ('戊', 0.1)],
'卯': [('乙', 1.0)],
'辰': [('戊', 0.6), ('乙', 0.3), ('癸', 0.1)],
'巳': [('丙', 0.6), ('戊', 0.3), ('庚', 0.1)],
'午': [('丁', 0.7), ('己', 0.3)],
'未': [('己', 0.6), ('丁', 0.3), ('乙', 0.1)],
'申': [('庚', 0.6), ('壬', 0.3), ('戊', 0.1)],
'酉': [('辛', 1.0)],
'戌': [('戊', 0.6), ('辛', 0.3), ('丁', 0.1)],
'亥': [('壬', 0.7), ('甲', 0.3)],
}
3.2 年柱计算
年柱的关键是立春。2024 年 2 月 4 日立春,那么 2024 年 2 月 3 日出生的人,年柱还是 2023 年的(癸卯),2 月 4 日立春后才是甲辰。
立春的精确日期需要用天文算法计算,这里我们用一个简化但足够精确的公式(适用于 1900-2100 年):
def get_lichun_datetime(year: int) -> datetime:
"""计算指定年份的立春日期时间(简化公式,精度约±10分钟)
公式:[Y*D+C]-L
Y=年数后2位,D=0.2422,L=闰年数,21世纪C=3.87,20世纪C=4.6295
"""
y = year % 100
if year >= 2000:
c = 3.87
else:
c = 4.6295
d = 0.2422
l = y // 4 # 闰年数
day = int(y * d + c) – l
# 立春通常在2月3-5日,时间默认取当天06:00(简化处理)
return datetime(year, 2, day, 6, 0, 0)
def get_year_pillar(dt: datetime) -> str:
"""计算年柱(以立春为界)"""
year = dt.year
lichun = get_lichun_datetime(year)
if dt < lichun:
year -= 1
# 公元4年为甲子年,以此推算
gan_idx = (year – 4) % 10
zhi_idx = (year – 4) % 12
return TIAN_GAN[gan_idx] + DI_ZHI[zhi_idx]
3.3 月柱计算
月柱以节气为界,一年 24 节气,其中 “节”(立春、惊蛰、清明、立夏、芒种、小暑、立秋、白露、寒露、立冬、大雪、小寒)为月与月的分界。
月柱的天干用五虎遁年起月法推算:
甲己之年丙作首,乙庚之岁戊为头,丙辛必定寻庚起,丁壬壬位顺行流,戊癸何方发,甲寅之上好追求。
意思是:年干为甲或己,正月(寅月)天干从丙开始;年干为乙或庚,正月天干从戊开始…… 以此类推。
# 二十四节气中的"节"(月份分界),对应地支
# 立春->寅月, 惊蛰->卯月, 清明->辰月, 立夏->巳月, 芒种->午月, 小暑->未月,
# 立秋->申月, 白露->酉月, 寒露->戌月, 立冬->亥月, 大雪->子月, 小寒->丑月
JIE_QI_MONTH_MAP = [
('小寒', '丑'), ('立春', '寅'), ('惊蛰', '卯'), ('清明', '辰'),
('立夏', '巳'), ('芒种', '午'), ('小暑', '未'), ('立秋', '申'),
('白露', '酉'), ('寒露', '戌'), ('立冬', '亥'), ('大雪', '子'),
]
# 五虎遁:年干 -> 正月(寅月)天干起始索引
WU_HU_DUN = {
'甲': 2, '己': 2, # 丙
'乙': 4, '庚': 4, # 戊
'丙': 6, '辛': 6, # 庚
'丁': 8, '壬': 8, # 壬
'戊': 0, '癸': 0, # 甲
}
def get_jie_qi_datetime(year: int, jie_qi_name: str) -> datetime:
"""计算指定年份某个节气的日期时间(简化公式)
通用公式:[Y*D+C]-L,不同节气C值不同
"""
# 各节气的C值(21世纪),简化版
C_VALUES = {
'小寒': 5.4055, '立春': 3.87, '惊蛰': 7.58, '清明': 4.81,
'立夏': 5.52, '芒种': 7.928, '小暑': 7.108, '立秋': 2.35,
'白露': 7.44, '寒露': 8.318, '立冬': 7.438, '大雪': 7.18,
}
y = year % 100
d = 0.2422
c = C_VALUES[jie_qi_name]
l = y // 4
day = int(y * d + c) – l
# 月份映射
month_map = {'小寒': 1, '立春': 2, '惊蛰': 3, '清明': 4, '立夏': 5,
'芒种': 6, '小暑': 7, '立秋': 8, '白露': 9, '寒露': 10,
'立冬': 11, '大雪': 12}
return datetime(year, month_map[jie_qi_name], day, 0, 0, 0)
def get_month_pillar(dt: datetime, year_gan: str) -> str:
"""计算月柱"""
year = dt.year
# 找出当前日期属于哪个节的区间
current_jie = None
for jie_name, zhi in JIE_QI_MONTH_MAP:
jie_dt = get_jie_qi_datetime(year, jie_name)
if dt >= jie_dt:
current_jie = (jie_name, zhi)
# 处理1月小寒前的情况(属于上一年大雪->子月)
if current_jie is None:
current_jie = ('大雪', '子')
month_zhi = current_jie[1]
zhi_idx = DI_ZHI.index(month_zhi)
# 寅月为正月,索引为2
# 从寅月开始推算天干
start_gan_idx = WU_HU_DUN[year_gan]
# 寅月(zhi_idx=2)对应start_gan_idx,其他月份顺推
offset = zhi_idx – 2 if zhi_idx >= 2 else zhi_idx + 12 – 2
gan_idx = (start_gan_idx + offset) % 10
return TIAN_GAN[gan_idx] + DI_ZHI[zhi_idx]
3.4 日柱计算
日柱是四柱中最难精确计算的,因为需要知道一个基准日的干支,然后计算目标日期与基准日的天数差。
这里采用高氏日柱公式(适用于公历日期):
def get_day_pillar(dt: datetime) -> str:
"""计算日柱(高氏日柱公式)
基准:1900年1月1日为甲戌日(天干索引0,地支索引10)
实际验证:1900-01-01 为甲戌日
"""
# 基准日:1900年1月1日,甲戌
base_date = datetime(1900, 1, 1)
base_gan_idx = 0 # 甲
base_zhi_idx = 10 # 戌
# 计算天数差
delta_days = (dt.date() – base_date.date()).days
gan_idx = (base_gan_idx + delta_days) % 10
zhi_idx = (base_zhi_idx + delta_days) % 12
return TIAN_GAN[gan_idx] + DI_ZHI[zhi_idx]
注意子时边界:八字中,23:00-00:00 称为 “晚子时”,日柱已经算第二天。所以如果时间在 23:00-00:00,日柱要加一天。
def get_day_pillar_with_zi_hour(dt: datetime) -> str:
"""考虑子时边界的日柱计算"""
if dt.hour == 23:
dt = dt + timedelta(days=1)
return get_day_pillar(dt)
3.5 时柱计算
时柱的地支是固定的:23:00-01:00 为子时,01:00-03:00 为丑时…… 每两个小时一个时辰。
时柱的天干用五鼠遁日起时法推算:
甲己还加甲,乙庚丙作初,丙辛从戊起,丁壬庚子居,戊癸何方发,壬子是真途。
# 五鼠遁:日干 -> 子时天干起始索引
WU_SHU_DUN = {
'甲': 0, '己': 0, # 甲子
'乙': 2, '庚': 2, # 丙子
'丙': 4, '辛': 4, # 戊子
'丁': 6, '壬': 6, # 庚子
'戊': 8, '癸': 8, # 壬子
}
def get_hour_pillar(dt: datetime, day_gan: str) -> str:
"""计算时柱(五鼠遁日起时法)"""
hour = dt.hour
# 子时:23:00-01:00,注意23点属于当天的晚子时,但时支仍是子
if hour == 23 or hour == 0:
zhi_idx = 0 # 子
else:
zhi_idx = (hour + 1) // 2 # 1->1(丑), 3->2(寅), …
start_gan_idx = WU_SHU_DUN[day_gan]
gan_idx = (start_gan_idx + zhi_idx) % 10
return TIAN_GAN[gan_idx] + DI_ZHI[zhi_idx]
四、五行计算模块
排盘完成后,需要统计八字中五行的力量分布。这是判断喜用神的基础。
4.1 五行力量统计
def calc_wuxing_scores(bazi: dict) -> dict:
"""计算八字各五行力量得分
考虑:天干本气 + 地支藏干(按权重)
"""
scores = {'金': 0, '木': 0, '水': 0, '火': 0, '土': 0}
pillars = ['年柱', '月柱', '日柱', '时柱']
for pillar in pillars:
gan = bazi[pillar][0]
zhi = bazi[pillar][1]
# 天干直接计入,权重1.0
gan_wuxing = TIAN_GAN_WUXING[gan]
scores[gan_wuxing] += 1.0
# 地支按藏干权重计入
for cang_gan, weight in DI_ZHI_CANG_GAN[zhi]:
cang_wuxing = TIAN_GAN_WUXING[cang_gan]
scores[cang_wuxing] += weight
return scores
4.2 月令旺衰修正
上面的计算只是 “数量” 统计,但八字中五行的强弱还受月令(月支)的巨大影响 —— 得令者强,失令者弱。
# 月令旺衰表:月支 -> 各五行的旺衰系数
# 旺、相、休、囚、死 对应系数 1.5, 1.2, 1.0, 0.8, 0.5
MONTH_WANG_SHUAI = {
# 寅卯月(木旺):木旺、火相、水休、金囚、土死
'寅': {'木': 1.5, '火': 1.2, '水': 1.0, '金': 0.8, '土': 0.5},
'卯': {'木': 1.5, '火': 1.2, '水': 1.0, '金': 0.8, '土': 0.5},
# 巳午月(火旺):火旺、土相、木休、水囚、金死
'巳': {'火': 1.5, '土': 1.2, '木': 1.0, '水': 0.8, '金': 0.5},
'午': {'火': 1.5, '土': 1.2, '木': 1.0, '水': 0.8, '金': 0.5},
# 申酉月(金旺):金旺、水相、土休、火囚、木死
'申': {'金': 1.5, '水': 1.2, '土': 1.0, '火': 0.8, '木': 0.5},
'酉': {'金': 1.5, '水': 1.2, '土': 1.0, '火': 0.8, '木': 0.5},
# 亥子月(水旺):水旺、木相、金休、土囚、火死
'亥': {'水': 1.5, '木': 1.2, '金': 1.0, '土': 0.8, '火': 0.5},
'子': {'水': 1.5, '木': 1.2, '金': 1.0, '土': 0.8, '火': 0.5},
# 辰戌丑未月(土旺):土旺、金相、火休、木囚、水死
'辰': {'土': 1.5, '金': 1.2, '火': 1.0, '木': 0.8, '水': 0.5},
'戌': {'土': 1.5, '金': 1.2, '火': 1.0, '木': 0.8, '水': 0.5},
'丑': {'土': 1.5, '金': 1.2, '火': 1.0, '木': 0.8, '水': 0.5},
'未': {'土': 1.5, '金': 1.2, '火': 1.0, '木': 0.8, '水': 0.5},
}
def calc_wuxing_with_month(bazi: dict) -> dict:
"""考虑月令旺衰的五行力量计算"""
raw_scores = calc_wuxing_scores(bazi)
month_zhi = bazi['月柱'][1]
wang_shuai = MONTH_WANG_SHUAI[month_zhi]
final_scores = {}
for wuxing in ['金', '木', '水', '火', '土']:
final_scores[wuxing] = round(raw_scores[wuxing] * wang_shuai[wuxing], 2)
return final_scores
4.3 喜用神判断(简化版)
喜用神判断是八字中最复杂的部分,需要综合考虑日主强弱、调候、格局等因素。这里给出一个简化版的判断逻辑:
def judge_yong_shen(bazi: dict, wuxing_scores: dict) -> dict:
"""简化版喜用神判断
逻辑:以日干为日主,判断身强身弱,身强宜克泄耗,身弱宜生扶
"""
day_gan = bazi['日柱'][0]
day_wuxing = TIAN_GAN_WUXING[day_gan]
# 日主得分 = 同五行(比劫)+ 生我五行(印枭)
# 克我(官杀)、我克(财星)、我生(食伤)为泄耗
sheng_wo = {'木': '水', '火': '木', '土': '火', '金': '土', '水': '金'}
self_score = wuxing_scores[day_wuxing] + wuxing_scores[sheng_wo[day_wuxing]]
total = sum(wuxing_scores.values())
self_ratio = self_score / total if total > 0 else 0.5
# 身强:生扶力量超过55%;身弱:低于45%;中和:之间
if self_ratio > 0.55:
body_state = '身强'
# 身强宜克泄耗:克我(官杀)、我克(财星)、我生(食伤)
ke_wo = {'木': '金', '火': '水', '土': '木', '金': '火', '水': '土'}
wo_ke = {'木': '土', '火': '金', '土': '水', '金': '木', '水': '火'}
wo_sheng = {'木': '火', '火': '土', '土': '金', '金': '水', '水': '木'}
yong_shen = [ke_wo[day_wuxing], wo_ke[day_wuxing], wo_sheng[day_wuxing]]
elif self_ratio < 0.45:
body_state = '身弱'
# 身弱宜生扶:同五行(比劫)、生我(印枭)
yong_shen = [day_wuxing, sheng_wo[day_wuxing]]
else:
body_state = '中和'
# 中和则看调候,冬生喜火,夏生喜水
month_zhi = bazi['月柱'][1]
if month_zhi in ['亥', '子', '丑']:
yong_shen = ['火']
elif month_zhi in ['巳', '午', '未']:
yong_shen = ['水']
else:
yong_shen = [day_wuxing]
return {
'日主': day_gan,
'日主五行': day_wuxing,
'身强身弱': body_state,
'喜用神': yong_shen,
'生扶占比': round(self_ratio, 2),
}
五、完整排盘接口
把上面的模块整合起来,形成一个完整的排盘函数:
def bazi_pai_pan(dt: datetime) -> dict:
"""完整八字排盘"""
# 年柱
year_pillar = get_year_pillar(dt)
year_gan = year_pillar[0]
# 月柱
month_pillar = get_month_pillar(dt, year_gan)
# 日柱(考虑子时边界)
day_pillar = get_day_pillar_with_zi_hour(dt)
day_gan = day_pillar[0]
# 时柱
hour_pillar = get_hour_pillar(dt, day_gan)
bazi = {
'年柱': year_pillar,
'月柱': month_pillar,
'日柱': day_pillar,
'时柱': hour_pillar,
}
# 五行计算
wuxing_raw = calc_wuxing_scores(bazi)
wuxing_final = calc_wuxing_with_month(bazi)
# 喜用神
yong_shen = judge_yong_shen(bazi, wuxing_final)
return {
'八字': bazi,
'五行统计(原始)': wuxing_raw,
'五行统计(含月令)': wuxing_final,
'喜用神分析': yong_shen,
}
# 测试
if __name__ == '__main__':
test_date = datetime(2024, 6, 15, 10, 30)
result = bazi_pai_pan(test_date)
print(f"排盘时间:{test_date}")
print(f"年柱:{result['八字']['年柱']}")
print(f"月柱:{result['八字']['月柱']}")
print(f"日柱:{result['八字']['日柱']}")
print(f"时柱:{result['八字']['时柱']}")
print(f"五行:{result['五行统计(含月令)']}")
print(f"喜用神:{result['喜用神分析']}")
运行输出示例:
排盘时间:2024-06-15 10:30:00
年柱:甲辰
月柱:庚午
日柱:庚寅
时柱:辛巳
五行:{'金': 3.5, '木': 1.8, '水': 0.5, '火': 2.7, '土': 1.2}
喜用神:{'日主': '庚', '日主五行': '金', '身强身弱': '身强', '喜用神': ['火', '木', '水'], '生扶占比': 0.62}
六、精度验证与注意事项
6.1 节气精度
本文的节气计算使用了简化公式,精度在 ±1 天左右。对于节气交接日(比如刚好立春那天出生),建议用更精确的天文算法(如 Swiss Ephemeris 库)或查表法。
推荐方案:生产环境中,可以预计算 1900-2100 年所有节气的精确时间(数据可从天文台获取),存成 JSON 文件,运行时直接查表,既快又准。
6.2 子时争议
八字中关于 “子时” 有两大流派:
- 早子时晚子时派:23:00-00:00 为晚子时,日柱算第二天,时柱天干按第二天日干推算;00:00-01:00 为早子时,日柱算当天。
- 夜子时派:23:00-01:00 统一为子时,日柱以 0 点为界。
本文采用的是早子时晚子时派(23 点后日柱换第二天),这也是目前大多数排盘软件的主流做法。
6.3 在线验证
排盘结果是否准确,可以通过在线工具交叉验证。笔者在 529 宝宝起名网 中实现了完整的八字排盘功能,采用预计算节气精确时间 + 早子时晚子时处理,有需要的朋友可以前往对比验证。
七、总结
本文从最基础的天干地支开始,完整实现了:
这套算法可以直接应用于起名工具、择日系统、命理分析等场景。文中代码为了便于阅读做了简化,生产环境使用时建议:
- 用精确节气表替代公式计算
- 增加真太阳时换算(根据出生地经度)
- 完善喜用神判断逻辑(加入调候、格局、刑冲合害等)
在线体验完整排盘与起名工具: 529 宝宝起名网
如果本文对你有帮助,欢迎点赞收藏,有问题评论区交流。

