Module:Roman Date

Revision as of 14:29, 7 February 2024 by 2.124.47.92 (talk) (Fix leap year problem)

This module implements the {{Roman Date}} template. For behavioural documentation, please see the template page.

  • This module supports dates formatted in the form YYYY-MM-DD or MM-DD
  • This is a new module and may be subject to bugs, to report bugs please use the discord
  • This module also supports leap years

Known Bugs

  • Doesn't check for dates that are past the maximum number of days in a month
  • Doesn't check for dates below 1 and thus may fail

-- This Module implements {{Roman Date}}

local numeral = require("Module:Roman Numeral")

local p = {}

local function month_ides_lookup(month)
    if month == 3 then
        return 15
    elseif month == 5 then
        return 15
    elseif month == 7 then
        return 15
    elseif month == 10 then
        return 15
    else
        return 13
    end
end

local function checkLeapYear(year)
    return (((year % 4 == 0) and (year % 100 ~= 0)) or (year % 400 == 0));
end

local function _main(args)
    local months = {
        accusative = {
            'Januarias',
            'Februarias',
            'Martias',
            'Apriles',
            'Maias',
            'Junias',
            'Julias',
            'Augustas',
            'Septembres',
            'Octobres',
            'Novembres',
            'Decembres'
        },
        ablative = {
            'Januariis',
            'Februariis',
            'Martiis',
            'Aprilibus',
            'Maiis',
            'Juniis',
            'Juliis',
            'Augustis',
            'Septembribus',
            'Octobribus',
            'Novembribus',
            'Decembribus'
        }
    }

    local dayLookup = { { 'Kal. ', 'Kal. ', 'Kal. ', 'Kal. ', 'Kal. ', 'Kal. ', 'Kal. ', 'Kal. ', 'Kal. ', 'Kal. ', 'Kal. ', 'Kal. ', 'Kal. ' }, { 'a.d. IV Non. ', 'a.d. IV Non. ', 'a.d. VI Non. ', 'a.d. IV Non. ', 'a.d. VI Non. ', 'a.d. IV Non. ', 'a.d. VI Non. ', 'a.d. IV Non. ', 'a.d. IV Non. ', 'a.d. VI Non. ', 'a.d. IV Non. ', 'a.d. IV Non. ', 'a.d. IV Non. ' }, { 'a.d. III Non. ', 'a.d. III Non. ', 'a.d. V Non. ', 'a.d. III Non. ', 'a.d. V Non. ', 'a.d. III Non. ', 'a.d. V Non. ', 'a.d. III Non. ', 'a.d. III Non. ', 'a.d. V Non. ', 'a.d. III Non. ', 'a.d. III Non. ', 'a.d. III Non. ' }, { 'pr. Non. ', 'pr. Non. ', 'a.d. IV Non. ', 'pr. Non. ', 'a.d. IV Non. ', 'pr. Non. ', 'a.d. IV Non. ', 'pr. Non. ', 'pr. Non. ', 'a.d. IV Non. ', 'pr. Non. ', 'pr. Non. ', 'pr. Non. ' }, { 'Non. ', 'Non. ', 'a.d. III Non. ', 'Non. ', 'a.d. III Non. ', 'Non. ', 'a.d. III Non. ', 'Non. ', 'Non. ', 'a.d. III Non. ', 'Non. ', 'Non. ', 'Non. ' }, { 'a.d. VIII Id. ', 'a.d. VIII Id. ', 'pr. Non. ', 'a.d. VIII Id. ', 'pr. Non. ', 'a.d. VIII Id. ', 'pr. Non. ', 'a.d. VIII Id. ', 'a.d. VIII Id. ', 'pr. Non. ', 'a.d. VIII Id. ', 'a.d. VIII Id. ', 'a.d. VIII Id. ' }, { 'a.d. VII Id. ', 'a.d. VII Id. ', 'Non. ', 'a.d. VII Id. ', 'Non. ', 'a.d. VII Id. ', 'Non. ', 'a.d. VII Id. ', 'a.d. VII Id. ', 'Non. ', 'a.d. VII Id. ', 'a.d. VII Id. ', 'a.d. VII Id. ' }, { 'a.d. VI Id. ', 'a.d. VI Id. ', 'a.d. VIII Id. ', 'a.d. VI Id. ', 'a.d. VIII Id. ', 'a.d. VI Id. ', 'a.d. VIII Id. ', 'a.d. VI Id. ', 'a.d. VI Id. ', 'a.d. VIII Id. ', 'a.d. VI Id. ', 'a.d. VI Id. ', 'a.d. VI Id. ' }, { 'a.d. V Id. ', 'a.d. V Id. ', 'a.d. VII Id. ', 'a.d. V Id. ', 'a.d. VII Id. ', 'a.d. V Id. ', 'a.d. VII Id. ', 'a.d. V Id. ', 'a.d. V Id. ', 'a.d. VII Id. ', 'a.d. V Id. ', 'a.d. V Id. ', 'a.d. V Id. ' }, { 'a.d. IV Id. ', 'a.d. IV Id. ', 'a.d. VI Id. ', 'a.d. IV Id. ', 'a.d. VI Id. ', 'a.d. IV Id. ', 'a.d. VI Id. ', 'a.d. IV Id. ', 'a.d. IV Id. ', 'a.d. VI Id. ', 'a.d. IV Id. ', 'a.d. IV Id. ', 'a.d. IV Id. ' }, { 'a.d. III Id. ', 'a.d. III Id. ', 'a.d. V Id. ', 'a.d. III Id. ', 'a.d. V Id. ', 'a.d. III Id. ', 'a.d. V Id. ', 'a.d. III Id. ', 'a.d. III Id. ', 'a.d. V Id. ', 'a.d. III Id. ', 'a.d. III Id. ', 'a.d. III Id. ' }, { 'pr. Id. ', 'pr. Id. ', 'a.d. IV Id. ', 'pr. Id. ', 'a.d. IV Id. ', 'pr. Id. ', 'a.d. IV Id. ', 'pr. Id. ', 'pr. Id. ', 'a.d. IV Id. ', 'pr. Id. ', 'pr. Id. ', 'pr. Id. ' }, { 'Id. ', 'Id. ', 'a.d. III Id. ', 'Id. ', 'a.d. III Id. ', 'Id. ', 'a.d. III Id. ', 'Id. ', 'Id. ', 'a.d. III Id. ', 'Id. ', 'Id. ', 'Id. ' }, { 'a.d. XIX Kal. ', 'a.d. XVI Kal. ', 'pr. Id. ', 'a.d. XVIII Kal. ', 'pr. Id. ', 'a.d. XVIII Kal. ', 'pr. Id. ', 'a.d. XIX Kal. ', 'a.d. XVIII Kal. ', 'pr. Id. ', 'a.d. XVIII Kal. ', 'a.d. XIX Kal. ', None }, { 'a.d. XVIII Kal. ', 'a.d. XV Kal. ', 'Id. ', 'a.d. XVII Kal. ', 'Id. ', 'a.d. XVII Kal. ', 'Id. ', 'a.d. XVIII Kal. ', 'a.d. XVII Kal. ', 'Id. ', 'a.d. XVII Kal. ', 'a.d. XVIII Kal. ', None }, { 'a.d. XVII Kal. ', 'a.d. XIV Kal. ', 'a.d. XVII Kal. ', 'a.d. XVI Kal. ', 'a.d. XVII Kal. ', 'a.d. XVI Kal. ', 'a.d. XVII Kal. ', 'a.d. XVII Kal. ', 'a.d. XVI Kal. ', 'a.d. XVII Kal. ', 'a.d. XVI Kal. ', 'a.d. XVII Kal. ', None }, { 'a.d. XVI Kal. ', 'a.d. XIII Kal. ', 'a.d. XVI Kal. ', 'a.d. XV Kal. ', 'a.d. XVI Kal. ', 'a.d. XV Kal. ', 'a.d. XVI Kal. ', 'a.d. XVI Kal. ', 'a.d. XV Kal. ', 'a.d. XVI Kal. ', 'a.d. XV Kal. ', 'a.d. XVI Kal. ', None }, { 'a.d. XV Kal. ', 'a.d. XII Kal. ', 'a.d. XV Kal. ', 'a.d. XIV Kal. ', 'a.d. XV Kal. ', 'a.d. XIV Kal. ', 'a.d. XV Kal. ', 'a.d. XV Kal. ', 'a.d. XIV Kal. ', 'a.d. XV Kal. ', 'a.d. XIV Kal. ', 'a.d. XV Kal. ', None }, { 'a.d. XIV Kal. ', 'a.d. XI Kal. ', 'a.d. XIV Kal. ', 'a.d. XIII Kal. ', 'a.d. XIV Kal. ', 'a.d. XIII Kal. ', 'a.d. XIV Kal. ', 'a.d. XIV Kal. ', 'a.d. XIII Kal. ', 'a.d. XIV Kal. ', 'a.d. XIII Kal. ', 'a.d. XIV Kal. ', None }, { 'a.d. XIII Kal. ', 'a.d. X Kal. ', 'a.d. XIII Kal. ', 'a.d. XII Kal. ', 'a.d. XIII Kal. ', 'a.d. XII Kal. ', 'a.d. XIII Kal. ', 'a.d. XIII Kal. ', 'a.d. XII Kal. ', 'a.d. XIII Kal. ', 'a.d. XII Kal. ', 'a.d. XIII Kal. ', None }, { 'a.d. XII Kal. ', 'a.d. IX Kal. ', 'a.d. XII Kal. ', 'a.d. XI Kal. ', 'a.d. XII Kal. ', 'a.d. XI Kal. ', 'a.d. XII Kal. ', 'a.d. XII Kal. ', 'a.d. XI Kal. ', 'a.d. XII Kal. ', 'a.d. XI Kal. ', 'a.d. XII Kal. ', None }, { 'a.d. XI Kal. ', 'a.d. VIII Kal. ', 'a.d. XI Kal. ', 'a.d. X Kal. ', 'a.d. XI Kal. ', 'a.d. X Kal. ', 'a.d. XI Kal. ', 'a.d. XI Kal. ', 'a.d. X Kal. ', 'a.d. XI Kal. ', 'a.d. X Kal. ', 'a.d. XI Kal. ', None }, { 'a.d. X Kal. ', 'a.d. VII Kal. ', 'a.d. X Kal. ', 'a.d. IX Kal. ', 'a.d. X Kal. ', 'a.d. IX Kal. ', 'a.d. X Kal. ', 'a.d. X Kal. ', 'a.d. IX Kal. ', 'a.d. X Kal. ', 'a.d. IX Kal. ', 'a.d. X Kal. ', None }, { 'a.d. IX Kal. ', 'a.d. VI Kal. ', 'a.d. IX Kal. ', 'a.d. VIII Kal. ', 'a.d. IX Kal. ', 'a.d. VIII Kal. ', 'a.d. IX Kal. ', 'a.d. IX Kal. ', 'a.d. VIII Kal. ', 'a.d. IX Kal. ', 'a.d. VIII Kal. ', 'a.d. IX Kal. ', 'a.d. bis VI Kal. ' }, { 'a.d. VIII Kal. ', 'a.d. V Kal. ', 'a.d. VIII Kal. ', 'a.d. VII Kal. ', 'a.d. VIII Kal. ', 'a.d. VII Kal. ', 'a.d. VIII Kal. ', 'a.d. VIII Kal. ', 'a.d. VII Kal. ', 'a.d. VIII Kal. ', 'a.d. VII Kal. ', 'a.d. VIII Kal. ', 'a.d. VI Kal. ' }, { 'a.d. VII Kal. ', 'a.d. IV Kal. ', 'a.d. VII Kal. ', 'a.d. VI Kal. ', 'a.d. VII Kal. ', 'a.d. VI Kal. ', 'a.d. VII Kal. ', 'a.d. VII Kal. ', 'a.d. VI Kal. ', 'a.d. VII Kal. ', 'a.d. VI Kal. ', 'a.d. VII Kal. ', 'a.d. V Kal. ' }, { 'a.d. VI Kal. ', 'a.d. III Kal. ', 'a.d. VI Kal. ', 'a.d. V Kal. ', 'a.d. VI Kal. ', 'a.d. V Kal. ', 'a.d. VI Kal. ', 'a.d. VI Kal. ', 'a.d. V Kal. ', 'a.d. VI Kal. ', 'a.d. V Kal. ', 'a.d. VI Kal. ', 'a.d. IV Kal. ' }, { 'a.d. V Kal. ', 'pr. Kal. ', 'a.d. V Kal. ', 'a.d. IV Kal. ', 'a.d. V Kal. ', 'a.d. IV Kal. ', 'a.d. V Kal. ', 'a.d. V Kal. ', 'a.d. IV Kal. ', 'a.d. V Kal. ', 'a.d. IV Kal. ', 'a.d. V Kal. ', 'a.d. III Kal. ' }, { 'a.d. IV Kal. ', {}, 'a.d. IV Kal. ', 'a.d. III Kal. ', 'a.d. IV Kal. ', 'a.d. III Kal. ', 'a.d. IV Kal. ', 'a.d. IV Kal. ', 'a.d. III Kal. ', 'a.d. IV Kal. ', 'a.d. III Kal. ', 'a.d. IV Kal. ', 'pr. Kal. ' }, { 'a.d. III Kal. ', {}, 'a.d. III Kal. ', 'pr. Kal. ', 'a.d. III Kal. ', 'pr. Kal. ', 'a.d. III Kal. ', 'a.d. III Kal. ', 'pr. Kal. ', 'a.d. III Kal. ', 'pr. Kal. ', 'a.d. III Kal. ', {} }, { 'pr. Kal. ', {}, 'pr. Kal. ', {}, 'pr. Kal. ', {}, 'pr. Kal. ', 'pr. Kal. ', {}, 'pr. Kal. ', {}, 'pr. Kal. ', {} } }

	-- if only one argument then not a valid date
    if args[1] == nil then return end
    -- if two arguments then date without year
    if #args[1] == 2 then
        local MonthDay = {tonumber(args[1][1]), tonumber(args[1][2])}
        if MonthDay[1] > 13 then return end
        if MonthDay[1] == 2 and MonthDay[2] > 28 then
            MonthDay[1] = 13
        end
        local day = dayLookup[MonthDay[2]][MonthDay[1]]
        if day == 'Kal. ' then
            return day .. months.ablative[MonthDay[1]]
        elseif day == 'Non. ' then
            return day .. months.ablative[MonthDay[1]]
        elseif day == 'Id. ' then
            return day .. months.ablative[MonthDay[1]]
        else
            if MonthDay[2] > month_ides_lookup(MonthDay[1]) then
                if tonumber(MonthDay[1]) == 12 then
                    return day .. months.accusative[1]
                elseif MonthDay[1] == 13 then
                    return day .. months.accusative[3]
                end
                return day .. months.accusative[MonthDay[1] + 1]
            end
            return day .. months.accusative[MonthDay[1]]
        end
    -- if 3 arguments then date with year-month-day
    elseif #args[1] == 3 then
        local YearMonthDay = {tonumber(args[1][1]), tonumber(args[1][2]), tonumber(args[1][3])}
        MonthDay = {YearMonthDay[2], YearMonthDay[3]}
        if YearMonthDay[1] > 0 then
        	avc = 753
        elseif YearMonthDay[1] < 0 then
        	avc = 754
        end
        if MonthDay[1] > 13 then return end
        if checkLeapYear(YearMonthDay[1]) then
            if YearMonthDay[2] == 2 then
                YearMonthDay[2] = 13
                MonthDay = {13, YearMonthDay[3]}
            end
        else
            if YearMonthDay[2] == 2 and tonumber(YearMonthDay[3]) > 28 then return end
        end
        local day = dayLookup[MonthDay[2]][MonthDay[1]]
        if day == 'Kal. ' then
            return day .. months.ablative[MonthDay[1]] .. ' ' .. numeral.main({YearMonthDay[1]+avc}) .. ' AVC'
        elseif day == 'Non. ' then
            return day .. months.ablative[MonthDay[1]] .. ' ' .. numeral.main({YearMonthDay[1]+avc}) .. ' AVC'
        elseif day == 'Id. ' then
            return day .. months.ablative[MonthDay[1]] .. ' ' .. numeral.main({YearMonthDay[1]+avc}) .. ' AVC'
        else
            if MonthDay[2] > month_ides_lookup(MonthDay[1]) then
                if tonumber(MonthDay[1]) == 12 then
                    return day .. months.accusative[1] .. ' ' .. numeral.main({YearMonthDay[1]+avc}) .. ' AVC'
                elseif MonthDay[1] == 13 then
                    return day .. months.accusative[3] .. ' ' .. numeral.main({YearMonthDay[1]+avc}) .. ' AVC'
                end
                return day .. months.accusative[MonthDay[1] + 1] .. ' ' .. numeral.main({YearMonthDay[1]+avc}) .. ' AVC'
            end
            if tonumber(MonthDay[1]) == 13 then
            	MonthDay[1] = 2
            end
            return day .. months.accusative[MonthDay[1]] .. ' ' .. numeral.main({YearMonthDay[1]+avc}) .. ' AVC'
        end
    else return end

end

function p.main(frame)
	-- If called via #invoke, use the args passed into the invoking
    -- template, or the args passed to #invoke if any exist. Otherwise
    -- assume args are being passed directly in from the debug console
    -- or from another Lua module.
    -- All dates must be passed via ISO 8601 (YYYY-MM-DD) or (MM-DD)
    local origArgs
    if frame == mw.getCurrentFrame() then
    	origArgs = frame:getParent().args
    	for k, v in pairs(frame.args) do
    		origArgs = frame.args
    		break
    	end
    else
    	origArgs = frame['args']
    end
    -- Trim whitespace and remove blank arguments.
    local args = {}
    for k, v in pairs(origArgs) do
        if type( v ) == 'string' then
            v = mw.text.trim(v)
        end
        if v ~= '' then
            args[k] = v
        end
    end
    
    -- exit if not given anything
    if args == nil or args == {} then return end
    
    -- Remove dashes from args to get a table representing {year, month, day}
    if type(args[1]) == 'string' then
        args[1] = mw.text.split(args[1], '%f[^%d]%-')
    end
    return _main(args)
end

return p