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

模块:Chinese calendar:修订间差异

来自奇葩栖息地
添加的内容 删除的内容
(//Edit via InPageEdit)
标签手工回退
无编辑摘要
标签已被回退
第1行: 第1行:
local p = {}
local p = {}


-- 位运算模拟函数
-- 农历数据表
local lunarInfo = {
local function rshift(a, b)
if b < 0 then return lshift(a, -b) end
0x04bd8,
return math.floor(a / (2 ^ b))
0x04ae0,
end
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 function lshift(a, b)
-- 天干
if b < 0 then return rshift(a, -b) end
local Gan = { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" }
return a * (2 ^ b)

end
-- 地支
local Zhi = { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" }

-- 月份
local nStr3 = { "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "腊" }

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


-- 实现位运算函数
local function band(a, b)
local function band(a, b)
if not a or not b then return 0 end
local result = 0
local result = 0
local bitval = 1
local bitval = 1

-- 处理负数或0的情况
if a <= 0 or b <= 0 then return 0 end

while a > 0 and b > 0 do
while a > 0 and b > 0 do
if a % 2 == 1 and b % 2 == 1 then
if a % 2 == 1 and b % 2 == 1 then
第233行: 第20行:
end
end
bitval = bitval * 2
bitval = bitval * 2
a = math.floor(a/2)
a = math.floor(a / 2)
b = math.floor(b/2)
b = math.floor(b / 2)
end
end
return result
return result
end
end


-- 农历数据表
local function rshift(a, b)
local calendar = {
if not a or not b then return 0 end
lunarInfo = { 0x04bd8,
if a <= 0 then return 0 end
if b < 0 then return a end
0x04ae0,
0x0a570,
return math.floor(a / (2^b))
0x054d5,
end
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 },


Gan = { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" },
-- 计算农历闰月月份
Zhi = { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" },
local function leapMonth(y)
Animals = { "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪" },
if y < 1900 or y > 2100 then return 0 end
nStr1 = { "日", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十" },
local index = y - 1900
nStr2 = { "初", "十", "廿", "卅" },
if index < 0 or index >= #lunarInfo then return 0 end
nStr3 = { "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "腊" }
return band(lunarInfo[index], 0xf)
}
end


-- 计算农历闰月天
-- 核心转换函
local function leapDays(y)
function calendar.solar2lunar(y, m, d)
-- 边界检查
if y < 1900 or y > 2100 then return 0 end
if y < 1900 or y > 2100 then return nil end
local m = leapMonth(y)
if m == 0 then return 0 end
if y == 1900 and m == 1 and d < 31 then return nil end
if band(lunarInfo[y - 1900], 0x10000) ~= 0 then
return 30
end
return 29
end


-- 计算农历年天数
-- 计算距离19001月31日的总天数
local objDate = os.time({ year = y, month = m, day = d })
local function lYearDays(y)
if y < 1900 or y > 2100 then return 0 end
local sum = 348
local i = 0x8000
local idx = y - 1900
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
if band(lunarInfo[y - 1900], 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 baseDate = os.time({ year = 1900, month = 1, day = 31 })
local targetDate = os.time({ year = y, month = m, day = d })
local offset = math.floor((objDate - baseDate) / (24 * 60 * 60))

local offset = math.floor((targetDate - baseDate) / (24 * 60 * 60))
local i, temp, leap = 1900, 0, 0


-- 计算农历年
-- 计算农历年
while i < 2101 and offset > 0 do
local ly = 1900
local temp = 0
temp = calendar.lYearDays(i)
while ly < 2101 and offset > 0 do
temp = lYearDays(ly)
offset = offset - temp
offset = offset - temp
ly = ly + 1
i = i + 1
end
end

if offset < 0 then
if offset < 0 then
offset = offset + temp
offset = offset + temp
ly = ly - 1
i = i - 1
end
end


local year = i
-- 计算农历月日
leap = calendar.leapMonth(year)
local lm = 1
local ld = 1
local isLeap = false
local isLeap = false
local leap = leapMonth(ly)


-- 计算月
-- 计算月
i = 1
while offset > 0 and lm < 13 do
while i < 13 and offset > 0 do
if leap > 0 and lm == leap + 1 and not isLeap then
lm = lm - 1
if leap > 0 and i == (leap + 1) and isLeap == false then
i = i - 1
isLeap = true
isLeap = true
temp = leapDays(ly)
temp = calendar.leapDays(year)
else
else
temp = monthDays(ly, lm)
temp = calendar.monthDays(year, i)
end
end

if isLeap == true and i == (leap + 1) then
isLeap = false
end

offset = offset - temp
offset = offset - temp
if isLeap and lm == leap + 1 then isLeap = false end
i = i + 1
lm = lm + 1
end
end


if offset == 0 and leap > 0 and i == leap + 1 then
-- 计算日
if offset == 0 and leap > 0 and lm == leap + 1 then
if isLeap then
if isLeap then
isLeap = false
isLeap = false
else
else
isLeap = true
isLeap = true
lm = lm - 1
i = i - 1
end
end
end
end

if offset < 0 then
if offset < 0 then
offset = offset + temp
offset = offset + temp
lm = lm - 1
i = i - 1
end
end
ld = offset + 1


local month = i
-- 格式化输出
local gzYear = Gan[((ly - 4) % 10) + 1] .. Zhi[((ly - 4) % 12) + 1]
local day = offset + 1

local lMonth = nStr3[lm]
local lDay
return {
if ld == 10 then
lYear = year,
lDay = "初十"
lMonth = month,
elseif ld == 20 then
lDay = day,
lDay = "二十"
isLeap = isLeap
}
elseif ld == 30 then
end
lDay = "三十"

-- 辅助函数
function calendar.lYearDays(y)
local sum = 348
for i = 0x8000, 0x8, -1 do
i = rshift(i, 1)
if band(calendar.lunarInfo[y - 1900], i) ~= 0 then
sum = sum + 1
end
end
return sum + calendar.leapDays(y)
end

function calendar.leapMonth(y)
return band(calendar.lunarInfo[y - 1900], 0xf)
end

function calendar.leapDays(y)
if calendar.leapMonth(y) ~= 0 then
return band(calendar.lunarInfo[y - 1900], 0x10000) ~= 0 and 30 or 29
end
return 0
end

-- MediaWiki接口
function p.toLunar(frame)
local date = frame.args[1] or frame.args.date
if not date then
return '参数错误'
end

local y, m, d = date:match("(%d+)%-(%d+)%-(%d+)")
y, m, d = tonumber(y), tonumber(m), tonumber(d)

if not (y and m and d) then
return '日期格式错误'
end

local lunar = calendar.solar2lunar(y, m, d)
if not lunar then
return '超出计算范围(1900-2100)'
end

local result = calendar.Gan[(lunar.lYear - 4) % 10 + 1] ..
calendar.Zhi[(lunar.lYear - 4) % 12 + 1] .. '年'

if lunar.isLeap then
result = result .. '闰'
end

result = result .. calendar.nStr3[lunar.lMonth] .. '月'

if lunar.lDay < 11 then
result = result .. calendar.nStr2[1] .. calendar.nStr1[lunar.lDay]
elseif lunar.lDay < 20 then
result = result .. calendar.nStr2[2] .. calendar.nStr1[lunar.lDay - 10]
elseif lunar.lDay == 20 then
result = result .. calendar.nStr2[2] .. calendar.nStr2[2]
elseif lunar.lDay < 30 then
result = result .. calendar.nStr2[3] .. calendar.nStr1[lunar.lDay - 20]
else
else
lDay = nStr2[math.floor(ld / 10) + 1] .. nStr1[ld % 10 + 1]
result = result .. calendar.nStr2[4] .. calendar.nStr1[lunar.lDay - 30]
end
end


return gzYear .. "年" .. lMonth .. "月" .. lDay
return result
end
end



2025年1月7日 (二) 16:09的版本

[创建 | 历史 | 清除缓存]文档页面
此模块没有文档页面。如果你知道此模块的使用方法,请帮助为其创建文档页面。
local p = {}

-- 位运算模拟函数
local function rshift(a, b)
    if b < 0 then return lshift(a, -b) end
    return math.floor(a / (2 ^ b))
end

local function lshift(a, b)
    if b < 0 then return rshift(a, -b) end
    return a * (2 ^ b)
end

local function band(a, b)
    local result = 0
    local bitval = 1
    while a > 0 and b > 0 do
        if a % 2 == 1 and b % 2 == 1 then
            result = result + bitval
        end
        bitval = bitval * 2
        a = math.floor(a / 2)
        b = math.floor(b / 2)
    end
    return result
end

-- 农历数据表
local calendar = {
    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 },

    Gan = { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" },
    Zhi = { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" },
    Animals = { "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪" },
    nStr1 = { "日", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十" },
    nStr2 = { "初", "十", "廿", "卅" },
    nStr3 = { "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "腊" }
}

-- 核心转换函数
function calendar.solar2lunar(y, m, d)
    -- 边界检查
    if y < 1900 or y > 2100 then return nil end
    if y == 1900 and m == 1 and d < 31 then return nil end

    -- 计算距离1900年1月31日的总天数
    local objDate = os.time({ year = y, month = m, day = d })
    local baseDate = os.time({ year = 1900, month = 1, day = 31 })
    local offset = math.floor((objDate - baseDate) / (24 * 60 * 60))

    local i, temp, leap = 1900, 0, 0

    -- 计算农历年
    while i < 2101 and offset > 0 do
        temp = calendar.lYearDays(i)
        offset = offset - temp
        i = i + 1
    end

    if offset < 0 then
        offset = offset + temp
        i = i - 1
    end

    local year = i
    leap = calendar.leapMonth(year)
    local isLeap = false

    -- 计算月
    i = 1
    while i < 13 and offset > 0 do
        if leap > 0 and i == (leap + 1) and isLeap == false then
            i = i - 1
            isLeap = true
            temp = calendar.leapDays(year)
        else
            temp = calendar.monthDays(year, i)
        end

        if isLeap == true and i == (leap + 1) then
            isLeap = false
        end

        offset = offset - temp
        i = i + 1
    end

    if offset == 0 and leap > 0 and i == leap + 1 then
        if isLeap then
            isLeap = false
        else
            isLeap = true
            i = i - 1
        end
    end

    if offset < 0 then
        offset = offset + temp
        i = i - 1
    end

    local month = i
    local day = offset + 1

    return {
        lYear = year,
        lMonth = month,
        lDay = day,
        isLeap = isLeap
    }
end

-- 辅助函数
function calendar.lYearDays(y)
    local sum = 348
    for i = 0x8000, 0x8, -1 do
        i = rshift(i, 1)
        if band(calendar.lunarInfo[y - 1900], i) ~= 0 then
            sum = sum + 1
        end
    end
    return sum + calendar.leapDays(y)
end

function calendar.leapMonth(y)
    return band(calendar.lunarInfo[y - 1900], 0xf)
end

function calendar.leapDays(y)
    if calendar.leapMonth(y) ~= 0 then
        return band(calendar.lunarInfo[y - 1900], 0x10000) ~= 0 and 30 or 29
    end
    return 0
end

-- MediaWiki接口
function p.toLunar(frame)
    local date = frame.args[1] or frame.args.date
    if not date then
        return '参数错误'
    end

    local y, m, d = date:match("(%d+)%-(%d+)%-(%d+)")
    y, m, d = tonumber(y), tonumber(m), tonumber(d)

    if not (y and m and d) then
        return '日期格式错误'
    end

    local lunar = calendar.solar2lunar(y, m, d)
    if not lunar then
        return '超出计算范围(1900-2100)'
    end

    local result = calendar.Gan[(lunar.lYear - 4) % 10 + 1] ..
        calendar.Zhi[(lunar.lYear - 4) % 12 + 1] .. '年'

    if lunar.isLeap then
        result = result .. '闰'
    end

    result = result .. calendar.nStr3[lunar.lMonth] .. '月'

    if lunar.lDay < 11 then
        result = result .. calendar.nStr2[1] .. calendar.nStr1[lunar.lDay]
    elseif lunar.lDay < 20 then
        result = result .. calendar.nStr2[2] .. calendar.nStr1[lunar.lDay - 10]
    elseif lunar.lDay == 20 then
        result = result .. calendar.nStr2[2] .. calendar.nStr2[2]
    elseif lunar.lDay < 30 then
        result = result .. calendar.nStr2[3] .. calendar.nStr1[lunar.lDay - 20]
    else
        result = result .. calendar.nStr2[4] .. calendar.nStr1[lunar.lDay - 30]
    end

    return result
end

return p