Module:IriniaCalendar

From DSRPG
Revision as of 20:00, 4 May 2025 by Dubhghlas (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Documentation for this module may be created at Module:IriniaCalendar/doc

-- Module:IriniaCalendar
-- A module for handling the custom calendar of Irinia

local p = {}

-- Configurable calendar variables
local calendar = {
    current = { day = 4, month = 5, year = 1236 },
    months = {
        [1] = "Frost Moon",   [2] = "Shadow Moon", [3] = "Storm Moon",
        [4] = "Mist Moon",    [5] = "Bloom Moon",  [6] = "Sun Moon",
        [7] = "Thunder Moon", [8] = "Harvest Moon",[9] = "Ember Moon",
        [10] = "Frost Moon",  [11] = "Twilight Moon",[12] = "Star Moon"
    },
    days_in_month = {
        [1] = 30, [2] = 28, [3] = 30, [4] = 29,
        [5] = 31, [6] = 31, [7] = 30, [8] = 31,
        [9] = 30,[10] = 31,[11] = 28,[12] = 30
    },
    weekdays = {
        [1] = "Silverday", [2] = "Brassday", [3] = "Woodday",
        [4] = "Stoneday",  [5] = "Glassday", [6] = "Steamday",
        [7] = "Gearsday"
    },
    seasons = {
        [1] = "Winter", [2] = "Winter", [3] = "Spring",
        [4] = "Spring", [5] = "Spring", [6] = "Summer",
        [7] = "Summer", [8] = "Summer", [9] = "Autumn",
        [10] = "Autumn",[11] = "Autumn",[12] = "Winter"
    },
    era = "AE",
    days_in_year = 359
}

-- Format a date via #invoke args: day, month, year, format
function p.formatDate(frame)
    local args  = frame.args or {}
    local day   = tonumber(args.day)   or calendar.current.day
    local month = tonumber(args.month) or calendar.current.month
    local year  = tonumber(args.year)  or calendar.current.year
    local fmt   = args.format          or "full"

    if month < 1 or month > #calendar.months then
        month = ((month - 1) % #calendar.months) + 1
    end
    local monthName = calendar.months[month]

    if fmt == "full" then
        return day .. " " .. monthName .. ", " .. year .. " " .. calendar.era
    elseif fmt == "short" then
        return day .. " " .. monthName .. ", " .. year
    elseif fmt == "month-year" then
        return monthName .. ", " .. year .. " " .. calendar.era
    elseif fmt == "day-month" then
        return day .. " " .. monthName
    elseif fmt == "numeric" then
        return day .. "/" .. month .. "/" .. year .. " " .. calendar.era
    else
        -- fallback for unknown formats
        return day .. " " .. monthName .. ", " .. year .. " " .. calendar.era
    end
end

-- Total days since year 0
function p.totalDays(date)
    if not date or not date.day or not date.month or not date.year then return 0 end
    local total = date.year * calendar.days_in_year
    for i = 1, date.month - 1 do
        total = total + calendar.days_in_month[i]
    end
    total = total + date.day
    return total
end

-- Compare two dates: returns -1, 0, or 1
function p.compareDate(a, b)
    if a.year < b.year then return -1 elseif a.year > b.year then return 1 end
    if a.month < b.month then return -1 elseif a.month > b.month then return 1 end
    if a.day < b.day then return -1 elseif a.day > b.day then return 1 end
    return 0
end

-- Calculate difference between two dates as a string
function p.dateDifference(d1, d2)
    local negative = false
    if p.compareDate(d1, d2) > 0 then d1, d2 = d2, d1; negative = true end

    local years  = d2.year - d1.year
    local months = 0
    local days   = 0

    if d2.month >= d1.month then
        months = d2.month - d1.month
    else
        years  = years - 1
        months = 12 - d1.month + d2.month
    end

    if d2.day >= d1.day then
        days = d2.day - d1.day
    else
        if months > 0 then
            months = months - 1
        else
            years  = years - 1
            months = 11
        end
        local prev = d2.month - 1
        if prev < 1 then prev = 12 end
        days = calendar.days_in_month[prev] - d1.day + d2.day
    end

    local parts = {}
    if years  ~= 0 then table.insert(parts, years .. " year"  .. (years  ~= 1 and "s" or "")) end
    if months ~= 0 then table.insert(parts, months.. " month" .. (months ~= 1 and "s" or "")) end
    if days   ~= 0 or #parts == 0 then table.insert(parts, days  .. " day"   .. (days   ~= 1 and "s" or "")) end

    local result = table.concat(parts, ", ")
    if #parts > 1 then
        result = string.gsub(result, ", ([^,]*)$", " and %1")
    end
    if negative then result = result .. " ago" end
    return result
end

-- How long since a given date
function p.timeSince(frame)
    local args = frame.args or {}
    local d    = {
        day   = tonumber(args.day)   or 1,
        month = tonumber(args.month) or 1,
        year  = tonumber(args.year)  or 0
    }
    return p.dateDifference(d, calendar.current)
end

-- How long until a given date
function p.timeUntil(frame)
    local args = frame.args or {}
    local d    = {
        day   = tonumber(args.day)   or 1,
        month = tonumber(args.month) or 1,
        year  = tonumber(args.year)  or 0
    }
    return p.dateDifference(calendar.current, d)
end

-- Calculate age in years given birth date
function p.calculateAge(frame)
    local args = frame.args or {}
    local d    = {
        day   = tonumber(args.day)   or 1,
        month = tonumber(args.month) or 1,
        year  = tonumber(args.year)  or 0
    }
    local diff = p.dateDifference(d, calendar.current)
    local y    = string.match(diff, "^(%d+) years?")
    return y or "0"
end

return p