Jump to content
Main menu
Main menu
move to sidebar
hide
Navigation
Main page
Recent changes
Random page
Help about MediaWiki
Humanipedia
Search
Search
Appearance
Create account
Log in
Personal tools
Create account
Log in
Pages for logged out editors
learn more
Contributions
Talk
Editing
Module:Calendar date
Module
Discussion
English
Read
Edit source
View history
Tools
Tools
move to sidebar
hide
Actions
Read
Edit source
View history
General
What links here
Related changes
Special pages
Page information
Appearance
move to sidebar
hide
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
--[[ Display Gregorian date of a holiday that moves year to year. Date data can be obtained from multiple sources as configured in Module:Calendar date/events "localfile" = local data file (eg. https://en.wikipedia.org/wiki/Module:Calendar_date/localfiles/Hanukkah) "calculator" = user-supplied date calculator "wikidata" = <tbd> for holidays with their own date entity page such as https://www.wikidata.org/wiki/Q51224536 ]] require('strict') local p = {} local cfg -- Data structure from ~/events local eventdata -- Data structure from ~/localfiles/<holiday name> local track = {} -- Tracking category container --[[--------------------------< inlineError >----------------------- Critical error. Render output completely in red. Add to tracking category. ]] local function inlineError(arg, msg, tname) track["Category:Calendar date template errors"] = 1 return '<span style="font-size:100%" class="error citation-comment">Error in {{' .. tname .. '}} - Check <code style="color:inherit; border:inherit; padding:inherit;">|' .. arg .. '=</code> ' .. msg .. '</span>' end --[[--------------------------< trimArg >----------------------- trimArg returns nil if arg is "" while trimArg2 returns 'true' if arg is "" trimArg2 is for args that might accept an empty value, as an on/off switch like nolink= ]] local function trimArg(arg) if arg == "" or arg == nil then return nil end return mw.text.trim(arg) end local function trimArg2(arg) if arg == nil then return nil end return mw.text.trim(arg) end --[[--------------------------< tableLength >----------------------- Given a 1-D table, return number of elements ]] local function tableLength(T) local count = 0 for _ in pairs(T) do count = count + 1 end return count end --[[-------------------------< make_wikilink >---------------------------------------------------- Makes a wikilink; when both link and display text is provided, returns a wikilink in the form [ [L|D] ]; if only link is provided, returns a wikilink in the form [ [L] ]; if neither are provided or link is omitted, returns an empty string. ]] local function make_wikilink (link, display, no_link) if nil == no_link then if link and ('' ~= link) then if display and ('' ~= display) then return table.concat ({'[[', link, '|', display, ']]'}); end return table.concat ({'[[', link, ']]'}); end else -- no_link if display and ('' ~= display) then -- if there is display text return display; -- return that end return link or ''; -- return the target article name or empty string end end --[[--------------------------< createTracking >----------------------- Return data in track[] ie. tracking categories ]] local function createTracking() local out = {}; if tableLength(track) > 0 then for key, _ in pairs(track) do -- loop through table table.insert (out, make_wikilink (key)) -- and convert category names to links end end return table.concat (out) -- concat into one big string; empty string if table is empty end --[[--------------------------< isValidDate >---------------------------------------------------- Returns true if date is after 31 December 1899 , not after 2100, and represents a valid date (29 February 2017 is not a valid date). Applies Gregorian leapyear rules. All arguments are required. ]] local function isValidDate (year, month, day) local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} local month_length local y, m, d local today = os.date ('*') -- fetch a table of current date parts if not year or year == '' or not month or month == '' or not day or day == '' then return false -- something missing end y = tonumber (year) m = tonumber (month) d = tonumber (day) if 1900 > y or 2100 < y or 1 > m or 12 < m then -- year and month are within bounds return false end if (2==m) then -- if February month_length = 28 -- then 28 days unless if (0==(y%4) and (0~=(y%100) or 0==(y%400))) then -- is a leap year? month_length = 29 -- if leap year then 29 days in February end else month_length=days_in_month[m]; end if 1 > d or month_length < d then -- day is within bounds return false end return true end --[[--------------------------< makeDate >----------------------- Given a zero-padded 4-digit year, 2-digit month and 2-digit day, return a full date in df format df = mdy, dmy, iso, ymd ]] local function makeDate(year, month, day, df, format) local formatFull = { ['dmy'] = 'j F Y', ['mdy'] = 'F j, Y', ['ymd'] = 'Y F j', ['iso'] = 'Y-m-d' } local formatInfobox = { ['dmy'] = 'j F', ['mdy'] = 'F j', ['ymd'] = 'F j', ['iso'] = 'Y-m-d' } if not year or year == "" or not month or month == "" or not day or day == "" and format[df] then return nil end local date = table.concat ({year, month, day}) -- assemble iso format date if format ~= "infobox" then return mw.getContentLanguage():formatDate (formatFull[df], date) end return mw.getContentLanguage():formatDate (formatInfobox[df], date) end --[[--------------------------< dateOffset >----------------------- Given a 'origdate' in ISO format, return the date offset by number of days in 'offset' eg. given "2018-02-01" and "-1" it will return "2018-01-30" On error, return origdate ]] local function dateOffset(origdate, offset) local year, month, day = origdate:match ('(%d%d%d%d)-(%d%d)-(%d%d)') local now = os.time{year = year, month = month, day = day} local newdate = os.date("%Y-%m-%d", now + (tonumber(offset) * 24 * 3600)) return newdate and newdate or origdate end --[[--------------------------< renderHoli >----------------------- Render the data ]] local function renderHoli(cfg,eventdata,calcdate,date,df,format,tname,cite) local hits = 0 local matchdate = "^" .. date local startdate,enddate,outoffset,endoutoffset = nil local starttitle,endtitle = "" -- user-supplied date calculator if cfg.datatype == "calculator" then if cfg.datasource then startdate = calcdate enddate = dateOffset(startdate, cfg.days - 1) else return inlineError("holiday", 'invalid calculator result', tname ) end -- read dates from localfile -- it assumes dates are in chrono order, need a more flexible method elseif cfg.datatype == "localfile" then local numRecords = tableLength(eventdata) -- Get first and last date of holiday for i = 1, numRecords do if mw.ustring.find( eventdata[i].date, matchdate ) then if hits == 0 then startdate = eventdata[i].date hits = 1 end if hits >= tonumber(cfg.days) then enddate = eventdata[i].date break end hits = hits + 1 end end end -- Verify data and special conditions if startdate == nil or enddate == nil then if cfg.name == "Hanukkah" and startdate and not enddate then -- Hanukkah bug, template doesn't support cross-year boundary enddate = dateOffset(startdate, 8) elseif cfg.datatype == "localfile" and cfg.days > "1" and startdate then enddate = dateOffset(startdate, cfg.days - 1) elseif startdate and not enddate then return inlineError("year", 'cannot find enddate', tname) .. createTracking() else return inlineError("holiday", 'cannot find startdate and enddate', tname) .. createTracking() end end -- Generate start-date offset (ie. holiday starts the evening before the given date) if cfg.startoffset then startdate = dateOffset(startdate, cfg.startoffset) if startdate ~= enddate then enddate = dateOffset(enddate, cfg.startoffset) else cfg.days = (cfg.days == "1") and "2" end end -- Generate end-date outside-Irael offset (ie. outside Israel the holiday ends +1 day later) endoutoffset = cfg.endoutoffset and dateOffset(enddate, cfg.endoutoffset) -- Format dates into df format local year, month, day = startdate:match ('(%d%d%d%d)-(%d%d)-(%d%d)') startdate = makeDate(year, month, day, df, format) year, month, day = enddate:match ('(%d%d%d%d)-(%d%d)-(%d%d)') enddate = makeDate(year, month, day, df, format) if startdate == nil or enddate == nil then return nil end -- Add "outside of Israel" notices if endoutoffset then year, month, day = endoutoffset:match ('(%d%d%d%d)-(%d%d)-(%d%d)') local leader = ((format == "infobox") and "<br>") or " " endoutoffset = leader .. "(" .. makeDate(year, month, day, df, "infobox") .. " outside of Israel)" end if not endoutoffset then endoutoffset = "" end --- Determine format string format = ((format == "infobox") and " β<br>") or " β " --- Determine pre-pended text string eg. "sunset, <date>" local prepend1 = (cfg.prepend1 and (cfg.prepend1 .. ", ")) or "" local prepend2 = (cfg.prepend2 and (cfg.prepend2 .. ", ")) or "" -- return output if startdate == enddate or cfg.days == "1" then -- single date return prepend1 .. startdate .. endoutoffset .. cite end return prepend1 .. startdate .. format .. prepend2 .. enddate .. endoutoffset .. cite end --[[--------------------------< calendardate >----------------------- Main function ]] function p.calendardate(frame) local pframe = frame:getParent() local args = pframe.args local tname = "Calendar date" -- name of calling template. Change if template rename. local holiday = nil -- name of holiday local date = nil -- date of holiday (year) local df = nil -- date format (mdy, dmy, iso - default: iso) local format = nil -- template display format options local cite = nil -- leave a citation at end local calcdate = "" --- Determine holiday holiday = trimArg(args.holiday) -- required if not holiday then holiday = trimArg(args.event) -- event alias if not holiday then return inlineError("holiday", 'missing holiday argument', tname) .. createTracking() end end --- Determine date date = trimArg(args.year) -- required if not date then return inlineError("year", 'missing year argument', tname) .. createTracking() elseif not isValidDate(date, "01", "01") then return inlineError("year", 'invalid year', tname) .. createTracking() end --- Determine format type format = trimArg(args.format) if not format or format ~= "infobox" then format = "none" end -- Load configuration file local eventsfile = mw.loadData ('Module:Calendar date/events') if eventsfile.hebrew_calendar[mw.ustring.upper(holiday)] then cfg = eventsfile.hebrew_calendar[mw.ustring.upper(holiday)] elseif eventsfile.christian_events[mw.ustring.upper(holiday)] then cfg = eventsfile.christian_events[mw.ustring.upper(holiday)] elseif eventsfile.carnivals[mw.ustring.upper(holiday)] then cfg = eventsfile.carnivals[mw.ustring.upper(holiday)] elseif eventsfile.chinese_events[mw.ustring.upper(holiday)] then cfg = eventsfile.chinese_events[mw.ustring.upper(holiday)] elseif eventsfile.misc_events[mw.ustring.upper(holiday)] then cfg = eventsfile.misc_events[mw.ustring.upper(holiday)] else return inlineError("holiday", 'unknown holiday ' .. holiday, tname) .. createTracking() end -- If datatype = localfile if cfg.datatype == "localfile" then local eventfile = nil eventfile = mw.loadData(cfg.datasource) if eventfile.event then eventdata = eventfile.event else return inlineError("holiday", 'unknown holiday file ' .. cfg.datasource .. '</span>', tname) .. createTracking() end -- If datatype = calculator elseif cfg.datatype == "calculator" then calcdate = frame:preprocess(cfg.datasource:gsub("YYYY", date)) local year, month, day = calcdate:match ('(%d%d%d%d)-(%d%d)-(%d%d)') if not isValidDate(year, month, day) then return inlineError("holiday", 'invalid calculated date ' .. calcdate, tname) .. createTracking() end else return inlineError("holiday", 'unknown "datatype" in configuration', tname) .. createTracking() end --- Determine df - priority to |df in template, otherwise df in datafile, otherwise default to dmy df = trimArg(args.df) if not df then df = (cfg.df and cfg.df) or "dmy" end if df ~= "mdy" and df ~= "dmy" and df ~= "iso" then df = "dmy" end -- Determine citation cite = trimArg2(args.cite) if cite then if (cite ~= "no") then cite = "" if cfg.citeurl and cfg.accessdate and cfg.source and cfg.name then local citetitle = cfg.citetitle if citetitle == nil then citetitle = 'Dates for ' .. cfg.name end cite = frame:preprocess('<ref name="' .. holiday .. ' dates">{{cite web |url=' .. cfg.citeurl .. ' |title=' .. citetitle .. ' |publisher=' .. cfg.source .. '|accessdate=' .. cfg.accessdate .. '}}</ref>') elseif cfg.source then cite = frame:preprocess('<ref name="' .. holiday .. ' dates">' .. cfg.source:gsub("YYYY", date) .. '</ref>') end else cite = "" end else cite = "" end -- Render local rend = renderHoli( cfg,eventdata,calcdate,date,df,format,tname,cite) if not rend then rend = '<span style="font-size:100%" class="error citation-comment">Error in [[:Template:' .. tname .. ']]: Unknown problem. Please report on template talk page.</span>' track["Category:Webarchive template errors"] = 1 end return rend .. createTracking() end return p
Summary:
Please note that all contributions to Humanipedia may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see
Humanipedia:Copyrights
for details).
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Debug console
* The module exports are available as the variable "p", including unsaved modifications. * Precede a line with "=" to evaluate it as an expression or use print(). Use mw.logObject() for tables. * Use mw.log() and mw.logObject() in module code to send messages to this console.
Templates used on this page:
Template:Error
(
edit
)
Template:Lua
(
edit
)
Template:Module other
(
edit
)
Template:Module rating
(
edit
)
Template:Ombox
(
edit
)
Template:Pp
(
edit
)
Template:Protection padlock
(
edit
)
Template:Sandbox other
(
edit
)
Template:Template link
(
edit
)
Template:Ti
(
edit
)
Template:Tl
(
edit
)
Module:Calendar date/doc
(
edit
)
Module:Error
(
edit
)
Module:File link
(
edit
)
Module:Lua banner
(
edit
)
Module:Message box
(
edit
)
Module:Protection banner
(
edit
)
Module:String
(
edit
)