Module:Age

From Magic: The Gathering Wiki
Jump to navigation Jump to search
Description
This module calculates age information from given years, with support for approximate years (using c. or {{circa}}).
It provides five functions:
  • age – returns only the age range (e.g. "63–64").
  • ageInYears – returns the age as a single value with "years" (e.g. "64 years" or "approx. 64 years"). Can take one parameter (birth year) or two parameters (birth year and reference year).
  • birthDateAndAge – returns the birth year (or c. year) followed by the age in parentheses.
  • deathDateAndAge – returns the death year (or c. year) followed by the age at death in parentheses.
  • startDateAndAge – returns the start year (or c. year) followed by how many years ago in parentheses.
Usage
  • {{#invoke:Age|age|YEAR}}
  • {{#invoke:Age|ageInYears|BIRTH_YEAR}}
  • {{#invoke:Age|ageInYears|BIRTH_YEAR|REFERENCE_YEAR}}
  • {{#invoke:Age|birthDateAndAge|YEAR}}
  • {{#invoke:Age|deathDateAndAge|BIRTH|DEATH}}
  • {{#invoke:Age|startDateAndAge|YEAR}}
Sample output

Age

{{#invoke:Age|age|4500}}approx. 64

{{#invoke:Age|age|c. 4500}}approx. 64

{{#invoke:Age|age|{{circa}} 4500}}approx. 64

Age in years

{{#invoke:Age|ageInYears|4500}}approx. 64 years

{{#invoke:Age|ageInYears|c. 4500}}approx. 64 years

{{#invoke:Age|ageInYears|4500|4560}} → 60 years

{{#invoke:Age|ageInYears|c. 4500|4560}}approx. 60 years

{{#invoke:Age|ageInYears|4500|c. 4560}}approx. 60 years

Birth date and age

{{#invoke:Age|birthDateAndAge|4500}} → 4500 AR (age approx. 64)

{{#invoke:Age|birthDateAndAge|c. 4500}}c. 4500 AR (age approx. 64)

{{#invoke:Age|birthDateAndAge|{{circa}} 4500}}c. 4500 AR (age approx. 64)

Death date and age

{{#invoke:Age|deathDateAndAge|100|200}} → 200 AR (aged 99–100)

{{#invoke:Age|deathDateAndAge|c. 100|200}} → 200 AR (aged approx. 100)

{{#invoke:Age|deathDateAndAge|100|c. 200}}c. 200 AR (aged approx. 100)

Start date and age

{{#invoke:Age|startDateAndAge|1000}} → 1000 AR (approx. 3564 years ago)

{{#invoke:Age|startDateAndAge|c. 1000}}c. 1000 AR (approx. 3564 years ago)

{{#invoke:Age|startDateAndAge|{{circa}} 1000}}c. 1000 AR (approx. 3564 years ago)


-- Module:Age
local p = {}

-- Safely fetch a frame argument. Returns nil if missing or blank (after trim).
local function argTrim(frame, key)
    local v = frame.args[key]
    if v == nil then return nil end
    v = mw.text.trim(tostring(v))
    if v == "" then return nil end
    return v
end

-- Helper: strip "c." or {{circa}} markup and return (isApprox, number)
local function parseYear(input)
    if not input then return false, nil end
    input = mw.text.trim(tostring(input))
    if input == "" then return false, nil end

    -- Strip HTML tags (e.g. from {{circa}})
    local clean = mw.ustring.gsub(input, "<.->", "")
    clean = mw.text.trim(clean)

    -- Does it start with "c." ?
    if mw.ustring.match(clean, "^c%.") then
        local numstr = mw.ustring.gsub(clean, "^c%.%s*", "")
        local num = tonumber(numstr)
        return true, num
    end

    -- Otherwise try to parse a plain number
    return false, tonumber(clean)
end

-- Helper: default Year expansion (trimmed); returns a string or nil
local function defaultYear(frame)
    local y = frame:expandTemplate{ title = "Year" }
    y = mw.text.trim(tostring(y or ""))
    if y == "" then return nil end
    return y
end

-- Age-only output (for {{Age}})
function p.age(frame)
    local birthInput = argTrim(frame, 1) or argTrim(frame, "birth_year")
    local yearInput  = argTrim(frame, 2) or argTrim(frame, "year") or defaultYear(frame)

    local birthApprox, birthYear = parseYear(birthInput)
    local yearApprox,  yearNum   = parseYear(yearInput)

    if not birthYear or not yearNum then
        return "?"
    end

    if birthApprox or yearApprox then
        local age = yearNum - birthYear
        return frame:expandTemplate{title = "approx"} .. " " .. tostring(age)
    end

    local minAge = yearNum - birthYear - 1
    local maxAge = yearNum - birthYear
    return tostring(minAge) .. "–" .. tostring(maxAge)
end

-- Age in years (for {{Age in years}})
function p.ageInYears(frame)
    local birthInput = argTrim(frame, 1) or argTrim(frame, "birth_year")
    local yearInput  = argTrim(frame, 2) or argTrim(frame, "year") or defaultYear(frame)

    local birthApprox, birthYear = parseYear(birthInput)
    local yearApprox,  yearNum   = parseYear(yearInput)

    if not birthYear or not yearNum then
        return "?"
    end

    local age = yearNum - birthYear

    if birthApprox or yearApprox then
        return frame:expandTemplate{title = "approx"} .. " " .. tostring(age) .. " years"
    end

    return tostring(age) .. " years"
end

-- Birth year + age output (for {{Birth date and age}})
function p.birthDateAndAge(frame)
    local birthInput = argTrim(frame, 1) or argTrim(frame, "birth_year")
    local yearInput  = argTrim(frame, 2) or argTrim(frame, "year") or defaultYear(frame)

    local birthApprox, birthYear = parseYear(birthInput)
    local yearApprox,  yearNum   = parseYear(yearInput)

    if not birthYear or not yearNum then
        return "?"
    end

    -- Approximate case
    if birthApprox or yearApprox then
        local age = yearNum - birthYear
        local yearText
        if birthApprox then
            yearText = frame:expandTemplate{title = "circa"} .. " " .. tostring(birthYear) .. " [[AR]]"
        else
            yearText = tostring(birthYear) .. " [[AR]]"
        end
        local ageText = frame:expandTemplate{title = "approx"} .. " " .. tostring(age)
        return yearText .. " (age " .. ageText .. ")"
    end

    -- Exact case
    local minAge = yearNum - birthYear - 1
    local maxAge = yearNum - birthYear
    return tostring(birthYear) .. " [[AR]] (age " .. tostring(minAge) .. "–" .. tostring(maxAge) .. ")"
end

-- Death year + age at death output (for {{Death date and age}})
function p.deathDateAndAge(frame)
    local birthInput = argTrim(frame, 1) or argTrim(frame, "birth_year")
    local deathInput = argTrim(frame, 2) or argTrim(frame, "death_year")

    local birthApprox, birthYear = parseYear(birthInput)
    local deathApprox, deathYear = parseYear(deathInput)

    if not birthYear or not deathYear then
        return "?"
    end

    -- Approximate case if either is approximate
    if birthApprox or deathApprox then
        local age = deathYear - birthYear

        local deathText
        if deathApprox then
            deathText = frame:expandTemplate{title = "circa"} .. " " .. tostring(deathYear) .. " [[AR]]"
        else
            deathText = tostring(deathYear) .. " [[AR]]"
        end

        local ageText = frame:expandTemplate{title = "approx"} .. " " .. tostring(age)
        return deathText .. " (aged " .. ageText .. ")"
    end

    -- Exact case
    local minAge = deathYear - birthYear - 1
    local maxAge = deathYear - birthYear
    return tostring(deathYear) .. " [[AR]] (aged " .. tostring(minAge) .. "–" .. tostring(maxAge) .. ")"
end

-- Start year + years ago output (for {{Start date and age}})
function p.startDateAndAge(frame)
    local startInput = argTrim(frame, 1) or argTrim(frame, "start_year")
    local yearInput  = argTrim(frame, 2) or argTrim(frame, "year") or defaultYear(frame)

    local startApprox, startYear = parseYear(startInput)
    local yearApprox,  yearNum   = parseYear(yearInput)

    if not startYear or not yearNum then
        return "?"
    end

    -- Approximate case
    if startApprox or yearApprox then
        local yearsAgo = yearNum - startYear
        local yearsText = frame:expandTemplate{title = "approx"} .. " " .. tostring(yearsAgo)

        local startText
        if startApprox then
            startText = frame:expandTemplate{title = "circa"} .. " " .. tostring(startYear) .. " [[AR]]"
        else
            startText = tostring(startYear) .. " [[AR]]"
        end

        return startText .. " (" .. yearsText .. " years ago)"
    end

    -- Exact case
    local minYears = yearNum - startYear - 1
    local maxYears = yearNum - startYear
    return tostring(startYear) .. " [[AR]] (" .. tostring(minYears) .. "–" .. tostring(maxYears) .. " years ago)"
end

return p