Files
spring-festival-greetings/utils/lunar.js
2026-02-24 18:01:52 +08:00

179 lines
4.9 KiB
JavaScript
Raw 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.
/**
* 农历转换工具
* 仅包含简单的公历转农历功能
*/
const calendar = {
/**
* 农历 1900-2049 的润大小信息表
* @Array Of Property
* @return Hex
*/
lunarInfo: [
0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0,
0x09ad0, 0x055d2, 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540,
0x0d6a0, 0x0ada2, 0x095b0, 0x14977, 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50,
0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, 0x06566, 0x0d4a0,
0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950,
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2,
0x0a950, 0x0b557, 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5d0, 0x14573,
0x052d0, 0x0a9a8, 0x0e950, 0x06aa0, 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4,
0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, 0x096d0, 0x04dd5,
0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6,
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46,
0x0ab60, 0x09570, 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58,
0x055c0, 0x0ab60, 0x096d5, 0x092e0, 0x0c960, 0x0d954, 0x0d4a0, 0x0da50,
0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, 0x0a950, 0x0b4a0,
0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930,
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260,
0x0ea65, 0x0d530, 0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0,
0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, 0x0b5a0, 0x056d0, 0x055b2, 0x049b0,
0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0,
],
/**
* 传回农历 y年的总天数
* @param y
* @return Number
*/
lYearDays: function (y) {
var i,
sum = 348;
for (i = 0x8000; i > 0x8; i >>= 1)
sum += this.lunarInfo[y - 1900] & i ? 1 : 0;
return sum + this.leapDays(y);
},
/**
* 传回农历 y年闰月的天数
* @param y
* @return Number
*/
leapDays: function (y) {
if (this.leapMonth(y)) {
return this.lunarInfo[y - 1900] & 0x10000 ? 30 : 29;
}
return 0;
},
/**
* 传回农历 y年闰哪个月 1-12 , 没闰传回 0
* @param y
* @return Number
*/
leapMonth: function (y) {
return this.lunarInfo[y - 1900] & 0xf;
},
/**
* 传回农历 y年m月的总天数
* @param y
* @param m
* @return Number
*/
monthDays: function (y, m) {
return this.lunarInfo[y - 1900] & (0x10000 >> m) ? 30 : 29;
},
/**
* 算出农历, 传入日期控件, 传回农历日期对象
* @param objDate
* @return Object
*/
solar2lunar: function (objDate) {
var i,
temp = 0;
var baseDate = new Date(1900, 0, 31);
var offset = Math.floor(
(objDate.getTime() - baseDate.getTime()) / 86400000,
);
var year = 1900;
for (i = 1900; i < 2050 && offset > 0; i++) {
temp = this.lYearDays(i);
if (offset < temp) break;
offset -= temp;
year = i;
}
// 如果循环结束时 offset 仍大于0 (超出范围),则年份最后一次增加未被撤销?
// 不break时 year=i。 如果没breakyear会一直增加。
// 修正:循环里 year = i 是对的。
// 但是 calendar.js 原版通常是 year++ 在 check 之后?
// 这里的逻辑:
// offset 是总天数。
// 减去1900年的天数如果 offset > 0说明在1900之后。
// year 变成 1901。
// 正确。
var leapMonth = this.leapMonth(year);
var isLeap = false;
var month = 1;
for (i = 1; i < 13; i++) {
// 闰月
temp = this.monthDays(year, i);
if (offset < temp) {
month = i;
break;
}
offset -= temp;
if (leapMonth > 0 && i == leapMonth) {
temp = this.leapDays(year);
if (offset < temp) {
isLeap = true;
month = i;
break;
}
offset -= temp;
}
}
var day = offset + 1;
// 格式化输出
const monthCn = this.toChinaMonth(month);
const dayCn = this.toChinaDay(day);
return {
lYear: year,
lMonth: month,
lDay: day,
isLeap: isLeap,
monthCn: monthCn,
dayCn: dayCn,
lunarDateStr: (isLeap ? "闰" : "") + monthCn + dayCn,
};
},
toChinaMonth: function (m) {
var s = "正二三四五六七八九十冬腊";
var str = s.substring(m - 1, m);
return str + "月";
},
toChinaDay: function (d) {
var s = "初十廿三";
var arr = ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十"];
var str = "";
switch (Math.floor(d / 10)) {
case 0:
str = "初" + arr[d - 1];
break;
case 1:
str = d == 10 ? "初十" : "十" + arr[d - 11];
break;
case 2:
str = d == 20 ? "二十" : "廿" + arr[d - 21];
break;
case 3:
str = d == 30 ? "三十" : "三" + arr[d - 31];
break;
}
return str;
},
};
export default calendar;