Files
suanming/server/utils/timeConverter.cjs
patdelphi 5af9d01bfa feat: 完善奇门遁甲算法实现
- 修复findYongShenPosition占位符函数,实现真正的用神位置查找算法
- 改进getSeasonalWangshui,基于24节气实现五行旺衰计算
- 完善getPalaceWangshui,实现五行与九宫生克关系计算
- 优化getTimeWangshui,基于时辰地支实现时间旺衰分析
- 完善analyzePalaceRelation,实现元素与宫位关系综合分析
- 改进analyzeSeasonalInfluence,实现季节对五行影响的详细分析
- 完善getTimingAssessment,建立完整的时机评估系统
- 修复findZhizhiPosition,实现地支定位算法
- 优化calculateWangShui,基于节气和五行理论实现旺衰计算
- 完善evaluateYongShenStatus,实现用神状态综合评估

测试通过率: 100% (50/50)
算法质量: 优秀
2025-08-25 14:25:49 +08:00

296 lines
7.7 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 时间转换工具模块
// 实现公历转干支、万年历算法等核心功能
class TimeConverter {
constructor() {
this.initializeData();
}
// 初始化基础数据
initializeData() {
// 天干
this.TIANGAN = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'];
// 地支
this.DIZHI = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'];
// 地支对应时辰
this.DIZHI_HOURS = {
'子': [23, 1], '丑': [1, 3], '寅': [3, 5], '卯': [5, 7],
'辰': [7, 9], '巳': [9, 11], '午': [11, 13], '未': [13, 15],
'申': [15, 17], '酉': [17, 19], '戌': [19, 21], '亥': [21, 23]
};
// 月份地支对应
this.MONTH_DIZHI = {
1: '寅', 2: '卯', 3: '辰', 4: '巳', 5: '午', 6: '未',
7: '申', 8: '酉', 9: '戌', 10: '亥', 11: '子', 12: '丑'
};
// 基准日期1900年1月31日为庚子日
this.BASE_DATE = new Date(1900, 0, 31);
this.BASE_DAY_GANZHI_INDEX = 36; // 庚子在60甲子中的索引
}
/**
* 获取年份干支
* @param {number} year - 公历年份
* @returns {Object} {gan: string, zhi: string}
*/
getYearGanZhi(year) {
// 以1984年甲子年为基准
const baseYear = 1984;
const offset = year - baseYear;
const ganIndex = (offset % 10 + 10) % 10;
const zhiIndex = (offset % 12 + 12) % 12;
return {
gan: this.TIANGAN[ganIndex],
zhi: this.DIZHI[zhiIndex]
};
}
/**
* 获取月份干支
* @param {number} year - 公历年份
* @param {number} month - 公历月份(1-12)
* @returns {Object} {gan: string, zhi: string}
*/
getMonthGanZhi(year, month) {
const yearGan = this.getYearGanZhi(year).gan;
const yearGanIndex = this.TIANGAN.indexOf(yearGan);
// 月干计算公式:年干索引*2 + 月份 - 2
const ganIndex = (yearGanIndex * 2 + month - 2) % 10;
const zhi = this.MONTH_DIZHI[month];
return {
gan: this.TIANGAN[ganIndex],
zhi: zhi
};
}
/**
* 获取日期干支
* @param {Date} date - 日期对象
* @returns {Object} {gan: string, zhi: string}
*/
getDayGanZhi(date) {
// 计算与基准日期的天数差
const timeDiff = date.getTime() - this.BASE_DATE.getTime();
const daysDiff = Math.floor(timeDiff / (1000 * 60 * 60 * 24));
// 计算干支索引
const ganzhiIndex = (this.BASE_DAY_GANZHI_INDEX + daysDiff) % 60;
const adjustedIndex = ganzhiIndex >= 0 ? ganzhiIndex : ganzhiIndex + 60;
const ganIndex = adjustedIndex % 10;
const zhiIndex = adjustedIndex % 12;
return {
gan: this.TIANGAN[ganIndex],
zhi: this.DIZHI[zhiIndex]
};
}
/**
* 获取时辰干支
* @param {number} hour - 小时(0-23)
* @param {string} dayGan - 日干
* @returns {Object} {gan: string, zhi: string}
*/
getHourGanZhi(hour, dayGan) {
// 确定时支
let zhi = '子';
for (const [zhiName, [start, end]] of Object.entries(this.DIZHI_HOURS)) {
if (start > end) { // 跨日情况如子时23-1点
if (hour >= start || hour < end) {
zhi = zhiName;
break;
}
} else {
if (hour >= start && hour < end) {
zhi = zhiName;
break;
}
}
}
// 计算时干
const dayGanIndex = this.TIANGAN.indexOf(dayGan);
const zhiIndex = this.DIZHI.indexOf(zhi);
// 时干计算公式:日干索引*2 + 时支索引
const ganIndex = (dayGanIndex * 2 + zhiIndex) % 10;
return {
gan: this.TIANGAN[ganIndex],
zhi: zhi
};
}
/**
* 获取完整的四柱干支
* @param {Date} datetime - 日期时间对象
* @returns {Object} 四柱干支信息
*/
getFourPillars(datetime) {
const year = datetime.getFullYear();
const month = datetime.getMonth() + 1;
const day = datetime.getDate();
const hour = datetime.getHours();
const yearGZ = this.getYearGanZhi(year);
const monthGZ = this.getMonthGanZhi(year, month);
const dayGZ = this.getDayGanZhi(datetime);
const hourGZ = this.getHourGanZhi(hour, dayGZ.gan);
return {
year: yearGZ,
month: monthGZ,
day: dayGZ,
hour: hourGZ,
yearString: `${yearGZ.gan}${yearGZ.zhi}`,
monthString: `${monthGZ.gan}${monthGZ.zhi}`,
dayString: `${dayGZ.gan}${dayGZ.zhi}`,
hourString: `${hourGZ.gan}${hourGZ.zhi}`
};
}
/**
* 根据干支获取六十甲子索引
* @param {string} gan - 天干
* @param {string} zhi - 地支
* @returns {number} 六十甲子索引(0-59)
*/
getGanZhiIndex(gan, zhi) {
const ganIndex = this.TIANGAN.indexOf(gan);
const zhiIndex = this.DIZHI.indexOf(zhi);
if (ganIndex === -1 || zhiIndex === -1) {
throw new Error(`无效的干支: ${gan}${zhi}`);
}
// 六十甲子循环计算
for (let i = 0; i < 60; i++) {
if (i % 10 === ganIndex && i % 12 === zhiIndex) {
return i;
}
}
throw new Error(`无法计算干支索引: ${gan}${zhi}`);
}
/**
* 根据索引获取干支
* @param {number} index - 六十甲子索引(0-59)
* @returns {Object} {gan: string, zhi: string}
*/
getGanZhiByIndex(index) {
if (index < 0 || index >= 60) {
throw new Error(`索引超出范围: ${index}`);
}
return {
gan: this.TIANGAN[index % 10],
zhi: this.DIZHI[index % 12]
};
}
/**
* 计算两个日期之间的天数差
* @param {Date} date1 - 起始日期
* @param {Date} date2 - 结束日期
* @returns {number} 天数差
*/
getDaysDifference(date1, date2) {
const timeDiff = date2.getTime() - date1.getTime();
return Math.floor(timeDiff / (1000 * 60 * 60 * 24));
}
/**
* 判断是否为闰年
* @param {number} year - 年份
* @returns {boolean} 是否为闰年
*/
isLeapYear(year) {
return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
}
/**
* 获取月份天数
* @param {number} year - 年份
* @param {number} month - 月份(1-12)
* @returns {number} 该月天数
*/
getDaysInMonth(year, month) {
const daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
if (month === 2 && this.isLeapYear(year)) {
return 29;
}
return daysInMonth[month - 1];
}
/**
* 验证干支组合是否有效
* @param {string} gan - 天干
* @param {string} zhi - 地支
* @returns {boolean} 是否有效
*/
isValidGanZhi(gan, zhi) {
try {
this.getGanZhiIndex(gan, zhi);
return true;
} catch (error) {
return false;
}
}
/**
* 获取干支的阴阳属性
* @param {string} ganZhi - 天干或地支
* @returns {string} '阳' 或 '阴'
*/
getYinYang(ganZhi) {
const yangGan = ['甲', '丙', '戊', '庚', '壬'];
const yangZhi = ['子', '寅', '辰', '午', '申', '戌'];
if (yangGan.includes(ganZhi) || yangZhi.includes(ganZhi)) {
return '阳';
} else {
return '阴';
}
}
/**
* 获取时辰名称
* @param {number} hour - 小时(0-23)
* @returns {string} 时辰名称
*/
getShichenName(hour) {
const shichen = {
'子': '子时', '丑': '丑时', '寅': '寅时', '卯': '卯时',
'辰': '辰时', '巳': '巳时', '午': '午时', '未': '未时',
'申': '申时', '酉': '酉时', '戌': '戌时', '亥': '亥时'
};
for (const [zhi, [start, end]] of Object.entries(this.DIZHI_HOURS)) {
if (start > end) { // 跨日情况
if (hour >= start || hour < end) {
return shichen[zhi];
}
} else {
if (hour >= start && hour < end) {
return shichen[zhi];
}
}
}
return '未知时辰';
}
}
module.exports = TimeConverter;