Module:Calendar
Documentation for this module may be created at Module:Calendar/doc
require('strict')
local p = {}
local root = {}
local function addRow(row)
table.insert(root, row)
end
local function isLeapYear(year)
return year % 4 == 0 and (year % 100 ~= 0 or year % 400 == 0)
end
local function getDaysInMonth(month, year)
return month == 2 and isLeapYear(year) and 29
or ("\31\28\31\30\31\30\31\31\30\31\30\31"):byte(month)
end
local function getMonthNumber(m)
if tonumber(m) ~= nil then
return tonumber(m)
elseif m == "current" then
return tonumber(os.date("%m"))
elseif m == "next" then
return tonumber(os.date("%m")) % 12 + 1
elseif m == "last" then
return (tonumber(os.date("%m")) - 2) % 12 + 1
else
return 1
end
end
local function applyDefaultValue(inputValue, defaultValue)
return (inputValue and inputValue ~= "") and inputValue or defaultValue
end
local function getWeekdays(format)
if format == "Mon1st" then
return {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"}
elseif format == "iso" then
return {"Wk", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"}
else
return {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"}
end
end
local function getIsoWeekNumber(year, month, day)
local daysFromStart = os.difftime(os.time{year= year, month=month, day=day}, os.time{year=year, month=1, day=1}) / 86400
local daysUntilEnd = os.difftime(os.time{year= year + 1, month=1, day=1}, os.time{year=year, month=month, day=day}) / 86400
local firstWeekday = tonumber(os.date("%w",os.time{year=year, month=month, day=1}))
local nextFirstWeekday = tonumber(os.date("%w",os.time{year=year+1, month=month, day=1}))
if daysUntilEnd < 4 and nextFirstWeekday >= 4 then return 1 end
local daysFromFirstMonday = daysFromStart - (8 - firstWeekday)
local iso = math.floor(daysFromFirstMonday / 7) + 2 - (firstWeekday > 5 and 1 or 0)
return iso == 0 and getIsoWeekNumber(year - 1, 12, 26) or iso
end
local function make_link(text, flag, pref, suff)
return flag and "[[" .. pref .. text .. suff .. "|" .. text .. "]]" or text
end
local function format_date(date)
return date < 10 and " " .. date or date
end
local function _calendar(frame, _monthNumber, full_mode, float)
local monthNumber = _monthNumber
local year = tonumber(applyDefaultValue(frame.args.year,os.date("%Y")))
local month = os.date("%B", os.time{year=year, month=monthNumber, day=1})
local show_year = applyDefaultValue(frame.args.show_year,"on")
local format = applyDefaultValue(frame.args.format,"Sun1st") --format = "iso"
local colspan = (format == "iso" and 8 or 7)
local prevnext = applyDefaultValue(frame.args.prevnext == "on", false)
local end_note = applyDefaultValue(frame.args.EndNote, "")
local colour = frame.args.colour
local title_colour = applyDefaultValue(colour,frame.args.title_colour)
local week_colour = applyDefaultValue(colour,frame.args.week_colour)
local wknum_colour = frame.args.wknum_colour
local lk = applyDefaultValue(frame.args.lk, "")
local show_link_year = string.match(lk, "y")
local show_link_month = string.match(lk, "m")
local show_link_day = string.match(lk, "d")
local lk_pref = frame.args.lk_pref
local lk_suff = frame.args.lk_suff
local lk_pref_d = applyDefaultValue(lk_pref,frame.args.lk_pref_d)
local lk_suff_d = applyDefaultValue(lk_suff,frame.args.lk_suff_d)
local lk_pref_m = applyDefaultValue(lk_pref,frame.args.lk_pref_m)
local lk_suff_m = applyDefaultValue(lk_suff,frame.args.lk_suff_m)
local lk_pref_mnext = frame.args.lk_pref_mnext
local lk_pref_mprev = frame.args.lk_pref_mprev
local lk_suff_mnext = frame.args.lk_suff_mnext
local lk_suff_mprev = frame.args.lk_suff_mprev
if full_mode and show_year == "on" then show_year = "with month" end
-- calculate helper variables
local prevMonth = os.date("%B", os.time{year=year, month=(monthNumber - 2) % 12 + 1, day=1})
local nextMonth = os.date("%B", os.time{year=year, month=monthNumber % 12 + 1, day=1})
local firstWeekday = tonumber(os.date("%w",os.time{year=year, month=monthNumber, day=1}))
local daysInMonth = getDaysInMonth(monthNumber, year)
-- constuct title
addRow("{| class=\"toccolours " .. float .. "\" style=\"text-align:center;\" cellpadding=2 cellspacing=0\n")
addRow("|- class=\"navbox-title\"" .. " style=\"background:" .. title_colour .. ";\"\n")
local title_colspan = (prevnext and colspan - 2 or colspan)
local title = make_link(month .. (show_year == "with month" and " " .. year or ""), show_link_month, lk_pref_m, lk_suff_m)
local title_row = "|colspan=\"" .. title_colspan .. "\"|'''" .. title .. "'''\n"
if prevnext then
addRow("|[[" .. lk_pref_mprev .. prevMonth .. lk_suff_mprev .. "| << ]]\n" .. title_row .. "|[[" .. lk_pref_mnext .. nextMonth .. lk_suff_mnext .. "| >> ]]\n")
else
addRow(title_row)
end
-- construct weekdays
addRow("|- class=\"navbox-title\"" .. " style=\"background:" .. week_colour .. ";\"\n")
for i, wd in ipairs(getWeekdays(format)) do
addRow("|'''" .. wd .. "'''\n")
end
addRow("|-\n")
-- construct dates
local daysToMiss = firstWeekday - ((format == "Mon1st" or format == "iso") and 1 or 0)
local date = - daysToMiss + 1
local num_rows = full_mode and 6 or math.ceil((daysInMonth + daysToMiss) / 7)
for i = 1, num_rows * colspan do
local lastColumn = i % colspan == 0
local firstColumn = i % colspan == 1
if format == "iso" and firstColumn then
addRow("| class=\"navbox-abovebelow\" style=\"background:" .. wknum_colour .. ";\"|" .. getIsoWeekNumber(year, monthNumber, date) .. "\n")
elseif date > 0 and date <= daysInMonth then
addRow("|" .. make_link(format_date(date), show_link_day, lk_pref_d .. month .. " ", lk_suff_d) .. "\n")
date = date + 1
else
addRow("| \n")
date = date + 1
end
if(lastColumn) then addRow("|-\n") end
end
if end_note ~= "" then
addRow("|- class=\"navbox-title\" \n")
addRow("|colspan=\"" .. colspan .."\"|" .. end_note .. "\n")
end
if show_year == "on" then
addRow("|- class=\"navbox-title\"" .. " style=\"background:" .. title_colour .. ";\"\n")
addRow("|colspan=\"" .. colspan .. "\"|'''" .. make_link(year, show_link_year, "", "") .. "'''\n")
end
addRow("|}")
end
function p.main(frame)
local _month = frame.args.month
local full_calendar = not (_month and _month ~= "")
local year = tonumber(applyDefaultValue(frame.args.year,os.date("%Y")))
local title = applyDefaultValue(frame.args.title,"")
local col = applyDefaultValue(frame.args.col,4)
local row = frame.args.row
local float = "float" .. applyDefaultValue(frame.args.float,"left")
if full_calendar then
addRow("{| class=\"" .. float .. "\" style=none\n")
addRow("! colspan=" .. col .. " style=\"text-align:center; font-size:larger;\" | " .. title .. " " .. year .. "\n")
for i=1, 12 do
if (i - 1) % col == 0 then addRow("|- style=\"vertical-align: top;\"\n") end
addRow("|\n")
_calendar(frame, i, true, "")
addRow("\n")
end
addRow("|}")
else
_calendar(frame, getMonthNumber(frame.args.month), false, float)
end
--return "<nowiki>" .. table.concat(root) .. "</nowiki> \n" ..
return table.concat(root)
end
return p