Module:Time elapsed
Jump to navigation
Jump to search
Implements {{Time elapsed}}.
Usage
{{#invoke:Time elapsed|main}}
Examples
{{#invoke:ModuleName|main|12|25|2020}}
{{#invoke:ModuleName|main|December|25th|2020}}
{{#invoke:ModuleName|main|Dec|05|2020}}
{{#invoke:ModuleName|main|month=January|day=1st|year=2000}}
local p = {}
-- Month name to number mapping
local months = {
january = 1, jan = 1,
february = 2, feb = 2,
march = 3, mar = 3,
april = 4, apr = 4,
may = 5,
june = 6, jun = 6,
july = 7, jul = 7,
august = 8, aug = 8,
september = 9, sep = 9, sept = 9,
october = 10, oct = 10,
november = 11, nov = 11,
december = 12, dec = 12
}
-- Parse month: accepts month names, abbreviations, or numbers
local function parseMonth(month)
if not month then return nil end
-- Try as number first
local monthNum = tonumber(month)
if monthNum and monthNum >= 1 and monthNum <= 12 then
return monthNum
end
-- Try as month name/abbreviation
local monthLower = string.lower(month)
return months[monthLower]
end
-- Parse day: strip ordinal suffixes and zero-padding
local function parseDay(day)
if not day then return nil end
-- Strip common ordinal suffixes
local dayStr = tostring(day):gsub("st$", ""):gsub("nd$", ""):gsub("rd$", ""):gsub("th$", "")
local dayNum = tonumber(dayStr)
if dayNum and dayNum >= 1 and dayNum <= 31 then
return dayNum
end
return nil
end
-- Parse year: must be 4 digits
local function parseYear(year)
if not year then return nil end
local yearStr = tostring(year)
if yearStr:match("^%d%d%d%d$") then
return tonumber(yearStr)
end
return nil
end
-- Calculate difference between two dates
local function dateDifference(startYear, startMonth, startDay, endYear, endMonth, endDay)
local years = endYear - startYear
local months = endMonth - startMonth
local days = endDay - startDay
-- Adjust for negative days
if days < 0 then
months = months - 1
-- Get days in previous month
local prevMonth = endMonth - 1
local prevYear = endYear
if prevMonth < 1 then
prevMonth = 12
prevYear = prevYear - 1
end
local daysInPrevMonth = os.time({year=prevYear, month=prevMonth+1, day=1}) - os.time({year=prevYear, month=prevMonth, day=1})
daysInPrevMonth = daysInPrevMonth / 86400
days = days + daysInPrevMonth
end
-- Adjust for negative months
if months < 0 then
years = years - 1
months = months + 12
end
return years, months, days
end
function p.main(frame)
-- Get parameters (positional or named)
local args = frame.args
if not args[1] and frame:getParent() then
args = frame:getParent().args
end
-- Parse parameters: MM, DD, YYYY order
local month = parseMonth(args[1] or args.month)
local day = parseDay(args[2] or args.day)
local year = parseYear(args[3] or args.year)
-- Validate all parameters
if not month then
return '<span class="error">Invalid or missing month</span>'
end
if not day then
return '<span class="error">Invalid or missing day</span>'
end
if not year then
return '<span class="error">Invalid or missing year (must be 4 digits)</span>'
end
-- Get current date
local today = os.date("*t")
local currentYear = today.year
local currentMonth = today.month
local currentDay = today.day
-- Calculate difference
local years, months, days = dateDifference(year, month, day, currentYear, currentMonth, currentDay)
-- Build output with proper pluralization
local parts = {}
-- Years
if years == 1 then
table.insert(parts, "1 year")
else
table.insert(parts, years .. " years")
end
-- Months (only if not zero)
if months == 1 then
table.insert(parts, "1 month")
elseif months > 1 then
table.insert(parts, months .. " months")
end
-- Days
if days == 1 then
table.insert(parts, "1 day")
else
table.insert(parts, days .. " days")
end
-- Join parts with proper grammar
local result
if #parts == 3 then
result = parts[1] .. ", " .. parts[2] .. " and " .. parts[3]
elseif #parts == 2 then
result = parts[1] .. " and " .. parts[2]
else
result = parts[1]
end
return result
end
return p