UNPKG

yijing-bazi-mcp

Version:

易经八字分析 MCP 服务器 - 提供传统命理分析和易经卦象解读的AI工具

366 lines (322 loc) 11.1 kB
/** * 日期工具类 * 处理公历、农历转换,节气计算等功能 */ const Lunar = require('lunar-javascript'); const moment = require('moment-timezone'); class DateUtils { constructor() { this.timezone = 'Asia/Shanghai'; } /** * 将公历日期转换为农历 * @param {Date|string} date - 公历日期 * @returns {Object} 农历信息 */ solarToLunar(date) { try { const solarDate = moment(date).tz(this.timezone); const lunar = Lunar.Solar.fromDate(solarDate.toDate()).getLunar(); return { year: lunar.getYear(), month: lunar.getMonth(), day: lunar.getDay(), yearInChinese: lunar.getYearInChinese(), monthInChinese: lunar.getMonthInChinese(), dayInChinese: lunar.getDayInChinese(), yearInGanZhi: lunar.getYearInGanZhi(), monthInGanZhi: lunar.getMonthInGanZhi(), dayInGanZhi: lunar.getDayInGanZhi(), timeInGanZhi: this.getTimeInGanZhi(solarDate.hour()), isLeapMonth: lunar.isLeap(), festivals: lunar.getFestivals(), jieQi: lunar.getJieQi(), constellation: lunar.getXingZuo(), animal: lunar.getYearShengXiao() }; } catch (error) { throw new Error(`日期转换失败: ${error.message}`); } } /** * 根据时辰获取时柱干支 * @param {number} hour - 小时(0-23) * @returns {string} 时柱干支 */ getTimeInGanZhi(hour) { const timeMap = { 23: '子', 0: '子', 1: '丑', 2: '丑', 3: '寅', 4: '寅', 5: '卯', 6: '卯', 7: '辰', 8: '辰', 9: '巳', 10: '巳', 11: '午', 12: '午', 13: '未', 14: '未', 15: '申', 16: '申', 17: '酉', 18: '酉', 19: '戌', 20: '戌', 21: '亥', 22: '亥' }; const timeBranch = timeMap[hour]; if (!timeBranch) return '未知'; // 根据日干推算时干 // 这里需要结合具体的日干来计算时干 // 简化处理,返回地支 return timeBranch; } /** * 计算完整的四柱八字 * @param {Date|string} birthDate - 出生日期时间 * @param {string} timezone - 时区,默认为北京时间 * @returns {Object} 四柱八字信息 */ calculateBaZi(birthDate, timezone = 'Asia/Shanghai') { try { const birthMoment = moment(birthDate).tz(timezone); const solar = Lunar.Solar.fromDate(birthMoment.toDate()); const lunar = solar.getLunar(); // 获取年柱 const yearGanZhi = lunar.getYearInGanZhi(); const yearGan = yearGanZhi.charAt(0); const yearZhi = yearGanZhi.charAt(1); // 获取月柱 const monthGanZhi = lunar.getMonthInGanZhi(); const monthGan = monthGanZhi.charAt(0); const monthZhi = monthGanZhi.charAt(1); // 获取日柱 const dayGanZhi = lunar.getDayInGanZhi(); const dayGan = dayGanZhi.charAt(0); const dayZhi = dayGanZhi.charAt(1); // 计算时柱 const hour = birthMoment.hour(); const timeZhi = this.getTimeBranch(hour); const timeGan = this.calculateTimeStem(dayGan, timeZhi); return { year: { stem: yearGan, branch: yearZhi, ganZhi: yearGanZhi }, month: { stem: monthGan, branch: monthZhi, ganZhi: monthGanZhi }, day: { stem: dayGan, branch: dayZhi, ganZhi: dayGanZhi }, time: { stem: timeGan, branch: timeZhi, ganZhi: timeGan + timeZhi }, birthInfo: { solar: { year: birthMoment.year(), month: birthMoment.month() + 1, day: birthMoment.date(), hour: birthMoment.hour(), minute: birthMoment.minute() }, lunar: { year: lunar.getYear(), month: lunar.getMonth(), day: lunar.getDay(), yearInChinese: lunar.getYearInChinese(), monthInChinese: lunar.getMonthInChinese(), dayInChinese: lunar.getDayInChinese(), isLeapMonth: lunar.isLeap() }, timezone: timezone, jieQi: lunar.getJieQi(), constellation: lunar.getXingZuo(), animal: lunar.getYearShengXiao() } }; } catch (error) { throw new Error(`八字计算失败: ${error.message}`); } } /** * 根据小时获取时支 * @param {number} hour - 小时(0-23) * @returns {string} 时支 */ getTimeBranch(hour) { const branches = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']; if (hour === 23 || hour === 0) return '子'; if (hour >= 1 && hour <= 2) return '丑'; if (hour >= 3 && hour <= 4) return '寅'; if (hour >= 5 && hour <= 6) return '卯'; if (hour >= 7 && hour <= 8) return '辰'; if (hour >= 9 && hour <= 10) return '巳'; if (hour >= 11 && hour <= 12) return '午'; if (hour >= 13 && hour <= 14) return '未'; if (hour >= 15 && hour <= 16) return '申'; if (hour >= 17 && hour <= 18) return '酉'; if (hour >= 19 && hour <= 20) return '戌'; if (hour >= 21 && hour <= 22) return '亥'; return '子'; // 默认返回子时 } /** * 根据日干和时支计算时干 * @param {string} dayStem - 日干 * @param {string} timeBranch - 时支 * @returns {string} 时干 */ calculateTimeStem(dayStem, timeBranch) { const stems = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']; const branches = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']; const dayIndex = stems.indexOf(dayStem); const timeIndex = branches.indexOf(timeBranch); if (dayIndex === -1 || timeIndex === -1) return '甲'; // 默认返回甲 // 时干计算公式:(日干序号 * 2 + 时支序号) % 10 const timeStemIndex = (dayIndex * 2 + timeIndex) % 10; return stems[timeStemIndex]; } /** * 计算大运 * @param {Object} bazi - 八字信息 * @param {string} gender - 性别 ('male' | 'female') * @returns {Array} 大运信息 */ calculateMajorLuck(bazi, gender) { try { const birthYear = bazi.birthInfo.solar.year; const monthStem = bazi.month.stem; const monthBranch = bazi.month.branch; const stems = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']; const branches = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']; const monthStemIndex = stems.indexOf(monthStem); const monthBranchIndex = branches.indexOf(monthBranch); // 判断顺逆 const yearStem = bazi.year.stem; const isYangYear = ['甲', '丙', '戊', '庚', '壬'].includes(yearStem); const isForward = (gender === 'male' && isYangYear) || (gender === 'female' && !isYangYear); const majorLuck = []; const direction = isForward ? 1 : -1; for (let i = 0; i < 8; i++) { const stemIndex = (monthStemIndex + direction * (i + 1) + 10) % 10; const branchIndex = (monthBranchIndex + direction * (i + 1) + 12) % 12; const startAge = (i + 1) * 10; const endAge = startAge + 9; const startYear = birthYear + startAge; const endYear = birthYear + endAge; majorLuck.push({ period: i + 1, stem: stems[stemIndex], branch: branches[branchIndex], ganZhi: stems[stemIndex] + branches[branchIndex], startAge, endAge, startYear, endYear, description: `第${i + 1}步大运:${stems[stemIndex]}${branches[branchIndex]}${startAge}-${endAge}岁)` }); } return majorLuck; } catch (error) { throw new Error(`大运计算失败: ${error.message}`); } } /** * 计算流年 * @param {number} year - 年份 * @returns {Object} 流年信息 */ calculateAnnualLuck(year) { try { const solar = Lunar.Solar.fromYmd(year, 1, 1); const lunar = solar.getLunar(); const yearGanZhi = lunar.getYearInGanZhi(); return { year, stem: yearGanZhi.charAt(0), branch: yearGanZhi.charAt(1), ganZhi: yearGanZhi, animal: lunar.getYearShengXiao(), description: `${year}${yearGanZhi}${lunar.getYearShengXiao()}年` }; } catch (error) { throw new Error(`流年计算失败: ${error.message}`); } } /** * 计算流月 * @param {number} year - 年份 * @param {number} month - 月份 * @returns {Object} 流月信息 */ calculateMonthlyLuck(year, month) { try { const solar = Lunar.Solar.fromYmd(year, month, 1); const lunar = solar.getLunar(); const monthGanZhi = lunar.getMonthInGanZhi(); return { year, month, stem: monthGanZhi.charAt(0), branch: monthGanZhi.charAt(1), ganZhi: monthGanZhi, lunarMonth: lunar.getMonth(), lunarMonthInChinese: lunar.getMonthInChinese(), jieQi: lunar.getJieQi(), description: `${year}${month}${monthGanZhi}月` }; } catch (error) { throw new Error(`流月计算失败: ${error.message}`); } } /** * 验证日期格式 * @param {string|Date} date - 日期 * @returns {boolean} 是否有效 */ isValidDate(date) { const momentDate = moment(date); return momentDate.isValid(); } /** * 格式化日期 * @param {string|Date} date - 日期 * @param {string} format - 格式 * @returns {string} 格式化后的日期 */ formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') { return moment(date).tz(this.timezone).format(format); } /** * 获取当前时间的八字 * @returns {Object} 当前时间八字 */ getCurrentBaZi() { return this.calculateBaZi(new Date()); } /** * 计算年龄 * @param {string|Date} birthDate - 出生日期 * @param {string|Date} currentDate - 当前日期,默认为今天 * @returns {Object} 年龄信息 */ calculateAge(birthDate, currentDate = new Date()) { const birth = moment(birthDate); const current = moment(currentDate); const years = current.diff(birth, 'years'); const months = current.diff(birth, 'months') % 12; const days = current.diff(birth.add(years, 'years').add(months, 'months'), 'days'); return { years, months, days, totalDays: current.diff(birth, 'days'), description: `${years}${months}个月${days}天` }; } /** * 获取节气信息 * @param {number} year - 年份 * @returns {Array} 节气列表 */ getJieQiList(year) { try { const jieQiList = []; for (let month = 1; month <= 12; month++) { const solar = Lunar.Solar.fromYmd(year, month, 1); const lunar = solar.getLunar(); const jieQi = lunar.getJieQi(); if (jieQi) { jieQiList.push({ name: jieQi, month, description: `${year}${month}${jieQi}` }); } } return jieQiList; } catch (error) { throw new Error(`节气获取失败: ${error.message}`); } } } module.exports = DateUtils;