diff --git a/skills/chinese-almanac/almanac.js b/skills/chinese-almanac/almanac.js index b7a0569..3773722 100644 --- a/skills/chinese-almanac/almanac.js +++ b/skills/chinese-almanac/almanac.js @@ -1,27 +1,44 @@ /** * Chinese Almanac (黄历) Query Skill - * 使用 Tavily API 查询每日黄历信息 + * 使用 Tavily API 查询黄历 + lunar-javascript 计算农历 */ +const { Solar, Lunar } = require('lunar-javascript'); const TAVILY_API_KEY = process.env.TAVILY_API_KEY || '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'; +/** + * 计算农历日期(使用专业库) + * lunar-javascript 会自动处理时区,直接传入日期即可 + */ +function getLunarDate(jsDate) { + // 使用 local time 创建 Solar 对象,lunar-javascript 会正确处理 + const solar = Solar.fromYmd(jsDate.getFullYear(), jsDate.getMonth() + 1, jsDate.getDate()); + const lunar = solar.getLunar(); + + return { + lunarDate: lunar.toString(), // 如:二〇二六年正月初十 + lunarDay: lunar.getDayInChinese(), // 如:初十 + lunarMonth: lunar.getMonthInChinese(), // 如:正月 + lunarYear: lunar.getYearInChinese() // 如:二〇二六 + }; +} + /** * 查询黄历信息 */ async function queryAlmanac(date) { + let targetDate; if (!date) { - const tomorrow = new Date(); - tomorrow.setDate(tomorrow.getDate() + 1); - date = tomorrow.toISOString().split('T')[0]; + targetDate = new Date(); + targetDate.setDate(targetDate.getDate() + 1); // 明天 + } else { + targetDate = new Date(date); } - - // 动态计算农历日期(基于 2026 年春节 2 月 17 日) - const targetDate = date ? new Date(date) : new Date(); - const springFestival = new Date('2026-02-17'); - const lunarDay = Math.floor((targetDate - springFestival) / (1000 * 60 * 60 * 24)) + 1; - const lunarDateStr = `农历正月初${lunarDay}`; - const query = `${date} 黄历 宜忌 ${lunarDateStr}`; + // 使用专业库计算农历 + const lunarInfo = getLunarDate(targetDate); + + const query = `${targetDate.toISOString().split('T')[0]} 黄历 宜忌 ${lunarInfo.lunarDate}`; try { const response = await fetch('https://api.tavily.com/search', { @@ -43,12 +60,12 @@ async function queryAlmanac(date) { } const data = await response.json(); - const almanacInfo = parseAlmanacData(data, date, lunarDateStr); + const almanacInfo = parseAlmanacData(data, targetDate, lunarInfo); return { success: true, - date: date, - lunarDate: lunarDateStr, + date: targetDate.toISOString().split('T')[0], + lunarDate: lunarInfo.lunarDate, weekday: almanacInfo.weekday, ganzhi: almanacInfo.ganzhi, yi: almanacInfo.yi, @@ -59,7 +76,7 @@ async function queryAlmanac(date) { return { success: false, error: error.message, - fallback: getFallbackAlmanac(date, lunarDateStr) + fallback: getFallbackAlmanac(targetDate, lunarInfo) }; } } @@ -67,11 +84,11 @@ async function queryAlmanac(date) { /** * 解析黄历数据 */ -function parseAlmanacData(data, date, lunarDateStr) { +function parseAlmanacData(data, date, lunarInfo) { const result = { - lunarDate: lunarDateStr, + lunarDate: lunarInfo.lunarDate, weekday: getWeekday(date), - ganzhi: '丙午年 庚寅月 己巳日', + ganzhi: '丙午年 庚寅月 ' + getDayGanZhi(date), yi: ['作灶', '解除', '平治道涂', '余事勿取'], ji: ['祈福', '安葬', '祭祀', '安门'], chong: '冲猪 煞东' @@ -110,22 +127,40 @@ function parseAlmanacData(data, date, lunarDateStr) { /** * 获取星期 */ -function getWeekday(dateStr) { - const date = new Date(dateStr); +function getWeekday(date) { const weekdays = ['日', '一', '二', '三', '四', '五', '六']; return `星期${weekdays[date.getDay()]}`; } +/** + * 获取日干支(简化版) + */ +function getDayGanZhi(date) { + // 2026-02-17 是己巳日 + const baseDate = new Date('2026-02-17'); + const ganzhi = ['甲子','乙丑','丙寅','丁卯','戊辰','己巳','庚午','辛未','壬申','癸酉', + '甲戌','乙亥','丙子','丁丑','戊寅','己卯','庚辰','辛巳','壬午','癸未', + '甲申','乙酉','丙戌','丁亥','戊子','己丑','庚寅','辛卯','壬辰','癸巳', + '甲午','乙未','丙申','丁酉','戊戌','己亥','庚子','辛丑','壬寅','癸卯', + '甲辰','乙巳','丙午','丁未','戊申','己酉','庚戌','辛亥','壬子','癸丑', + '甲寅','乙卯','丙辰','丁巳','戊午','己未','庚申','辛酉','壬戌','癸亥']; + + const daysSince = Math.floor((date - baseDate) / (1000*60*60*24)); + const baseIndex = 5; // 己巳是第 5 个(从 0 开始) + const index = (baseIndex + daysSince) % 60; + return ganzhi[index >= 0 ? index : 60 + index] + '日'; +} + /** * Fallback 数据 */ -function getFallbackAlmanac(date, lunarDateStr) { +function getFallbackAlmanac(date, lunarInfo) { return { success: true, - date: date, - lunarDate: lunarDateStr, + date: date.toISOString().split('T')[0], + lunarDate: lunarInfo.lunarDate, weekday: getWeekday(date), - ganzhi: '丙午年 庚寅月 己巳日', + ganzhi: '丙午年 庚寅月 ' + getDayGanZhi(date), yi: ['作灶', '解除', '平治道涂', '余事勿取'], ji: ['祈福', '安葬', '祭祀', '安门'], chong: '冲猪 煞东', @@ -160,9 +195,15 @@ function formatAlmanac(almanac) { // 测试 if (require.main === module) { - queryAlmanac('2026-02-24').then(result => { - console.log(formatAlmanac(result)); - }); + console.log('=== 黄历查询测试(使用 lunar-javascript 库)===\n'); + + const arg = process.argv[2] || 'tomorrow'; + queryAlmanac(arg === 'today' ? null : (arg === 'tomorrow' ? undefined : arg)) + .then(result => { + console.log(formatAlmanac(result)); + console.log('\n详细信息:'); + console.log(`农历:${result.lunarDate}`); + }); } -module.exports = { queryAlmanac, formatAlmanac }; +module.exports = { queryAlmanac, formatAlmanac, getLunarDate };