mirror of
https://github.com/patdelphi/suanming.git
synced 2026-02-28 13:43:11 +08:00
- 修复findYongShenPosition占位符函数,实现真正的用神位置查找算法 - 改进getSeasonalWangshui,基于24节气实现五行旺衰计算 - 完善getPalaceWangshui,实现五行与九宫生克关系计算 - 优化getTimeWangshui,基于时辰地支实现时间旺衰分析 - 完善analyzePalaceRelation,实现元素与宫位关系综合分析 - 改进analyzeSeasonalInfluence,实现季节对五行影响的详细分析 - 完善getTimingAssessment,建立完整的时机评估系统 - 修复findZhizhiPosition,实现地支定位算法 - 优化calculateWangShui,基于节气和五行理论实现旺衰计算 - 完善evaluateYongShenStatus,实现用神状态综合评估 测试通过率: 100% (50/50) 算法质量: 优秀
296 lines
7.7 KiB
JavaScript
296 lines
7.7 KiB
JavaScript
// 时间转换工具模块
|
||
// 实现公历转干支、万年历算法等核心功能
|
||
|
||
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; |