You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript中实现阳历到阴历的转换功能?

JavaScript实现阳历转阴历的方案

要实现阳历(公历)转阴历(农历),核心是利用预编排的农历数据——因为农历是阴阳合历,涉及节气、闰月的天文计算复杂度极高,直接用现成的农历编排表是最实用的落地方案。下面是具体的实现思路和代码:

核心思路

  1. 以某一个已知的“阳历-农历对应日期”为基准(比如1900年1月31日对应农历1900年正月初一);
  2. 计算目标阳历日期与基准日的天数差;
  3. 对照预定义的农历年份数据(包含每年的闰月信息、每个月的天数),将天数差映射为对应的农历年、月、日;
  4. 附加干支纪年的计算逻辑。

具体实现代码

// 天干地支、农历月日名称定义
const TIANGAN = ['甲','乙','丙','丁','戊','己','庚','辛','壬','癸'];
const DIZHI = ['子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥'];
const LUNAR_MONTHS = ['正月','二月','三月','四月','五月','六月','七月','八月','九月','十月','冬月','腊月'];
const LUNAR_DAYS = ['初一','初二','初三','初四','初五','初六','初七','初八','初九','初十','十一','十二','十三','十四','十五','十六','十七','十八','十九','二十','廿一','廿二','廿三','廿四','廿五','廿六','廿七','廿八','廿九','三十'];

// 农历核心数据:1900-1905年的闰月+各月天数(示例,实际需补充1900-2100完整数据)
const LUNAR_YEAR_DATA = [
  { leapMonth: 8, months: [29,30,29,30,29,30,29,30,29,30,29,30] }, // 1900年,闰八月
  { leapMonth: 0, months: [30,29,30,29,30,29,30,29,30,29,30,29] }, // 1901年,无闰月
  { leapMonth: 6, months: [29,30,29,30,29,30,29,30,29,30,29,30] }, // 1902年,闰六月
  { leapMonth: 0, months: [30,29,30,29,30,29,30,29,30,29,30,29] }, // 1903年,无闰月
  { leapMonth: 5, months: [29,30,29,30,29,30,29,30,29,30,29,30] }, // 1904年,闰五月
  { leapMonth: 0, months: [30,29,30,29,30,29,30,29,30,29,30,29] }  // 1905年,无闰月
];

/**
 * 阳历转阴历
 * @param {number} year - 阳历年(如2024)
 * @param {number} month - 阳历月(1-12)
 * @param {number} day - 阳历日(1-31)
 * @returns {object} 农历对象:{year, yearGanZhi, month, day}
 */
function solarToLunar(year, month, day) {
  // 基准日期:1900年1月31日 = 农历1900年正月初一
  const BASE_DATE = new Date(1900, 0, 31);
  const targetDate = new Date(year, month - 1, day);
  
  // 计算天数差(排除时分秒影响)
  const diffDays = Math.floor((targetDate - BASE_DATE) / (1000 * 60 * 60 * 24));
  if (diffDays < 0) throw new Error('仅支持1900年正月初一及以后的日期转换');

  let totalDays = 0;
  let lunarYear = 1900;
  let lunarMonth = 1;
  let lunarDay = 1;
  let leapMonth = 0;

  // 定位农历年份
  while (lunarYear <= 2100) {
    const yearData = LUNAR_YEAR_DATA[lunarYear - 1900];
    if (!yearData) throw new Error('暂不支持该年份的转换,请补充农历数据');
    
    // 计算当年总天数(含闰月)
    const yearTotalDays = yearData.months.reduce((sum, d) => sum + d, 0) + 
                          (yearData.leapMonth ? yearData.months[yearData.leapMonth - 1] : 0);
    
    if (totalDays + yearTotalDays > diffDays) break;
    totalDays += yearTotalDays;
    lunarYear++;
  }

  // 定位农历月份
  const currentYearData = LUNAR_YEAR_DATA[lunarYear - 1900];
  leapMonth = currentYearData.leapMonth;
  let monthIndex = 0;

  while (monthIndex < currentYearData.months.length) {
    const monthDays = currentYearData.months[monthIndex];
    // 检查当前月是否容纳剩余天数
    if (totalDays + monthDays > diffDays) {
      lunarMonth = monthIndex + 1;
      break;
    }
    totalDays += monthDays;

    // 处理闰月:如果当前是闰月月份,额外检查闰月
    if (leapMonth === monthIndex + 1) {
      if (totalDays + monthDays > diffDays) {
        lunarMonth = `闰${LUNAR_MONTHS[leapMonth - 1]}`;
        break;
      }
      totalDays += monthDays;
    }
    monthIndex++;
  }

  // 计算农历日期
  lunarDay = diffDays - totalDays + 1;

  // 计算干支纪年
  const ganIndex = (lunarYear - 4) % 10;
  const zhiIndex = (lunarYear - 4) % 12;
  const yearGanZhi = TIANGAN[ganIndex] + DIZHI[zhiIndex];

  return {
    year: lunarYear,
    yearGanZhi: yearGanZhi,
    month: typeof lunarMonth === 'number' ? LUNAR_MONTHS[lunarMonth - 1] : lunarMonth,
    day: LUNAR_DAYS[lunarDay - 1]
  };
}

// 示例调用
console.log(solarToLunar(2024, 9, 10)); // 输出:{ year: 2024, yearGanZhi: '甲辰', month: '八月', day: '初六' }

关键说明

  1. 农历数据补充:示例只包含1900-1905年的数据,实际使用时需要补充完整的1900-2100年农历编排数据(网上可找到公开的完整数据集);
  2. 日期范围:当前代码支持1900年正月初一及以后的日期,若需扩展范围,只需补充对应年份的农历数据;
  3. 干支计算:干支纪年以农历年为基准,公式(农历年-4)%10/12是因为公元4年为甲子年;
  4. 闰月处理:代码会自动识别闰月,并在返回的月份名称前加上“闰”字。

内容的提问来源于stack exchange,提问作者Jin Liu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 04:50:23