Module:Calendar
(Redirected from Module:Calender)
Documentation for this module may be created at Module:Calendar/doc
local p = {}
local LAUNCH = { year = 2026, month = 7, day = 28 }
local ERA = "Era Nova"
local PERIODS = {
"Early January",
"January--February",
"February--March",
"March--April",
"April--May",
"May--June",
"June",
"June--July",
"July--August",
"August--September",
"September--October",
"October--November",
"November--December",
"Late December",
}
local DAYS_PER_YEAR = #PERIODS
p.periods = PERIODS
p.daysPerYear = DAYS_PER_YEAR
local function trim(s)
return (tostring(s or ""):match("^%s*(.-)%s*$"))
end
local function daysFromCivil(y, m, d)
if m <= 2 then y = y - 1 end
local era = math.floor(y / 400)
local yoe = y - era * 400
local mp = (m + 9) % 12
local doy = math.floor((153 * mp + 2) / 5) + d - 1
local doe = yoe * 365 + math.floor(yoe / 4) - math.floor(yoe / 100) + doy
return era * 146097 + doe - 719468
end
local function civilFromDays(z)
z = z + 719468
local era = math.floor(z / 146097)
local doe = z - era * 146097
local yoe = math.floor(
(doe - math.floor(doe / 1460) + math.floor(doe / 36524) - math.floor(doe / 146096)) / 365
)
local y = yoe + era * 400
local doy = doe - (365 * yoe + math.floor(yoe / 4) - math.floor(yoe / 100))
local mp = math.floor((5 * doy + 2) / 153)
local d = doy - math.floor((153 * mp + 2) / 5) + 1
local m = mp + 3
if m > 12 then m = m - 12 end
if m <= 2 then y = y + 1 end
return y, m, d
end
local LAUNCH_DAYNUM = daysFromCivil(LAUNCH.year, LAUNCH.month, LAUNCH.day)
local LAUNCH_ISO = string.format("%04d-%02d-%02d", LAUNCH.year, LAUNCH.month, LAUNCH.day)
function p.pretty(period)
return (tostring(period or ""):gsub("%-%-", "–"))
end
function p.parse(text)
text = trim(text)
if text == "" then
return nil, "no date was given"
end
local y, m, d = text:match("^(%d%d%d%d)[%-/%.](%d%d?)[%-/%.](%d%d?)%f[%D]")
if not y then
return nil, "“" .. text .. "” is not in YYYY-MM-DD format"
end
y, m, d = tonumber(y), tonumber(m), tonumber(d)
local z = daysFromCivil(y, m, d)
local ry, rm, rd = civilFromDays(z)
if m < 1 or m > 12 or d < 1 or ry ~= y or rm ~= m or rd ~= d then
return nil, "“" .. text .. "” is not a real calendar date"
end
local offset = z - LAUNCH_DAYNUM
if offset < 0 then
return nil, "“" .. text .. "” is before the server launched (" .. LAUNCH_ISO .. ")"
end
return string.format("%04d-%02d-%02d", y, m, d), offset
end
function p.info(text)
local iso, offset = p.parse(text)
if not iso then
return nil, offset
end
local day = offset % DAYS_PER_YEAR + 1
return {
iso = iso,
year = math.floor(offset / DAYS_PER_YEAR) + 1,
day = day,
period = PERIODS[day],
}
end
function p.realDate(year, day)
local y, m, d = civilFromDays(LAUNCH_DAYNUM + (year - 1) * DAYS_PER_YEAR + (day - 1))
return string.format("%04d-%02d-%02d", y, m, d)
end
function p.iso(frame)
local i = p.info(frame.args[1])
return i and i.iso or ""
end
function p.yearNum(frame)
local i = p.info(frame.args[1])
return i and tostring(i.year) or ""
end
function p.dayNum(frame)
local i = p.info(frame.args[1])
return i and tostring(i.day) or ""
end
function p.period(frame)
local i = p.info(frame.args[1])
return i and i.period or ""
end
function p.label(frame)
local i = p.info(frame.args[1])
return i and p.pretty(i.period) or ""
end
function p.yearName(frame)
local i = p.info(frame.args[1])
return i and (ERA .. ", Year " .. i.year) or ""
end
function p.prettify(frame)
return p.pretty(frame.args[1])
end
function p.check(frame)
local i, message = p.info(frame.args[1])
if i then
return ""
end
return '<div class="error" style="margin: 0 0 1em;"><strong>RealDate problem:</strong> '
.. message
.. '. Use YYYY-MM-DD, for example 2026-09-15.</div>[[Category:Pages with a date problem]]'
end
return p