欢迎来到奇葩栖息地!欢迎加入Discord服务器:XfrfHCzfbW请先至特殊:参数设置验证邮箱后再进行编辑。特殊:参数设置挑选自己想要使用的小工具!不会编辑?请至这里学习Wikitext语法。

模块:Chinese calendar:修订间差异

来自奇葩栖息地
添加的内容 删除的内容
(//Edit via InPageEdit)
(//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)
return result
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 HEAVENLY_STEMS = { '', '', '', '', '', '', '', '', '', '' }
local Gan = { "", "", "", "", "", "", "", "", "", "" }

-- 地支
-- 地支
local EARTHLY_BRANCHES = { '', '', '', '', '', '', '', '', '', '', '', '' }
local Zhi = { "", "", "", "", "", "", "", "", "", "", "", "" }

-- 月份
-- 月份
local LUNAR_MONTHS = { '', '', '', '', '', '', '', '', '', '', '', '' }
local nStr3 = { "", "", "", "", "", "", "", "", "", "", "", "" }

-- 日期
-- 日期
local LUNAR_DAYS = {
local nStr2 = { "初", "十", "廿", "卅" }
'初', '初', '初', '初', '初', '初', '初', '初', '初', '初',
local nStr1 = { "日", "", "", "", "", "", "", "", "", "", "" }
'十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '二十',
'廿一', '廿二', '廿三', '廿四', '廿五', '廿六', '廿七', '廿八', '廿九', '三十'
}


-- 实现位运算函数
-- 农历数据 (1900-2100)
local LUNAR_INFO = {
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 SOLAR_TERMS_OFFSET = {
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)
local days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
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


local dayOfYear = day
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 getSpringFestival(lunarCode)
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 termIndex <= 2 then -- 小寒、大寒
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 d
return band(lunarInfo[index], 0xf)
end
end


-- 计算节气
-- 计算农历闰月天数
local function getSolarTerm(year, month, day)
local function leapDays(y)
local termIndex = (month - 1) * 2 + 1
if y < 1900 or y > 2100 then
return 0
end


for i = 0, 1 do
local m = leapMonth(y)
local idx = termIndex + i
local baseDay = SOLAR_TERMS_OFFSET[idx]
local offset = getTermOffset(year, idx)
local termDay = baseDay + offset


if termDay > 31 then
if m == 0 then
return 0
termDay = termDay - 31
end
end


-- Lua table index starts from 1
if day == termDay then
if band(lunarInfo[y - 1900 + 1], 0x10000) ~= 0 then
return SOLAR_TERMS[idx]
end
return 30
end
end

return nil
return 29
end
end


-- 计算农历日期
-- 计算农历年天数
local function calculateLunarDate(yearCode, year, month, day)
local function lYearDays(y)
if y < 1900 or y > 2100 then
-- 获取春节日期
return 0
local sfMonth, sfDay = getSpringFestival(yearCode)
end


local sum = 348
-- 计算目标日期和春节的天数差
local targetDayOfYear = getDayOfYear(year, month, day)
local i = 0x8000
-- Lua table index starts from 1
local springFestivalDayOfYear = getDayOfYear(year, sfMonth, sfDay)
local dayDiff = targetDayOfYear - springFestivalDayOfYear
local idx = y - 1900 + 1


-- Lua table index starts from 1
-- 如果在春节前,则属于上一个农历年
if dayDiff < 0 then
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
isLeapMonth = true
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 lunarMonth > 12 then
if m > 12 or m < 1 then
return 1, days + 1, false, year + 1
return 0
end
end

-- Lua table index starts from 1
if band(lunarInfo[y - 1900 + 1], rshift(0x10000, m)) ~= 0 then
return 30
end
end


return lunarMonth, days + 1, isLeapMonth, year
return 29
end
end


-- 将公历日期转换为农历日期
-- 主要的转换函数
function p.toLunar(frame)
function p.toLunar(frame)
-- 解析输入日期
local date = frame.args[1]
local showSolarTerm = frame.args.showSolarTerm
local date = frame.args[1] or frame:getParent().args.date


if showSolarTerm == nil then
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


local year = tonumber(date:sub(1, 4))
y, m, d = tonumber(y), tonumber(m), tonumber(d)
local month = tonumber(date:sub(6, 7))
local day = tonumber(date:sub(9, 10))


-- 输入日期范围验证
-- 验证日期范围
if year < 1900 or year > 2100 then
if y < 1900 or y > 2100 then
return '错误:年份超出范围(1900-2100)'
return "年份超出范围(1900-2100)"
end
end

if month < 1 or month > 12 then
return '错误:月份无效'
if m < 1 or m > 12 then
return "月份错误"
end
end

if not isValidDate(year, month, day) then
return '错误:日期无效'
if d < 1 or d > 31 then
return "日期错误"
end
end


-- 输出
-- 计算距离1900年1月31的天数
local yearCode = LUNAR_INFO[year - 1900 + 1]
local baseDate = os.time({ year = 1900, month = 1, day = 31 })
local lunarMonth, lunarDay, isLeapMonth, lunarYear = calculateLunarDate(yearCode, year, month, day)
local targetDate = os.time({ year = y, month = m, day = d })
local stemIndex = (lunarYear - 4) % 10
local offset = math.floor((targetDate - baseDate) / (24 * 60 * 60))

local branchIndex = (lunarYear - 4) % 12
-- 计算农历年
local result = HEAVENLY_STEMS[stemIndex + 1] .. EARTHLY_BRANCHES[branchIndex + 1] .. '年'
if isLeapMonth then
local ly = 1900
result = result .. '闰'
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
local solarTerm = getSolarTerm(year, month, day)
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


return result
-- 计算日
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