Module:Time elapsed

From Uncyclopedia, the content-free encyclopedia
Jump to navigation Jump to search

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