JavaScript农历与公历转换算法实现
在网页开发中,日历类应用经常需要处理农历与公历的对应关系。由于农历是阴阳合历,其置闰规则(十九年七闰)较为复杂。本文分享一段基于 JavaScript 的经典转换代码,通过核心数据表 lunarInfo 配合数学算法,即可在客户端轻松完成 1891-2100 年的日期双向换算。
转换原理与数据结构
农历转换的核心在于掌握每一年的历法特征。该算法使用一个预定义的数据数组 lunarInfo,存储了从 1891 年到 2100 年每年的关键信息。每一年由一个包含四个数字的数组表示,例如:[闰月月份, 正月天数, 正月初一对应的公历日期, 月份二进制数据]。
lunarInfo 中的后三位数字通常以十进制存储,但在实际处理时,最后一个数字会被转换为 16 位的二进制数。这个二进制序列的每一位代表该农历年中对应月份的大小:'1' 代表大月(30天),'0' 代表小月(29天)。通过这种压缩方式,可以高效地判断任意月份的准确天数。
核心功能实现步骤
第1步:配置基础年份范围
确定转换的有效区间。代码中定义了 MIN_YEAR : 1891 和 MAX_YEAR : 2100,这覆盖了绝大多数现代应用场景的需求范围。超出此范围的日期需要进行额外的逻辑扩展或提示用户。
第2步:初始化公历计算辅助函数
首先确保公历部分计算准确。系统实现了 isLeapYear 方法来判断闰年,进而通过 solarMonthDays 获取公历各月的天数(特别是二月是 28 还是 29 天)。这是进行“农历转公历”时的基准参照。
第3步:实现公历转农历(toLunar)
当需要将公历日期(如 2016-07-06)转换为农历时,算法执行以下逻辑:
- 定位基准日:查询当年对应的
lunarInfo,找到该年正月初一对应的公历日期(即yearData[1]月和yearData[2]日)。 - 计算天数差:利用 Date 对象计算目标公历日期与正月初一之间的天数差值(
betweenSolarDays)。 - 映射农历日期:根据天数差,在当年的农历月份序列中累加查找,确定具体的农历月份(
t)和日期(e)。 - 处理闰月:如果计算的月份恰好是当年的闰月,则在月份名称前添加“闰”字(如“闰五月”)。
- 格式化输出:最后将数字形式的年月日转换为中文形式(如“二零二三年 九月 十五”)以及干支纪年。
第4步:实现农历转公历(toSolar)
反向转换(如输入农历 2016-6-3 查公历)的流程如下:
- 获取农历天数偏移量:调用
betweenLunarDays,通过遍历当年的月份数据,计算目标农历日期距离该年正月初一的天数总和。 - 计算时间戳偏移:基于正月初一对应的公历日期,加上上一步计算出的天数差(转换为毫秒),得到目标日期的时间戳。
- 解析公历结果:利用 JavaScript 的
Date对象解析该时间戳,从而直接提取出公历的年、月、日数值。
完整代码示例
以下是整合好的 Lunar 对象代码。你可以直接将其嵌入项目中,并通过 Lunar.toSolar(年, 月, 日) 和 Lunar.toLunar(年, 月, 日) 调用接口。注意闰月的传入规则:若某年有闰月,第二个该月份需传为“闰月+1”后的序号(例如闰五月则传 6 月)。
var Lunar = {
MIN_YEAR : 1891,
MAX_YEAR : 2100,
// lunarInfo: 历年数据,此处省略具体数组内容以保持简洁
lunarInfo : [
// ... 完整的历年数据数组 ...
],
isLeapYear : function(year) {
return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));
},
solarMonthDays : function(year, month) {
var FebDays = this.isLeapYear(year) ? 29 : 28;
var monthHash = ['', 31, FebDays, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
return monthHash[month];
},
toLunar : function(year, month, day) {
var yearData = this.lunarInfo[year - this.MIN_YEAR];
if (year == this.MIN_YEAR && month <= 2 && day <= 9) {
return [1891, 1, 1, '辛卯', '兔', '正月', '初一'];
}
return this.lunarByBetween(year, this.betweenSolarDays(year, month, day, yearData[1], yearData[2]));
},
toSolar : function(year, month, day) {
var yearData = this.lunarInfo[year - this.MIN_YEAR];
var between = this.betweenLunarDays(year, month, day);
var ms = new Date(year +"-" + yearData[1] +"-"+ yearData[2]).getTime();
var s = ms + between * 24 * 60 * 60 * 1000;
var d = new Date();
d.setTime(s);
year = d.getFullYear();
month = d.getMonth() + 1;
day = d.getDate();
return [year, month, day];
},
// ... 其他内部计算方法(如 chineseNumber, betweenLunarDays 等)请参照完整源码 ...
};
以上就是JavaScript农历与公历相互转换的详细内容,更多关于JavaScript日期处理的技巧资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









