欢迎来到奇葩栖息地!欢迎加入Discord服务器:XfrfHCzfbW。请先至特殊:参数设置验证邮箱后再进行编辑。在特殊:参数设置挑选自己想要使用的小工具!不会编辑?请至这里学习Wikitext语法。
模块:Chinese calendar:修订间差异
来自奇葩栖息地
添加的内容 删除的内容
SkyEye FAST(讨论 | 贡献) 小 (//Edit via InPageEdit) |
SkyEye FAST(讨论 | 贡献) (//Edit via InPageEdit) |
||
(未显示同一用户的16个中间版本) | |||
第1行: | 第1行: | ||
local p = {} |
local p = {} |
||
-- 农历数据表 |
|||
local function extract(num, pos, len) |
|||
local lunarInfo = { |
|||
local shifted = math.floor(num / (2 ^ pos)) |
|||
0x04bd8, |
|||
local result = shifted % (2 ^ len) |
|||
0x04ae0, |
|||
0x0a570, |
|||
end |
|||
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, |
|||
0x0a5b0, |
|||
0x14573, |
|||
0x052b0, |
|||
0x0a9a8, |
|||
0x0e950, |
|||
0x06aa0, |
|||
0x0aea6, |
|||
0x0ab50, |
|||
0x04b60, |
|||
0x0aae4, |
|||
0x0a570, |
|||
0x05260, |
|||
0x0f263, |
|||
0x0d950, |
|||
0x05b57, |
|||
0x056a0, |
|||
0x096d0, |
|||
0x04dd5, |
|||
0x04ad0, |
|||
0x0a4d0, |
|||
0x0d4d4, |
|||
0x0d250, |
|||
0x0d558, |
|||
0x0b540, |
|||
0x0b6a0, |
|||
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, |
|||
0x04afb, |
|||
0x04ad0, |
|||
0x0a4d0, |
|||
0x1d0b6, |
|||
0x0d250, |
|||
0x0d520, |
|||
0x0dd45, |
|||
0x0b5a0, |
|||
0x056d0, |
|||
0x055b2, |
|||
0x049b0, |
|||
0x0a577, |
|||
0x0a4b0, |
|||
0x0aa50, |
|||
0x1b255, |
|||
0x06d20, |
|||
0x0ada0, |
|||
0x14b63, |
|||
0x09370, |
|||
0x049f8, |
|||
0x04970, |
|||
0x064b0, |
|||
0x168a6, |
|||
0x0ea50, |
|||
0x06b20, |
|||
0x1a6c4, |
|||
0x0aae0, |
|||
0x0a2e0, |
|||
0x0d2e3, |
|||
0x0c960, |
|||
0x0d557, |
|||
0x0d4a0, |
|||
0x0da50, |
|||
0x05d55, |
|||
0x056a0, |
|||
0x0a6d0, |
|||
0x055d4, |
|||
0x052d0, |
|||
0x0a9b8, |
|||
0x0a950, |
|||
0x0b4a0, |
|||
0x0b6a6, |
|||
0x0ad50, |
|||
0x055a0, |
|||
0x0aba4, |
|||
0x0a5b0, |
|||
0x052b0, |
|||
0x0b273, |
|||
0x06930, |
|||
0x07337, |
|||
0x06aa0, |
|||
0x0ad50, |
|||
0x14b55, |
|||
0x04b60, |
|||
0x0a570, |
|||
0x054e4, |
|||
0x0d160, |
|||
0x0e968, |
|||
0x0d520, |
|||
0x0daa0, |
|||
0x16aa6, |
|||
0x056d0, |
|||
0x04ae0, |
|||
0x0a9d4, |
|||
0x0a2d0, |
|||
0x0d150, |
|||
0x0f252, |
|||
0x0d520 |
|||
} |
|||
-- 天干 |
-- 天干 |
||
local |
local Gan = { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" } |
||
-- 地支 |
-- 地支 |
||
local |
local Zhi = { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" } |
||
-- 月份 |
-- 月份 |
||
local |
local nStr3 = { "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "腊" } |
||
-- 日期 |
-- 日期 |
||
local |
local nStr2 = { "初", "十", "廿", "卅" } |
||
local nStr1 = { "日", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十" } |
|||
'十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '二十', |
|||
'廿一', '廿二', '廿三', '廿四', '廿五', '廿六', '廿七', '廿八', '廿九', '三十' |
|||
} |
|||
-- 实现位运算函数 |
|||
-- 农历数据 (1900-2100) |
|||
local |
local function band(a, b) |
||
if not a or not b then |
|||
0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, |
|||
return 0 |
|||
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, |
|||
end |
|||
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 |
|||
} |
|||
-- Localize math.floor for performance |
|||
-- 节气数据(每个节气的日期偏移量) |
|||
local |
local floor = math.floor |
||
local result = 0 |
|||
6, 20, 4, 19, 6, 21, 5, 20, 6, 21, 6, 21, 7, 23, 8, 23, |
|||
local bitval = 1 |
|||
8, 23, 8, 24, 8, 23, 7, 22 |
|||
} |
|||
-- 处理负数或0的情况 |
|||
-- 节气名称 |
|||
if a <= 0 or b <= 0 then |
|||
local SOLAR_TERMS = { |
|||
return 0 |
|||
'小寒', '大寒', '立春', '雨水', '惊蛰', '春分', |
|||
end |
|||
'清明', '谷雨', '立夏', '小满', '芒种', '夏至', |
|||
'小暑', '大暑', '立秋', '处暑', '白露', '秋分', |
|||
'寒露', '霜降', '立冬', '小雪', '大雪', '冬至' |
|||
} |
|||
while a > 0 and b > 0 do |
|||
-- 检查日期是否合法 |
|||
if a % 2 == 1 and b % 2 == 1 then |
|||
local function isValidDate(year, month, day) |
|||
result = result + bitval |
|||
end |
|||
if (year % 4 == 0 and year % 100 ~= 0) or (year % 400 == 0) then |
|||
days[2] = 29 |
|||
bitval = bitval * 2 |
|||
a = floor(a/2) |
|||
b = floor(b/2) |
|||
end |
end |
||
return day <= days[month] |
|||
return result |
|||
end |
end |
||
local function rshift(a, b) |
|||
-- 计算指定公历日期是一年中的第几天 |
|||
if not a or not b then |
|||
local function getDayOfYear(year, month, day) |
|||
return 0 |
|||
local days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } |
|||
if (year % 4 == 0 and year % 100 ~= 0) or (year % 400 == 0) then |
|||
days[2] = 29 |
|||
end |
end |
||
if a <= 0 then |
|||
return 0 |
|||
for i = 1, month - 1 do |
|||
dayOfYear = dayOfYear + days[i] |
|||
end |
end |
||
return dayOfYear |
|||
end |
|||
if b < 0 then |
|||
-- 获取某年农历数据中的月份大小信息 |
|||
return a |
|||
local function getMonthSizes(lunarCode) |
|||
local monthSizes = {} |
|||
for i = 1, 12 do |
|||
monthSizes[i] = extract(lunarCode, 12 - i, 1) == 1 and 30 or 29 |
|||
end |
end |
||
return monthSizes |
|||
end |
|||
return math.floor(a / (2^b)) |
|||
-- 获取闰月信息 |
|||
local function getLeapMonth(lunarCode) |
|||
return extract(lunarCode, 12, 4) |
|||
end |
end |
||
-- 计算农历闰月月份 |
|||
-- 获取春节日期 |
|||
local function |
local function leapMonth(y) |
||
if y < 1900 or y > 2100 then |
|||
local month = extract(lunarCode, 16, 2) + 1 |
|||
return 0 |
|||
local day = extract(lunarCode, 18, 5) |
|||
end |
|||
return month, day |
|||
end |
|||
-- Lua table index starts from 1 |
|||
-- 计算节气的修正值,考虑年份差异带来的偏移 |
|||
local index = y - 1900 + 1 |
|||
local function getTermOffset(year, termIndex) |
|||
local y = year - 1900 |
|||
local d = 0 |
|||
-- Lua table index starts from 1 |
|||
-- 针对不同节气的偏移修正 |
|||
if |
if index <= 0 or index > #lunarInfo then |
||
return 0 |
|||
d = math.floor(y * 0.2422 + 3.87) - math.floor(y/4) |
|||
elseif termIndex <= 6 then -- 立春到春分 |
|||
d = math.floor(y * 0.2422 + 3.87) - math.floor(y/4) |
|||
elseif termIndex <= 12 then -- 清明到夏至 |
|||
d = math.floor(y * 0.2422 + 4.15) - math.floor(y/4) |
|||
elseif termIndex <= 18 then -- 小暑到秋分 |
|||
d = math.floor(y * 0.2422 + 4.15) - math.floor(y/4) |
|||
else -- 寒露到冬至 |
|||
d = math.floor(y * 0.2422 + 3.87) - math.floor(y/4) |
|||
end |
end |
||
return |
return band(lunarInfo[index], 0xf) |
||
end |
end |
||
-- 计算 |
-- 计算农历闰月天数 |
||
local function |
local function leapDays(y) |
||
if y < 1900 or y > 2100 then |
|||
return 0 |
|||
end |
|||
local m = leapMonth(y) |
|||
local idx = termIndex + i |
|||
local baseDay = SOLAR_TERMS_OFFSET[idx] |
|||
local offset = getTermOffset(year, idx) |
|||
local termDay = baseDay + offset |
|||
if m == 0 then |
|||
return 0 |
|||
termDay = termDay - 31 |
|||
end |
|||
-- Lua table index starts from 1 |
|||
if day == termDay then |
|||
if band(lunarInfo[y - 1900 + 1], 0x10000) ~= 0 then |
|||
return SOLAR_TERMS[idx] |
|||
return 30 |
|||
end |
end |
||
return nil |
|||
return 29 |
|||
end |
end |
||
-- 计算农历 |
-- 计算农历年天数 |
||
local function |
local function lYearDays(y) |
||
if y < 1900 or y > 2100 then |
|||
-- 获取春节日期 |
|||
return 0 |
|||
local sfMonth, sfDay = getSpringFestival(yearCode) |
|||
end |
|||
local sum = 348 |
|||
-- 计算目标日期和春节的天数差 |
|||
local |
local i = 0x8000 |
||
-- Lua table index starts from 1 |
|||
local springFestivalDayOfYear = getDayOfYear(year, sfMonth, sfDay) |
|||
local |
local idx = y - 1900 + 1 |
||
-- Lua table index starts from 1 |
|||
-- 如果在春节前,则属于上一个农历年 |
|||
if |
if idx <= 0 or idx > #lunarInfo then |
||
return 0 |
|||
if year > 1900 then |
|||
local prevYearCode = LUNAR_INFO[year - 1900] |
|||
local prevMonthSizes = getMonthSizes(prevYearCode) |
|||
local totalDays = dayDiff + prevMonthSizes[12] |
|||
return 12, totalDays + 1, false, year - 1 |
|||
else |
|||
return 12, 30 + dayDiff, false, year - 1 |
|||
end |
|||
end |
end |
||
while i > 0x8 do |
|||
-- 获取当年农历月份大小 |
|||
if band(lunarInfo[idx], i) ~= 0 then |
|||
local monthSizes = getMonthSizes(yearCode) |
|||
sum = sum + 1 |
|||
local leapMonth = getLeapMonth(yearCode) |
|||
end |
|||
i = rshift(i, 1) |
|||
-- 计算农历月份和日期 |
|||
end |
|||
local days = dayDiff |
|||
local lunarMonth = 1 |
|||
local isLeapMonth = false |
|||
return sum + leapDays(y) |
|||
while days >= monthSizes[lunarMonth] do |
|||
end |
|||
days = days - monthSizes[lunarMonth] |
|||
-- 计算农历月份天数 |
|||
if lunarMonth == leapMonth then |
|||
local function monthDays(y, m) |
|||
if not isLeapMonth then |
|||
if y < 1900 or y > 2100 then |
|||
return 0 |
|||
if days >= monthSizes[lunarMonth] then |
|||
end |
|||
days = days - monthSizes[lunarMonth] |
|||
lunarMonth = lunarMonth + 1 |
|||
end |
|||
else |
|||
lunarMonth = lunarMonth + 1 |
|||
isLeapMonth = false |
|||
end |
|||
else |
|||
lunarMonth = lunarMonth + 1 |
|||
end |
|||
if m > 12 or m < 1 then |
|||
return 0 |
|||
end |
|||
-- Lua table index starts from 1 |
|||
if band(lunarInfo[y - 1900 + 1], rshift(0x10000, m)) ~= 0 then |
|||
return 30 |
|||
end |
end |
||
return |
return 29 |
||
end |
end |
||
-- |
-- 主要的转换函数 |
||
function p.toLunar(frame) |
function p.toLunar(frame) |
||
-- 解析输入日期 |
|||
local date = frame.args[1] |
|||
local |
local date = frame.args[1] or frame:getParent().args.date |
||
if |
if not date then |
||
return "日期参数错误" |
|||
showSolarTerm = true |
|||
else |
|||
showSolarTerm = (showSolarTerm == true or showSolarTerm == "true" or showSolarTerm == "1") |
|||
end |
end |
||
local y, m, d = date:match("^(%d%d%d%d)-(%d%d?)-(%d%d?)$") |
|||
-- 输入格式验证 |
|||
if not date:match('^%d%d%d%d%-%d%d%-%d%d$') then |
|||
if not y or not m or not d then |
|||
return '错误:日期格式无效,请使用YYYY-MM-DD格式' |
|||
return "日期格式错误" |
|||
end |
end |
||
y, m, d = tonumber(y), tonumber(m), tonumber(d) |
|||
local month = tonumber(date:sub(6, 7)) |
|||
local day = tonumber(date:sub(9, 10)) |
|||
-- |
-- 验证日期范围 |
||
if |
if y < 1900 or y > 2100 then |
||
return |
return "年份超出范围(1900-2100)" |
||
end |
end |
||
if month < 1 or month > 12 then |
|||
if m < 1 or m > 12 then |
|||
return "月份错误" |
|||
end |
end |
||
if not isValidDate(year, month, day) then |
|||
if d < 1 or d > 31 then |
|||
return "日期错误" |
|||
end |
end |
||
-- |
-- 计算距离1900年1月31日的天数 |
||
local |
local baseDate = os.time({ year = 1900, month = 1, day = 31 }) |
||
local |
local targetDate = os.time({ year = y, month = m, day = d }) |
||
local |
local offset = math.floor((targetDate - baseDate) / (24 * 60 * 60)) |
||
local branchIndex = (lunarYear - 4) % 12 |
|||
-- 计算农历年 |
|||
local result = HEAVENLY_STEMS[stemIndex + 1] .. EARTHLY_BRANCHES[branchIndex + 1] .. '年' |
|||
local ly = 1900 |
|||
local temp = 0 |
|||
while ly < 2101 and offset > 0 do |
|||
temp = lYearDays(ly) |
|||
offset = offset - temp |
|||
ly = ly + 1 |
|||
end |
end |
||
result = result .. LUNAR_MONTHS[lunarMonth] .. '月' .. LUNAR_DAYS[lunarDay] |
|||
if offset < 0 then |
|||
offset = offset + temp |
|||
if showSolarTerm then |
|||
ly = ly - 1 |
|||
end |
|||
if solarTerm then |
|||
result = result .. '(' .. solarTerm .. ')' |
|||
-- 计算农历月日 |
|||
local lm = 1 |
|||
local ld = 1 |
|||
local isLeap = false |
|||
local leap = leapMonth(ly) |
|||
-- 计算月 |
|||
while offset > 0 and lm < 13 do |
|||
if leap > 0 and lm == leap + 1 and not isLeap then |
|||
lm = lm - 1 |
|||
isLeap = true |
|||
temp = leapDays(ly) |
|||
else |
|||
temp = monthDays(ly, lm) |
|||
end |
end |
||
offset = offset - temp |
|||
if isLeap and lm == leap + 1 then |
|||
isLeap = false |
|||
end |
|||
lm = lm + 1 |
|||
end |
end |
||
-- 计算日 |
|||
if offset == 0 and leap > 0 and lm == leap + 1 then |
|||
if isLeap then |
|||
isLeap = false |
|||
else |
|||
isLeap = true |
|||
lm = lm - 1 |
|||
end |
|||
end |
|||
if offset < 0 then |
|||
offset = offset + temp |
|||
lm = lm - 1 |
|||
end |
|||
ld = offset + 1 |
|||
-- 格式化输出 |
|||
local gzYear = Gan[((ly - 4) % 10) + 1] .. Zhi[((ly - 4) % 12) + 1] |
|||
local lMonth = nStr3[lm] |
|||
local lDay |
|||
if ld == 10 then |
|||
lDay = "初十" |
|||
elseif ld == 20 then |
|||
lDay = "二十" |
|||
elseif ld == 30 then |
|||
lDay = "三十" |
|||
else |
|||
lDay = nStr2[math.floor(ld / 10) + 1] .. nStr1[ld % 10 + 1] |
|||
end |
|||
return gzYear .. "年" .. lMonth .. "月" .. lDay |
|||
end |
end |
||
2025年1月9日 (四) 11:55的最新版本
local p = {}
-- 农历数据表
local 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,
0x0a5b0,
0x14573,
0x052b0,
0x0a9a8,
0x0e950,
0x06aa0,
0x0aea6,
0x0ab50,
0x04b60,
0x0aae4,
0x0a570,
0x05260,
0x0f263,
0x0d950,
0x05b57,
0x056a0,
0x096d0,
0x04dd5,
0x04ad0,
0x0a4d0,
0x0d4d4,
0x0d250,
0x0d558,
0x0b540,
0x0b6a0,
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,
0x04afb,
0x04ad0,
0x0a4d0,
0x1d0b6,
0x0d250,
0x0d520,
0x0dd45,
0x0b5a0,
0x056d0,
0x055b2,
0x049b0,
0x0a577,
0x0a4b0,
0x0aa50,
0x1b255,
0x06d20,
0x0ada0,
0x14b63,
0x09370,
0x049f8,
0x04970,
0x064b0,
0x168a6,
0x0ea50,
0x06b20,
0x1a6c4,
0x0aae0,
0x0a2e0,
0x0d2e3,
0x0c960,
0x0d557,
0x0d4a0,
0x0da50,
0x05d55,
0x056a0,
0x0a6d0,
0x055d4,
0x052d0,
0x0a9b8,
0x0a950,
0x0b4a0,
0x0b6a6,
0x0ad50,
0x055a0,
0x0aba4,
0x0a5b0,
0x052b0,
0x0b273,
0x06930,
0x07337,
0x06aa0,
0x0ad50,
0x14b55,
0x04b60,
0x0a570,
0x054e4,
0x0d160,
0x0e968,
0x0d520,
0x0daa0,
0x16aa6,
0x056d0,
0x04ae0,
0x0a9d4,
0x0a2d0,
0x0d150,
0x0f252,
0x0d520
}
-- 天干
local Gan = { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" }
-- 地支
local Zhi = { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" }
-- 月份
local nStr3 = { "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "腊" }
-- 日期
local nStr2 = { "初", "十", "廿", "卅" }
local nStr1 = { "日", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十" }
-- 实现位运算函数
local function band(a, b)
if not a or not b then
return 0
end
-- Localize math.floor for performance
local floor = math.floor
local result = 0
local bitval = 1
-- 处理负数或0的情况
if a <= 0 or b <= 0 then
return 0
end
while a > 0 and b > 0 do
if a % 2 == 1 and b % 2 == 1 then
result = result + bitval
end
bitval = bitval * 2
a = floor(a/2)
b = floor(b/2)
end
return result
end
local function rshift(a, b)
if not a or not b then
return 0
end
if a <= 0 then
return 0
end
if b < 0 then
return a
end
return math.floor(a / (2^b))
end
-- 计算农历闰月月份
local function leapMonth(y)
if y < 1900 or y > 2100 then
return 0
end
-- Lua table index starts from 1
local index = y - 1900 + 1
-- Lua table index starts from 1
if index <= 0 or index > #lunarInfo then
return 0
end
return band(lunarInfo[index], 0xf)
end
-- 计算农历闰月天数
local function leapDays(y)
if y < 1900 or y > 2100 then
return 0
end
local m = leapMonth(y)
if m == 0 then
return 0
end
-- Lua table index starts from 1
if band(lunarInfo[y - 1900 + 1], 0x10000) ~= 0 then
return 30
end
return 29
end
-- 计算农历年天数
local function lYearDays(y)
if y < 1900 or y > 2100 then
return 0
end
local sum = 348
local i = 0x8000
-- Lua table index starts from 1
local idx = y - 1900 + 1
-- Lua table index starts from 1
if idx <= 0 or idx > #lunarInfo then
return 0
end
while i > 0x8 do
if band(lunarInfo[idx], i) ~= 0 then
sum = sum + 1
end
i = rshift(i, 1)
end
return sum + leapDays(y)
end
-- 计算农历月份天数
local function monthDays(y, m)
if y < 1900 or y > 2100 then
return 0
end
if m > 12 or m < 1 then
return 0
end
-- Lua table index starts from 1
if band(lunarInfo[y - 1900 + 1], rshift(0x10000, m)) ~= 0 then
return 30
end
return 29
end
-- 主要的转换函数
function p.toLunar(frame)
-- 解析输入日期
local date = frame.args[1] or frame:getParent().args.date
if not date then
return "日期参数错误"
end
local y, m, d = date:match("^(%d%d%d%d)-(%d%d?)-(%d%d?)$")
if not y or not m or not d then
return "日期格式错误"
end
y, m, d = tonumber(y), tonumber(m), tonumber(d)
-- 验证日期范围
if y < 1900 or y > 2100 then
return "年份超出范围(1900-2100)"
end
if m < 1 or m > 12 then
return "月份错误"
end
if d < 1 or d > 31 then
return "日期错误"
end
-- 计算距离1900年1月31日的天数
local baseDate = os.time({ year = 1900, month = 1, day = 31 })
local targetDate = os.time({ year = y, month = m, day = d })
local offset = math.floor((targetDate - baseDate) / (24 * 60 * 60))
-- 计算农历年
local ly = 1900
local temp = 0
while ly < 2101 and offset > 0 do
temp = lYearDays(ly)
offset = offset - temp
ly = ly + 1
end
if offset < 0 then
offset = offset + temp
ly = ly - 1
end
-- 计算农历月日
local lm = 1
local ld = 1
local isLeap = false
local leap = leapMonth(ly)
-- 计算月
while offset > 0 and lm < 13 do
if leap > 0 and lm == leap + 1 and not isLeap then
lm = lm - 1
isLeap = true
temp = leapDays(ly)
else
temp = monthDays(ly, lm)
end
offset = offset - temp
if isLeap and lm == leap + 1 then
isLeap = false
end
lm = lm + 1
end
-- 计算日
if offset == 0 and leap > 0 and lm == leap + 1 then
if isLeap then
isLeap = false
else
isLeap = true
lm = lm - 1
end
end
if offset < 0 then
offset = offset + temp
lm = lm - 1
end
ld = offset + 1
-- 格式化输出
local gzYear = Gan[((ly - 4) % 10) + 1] .. Zhi[((ly - 4) % 12) + 1]
local lMonth = nStr3[lm]
local lDay
if ld == 10 then
lDay = "初十"
elseif ld == 20 then
lDay = "二十"
elseif ld == 30 then
lDay = "三十"
else
lDay = nStr2[math.floor(ld / 10) + 1] .. nStr1[ld % 10 + 1]
end
return gzYear .. "年" .. lMonth .. "月" .. lDay
end
return p