Module:Calendar/adirni

From Nguhcraft Wiki
Revision as of 09:21, 23 May 2026 by Cinthyr (talk | contribs) (todo: month names)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

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

-- if editing this file to fix an error, please keep the maximum line length to
-- strictly 80 characters, even in comments; I edit on small terminals often

local calendar = {}

local equinoxes = require "Module:Calendar/data/equinox_northwards"

local weekdays = {[0] = 1, 2, 3, 4, 5, 6, 7, 1}
-- 1/1/63374 was on odumso; this is pretty much arbitrary

local month_names = {
    en = {'Rebirth', 'Blooming', 'Month 3', 'Month 4', 'Month 5',
        'Month 6', 'Month 7', 'Month 8', 'Month 9', 'Freezing',
        'Darkness', 'Month 12', 'Lanterns', 'Unveiling'},
    ad_latin = {'1', 'Ḑekḑiņț', '3', '4', '5',
    	'6', '7', '8', '9', '10',
    	'11', '12', '13', '14'}
}

local day_names = {
    en = {'Odumso', 'Dénéso', 'Koșțîșo', 'Malîso', 'Mahnés', 'Heņșîșo',
        'Ursnés'},
    ad_latin = {'Odumso', 'Dénéso', 'Koșțîșo', 'Malîso', 'Mahnés', 'Heņșîșo',
        'Ursnés'},
    ad_latin_short = {'I', 'De', 'Ko', 'Na', 'Ma', 'He', 'U'}
}

local function equinox_date(year)
	local datetime = equinoxes[year - 1451]
	-- this would be so much easier if it was indexed with the year

	if not datetime then
		error("northward equinox data for the year " .. year .. " doesn't exist")
	end
	assert(datetime.year == year)
	return datetime.hour >= 6 and datetime.day or (datetime.day - 1)
end

local function o(n)
	-- this exists because %o returns *unsigned* octal, which breaks with negative
	-- years (year -1 is outputted as 1777777777777777777777)
	-- with the current breadth of equinox data, though, this probably won't be a
	-- practical issue
	if n >= 0 then
    	return string.format("%o", n)
    else
        return string.format("-%o", n)
    end
end

local function melting_length(year)
    local gyear = year - 61408 + 1
    -- what gregorian year does february happen in?
    local gleap = (gyear % 4 == 0 and gyear % 100 ~= 0) or gyear % 400 == 0
    local delta = equinox_date(gyear) - equinox_date(gyear - 1)
    -- difference between equinox dates
    
	return gleap and 21 + delta or 20 + delta
end

local function year_len(year)
    return 345 + melting_length(year)
end

local function month_len(month, year)
	if month == 1 or month == 4 or month == 6 or month == 9 or month == 11
    	or month == 13 then
    	return 26
	elseif month == 2 or month == 3 or month == 5 or month == 7 or month == 8
    	or month == 10 or month == 12 then
    	return 27
	elseif month == 14 then return melting_length(year)
	else error(tostring(month) ..  "is not a valid Adirni month")
	end
end

calendar.from = function(date_info)
    assert(date_info.year and date_info.month and date_info.day)

    local date = 78
    -- we choose the fixed point to be the northwards equinox of 1970,
    -- which was 21 March; this is the new year of 63374.
    -- 21/03/1970 has datestamp 79, but the equinox time is before 06:00 utc,
    -- so the actual date in the Adirni calendar is one day earlier.

    if date_info.year >= 63374 then
        local y = date_info.year
        while y > 63374 do
            y = y - 1
            date = date + year_len(y)
        end
        local m = date_info.month
        while m > 1 do
            m = m - 1
			date = date + month_len(m, date_info.year)
        end
        date = date + date_info.day - 1
    else
        date = date - (1 + month_len(date_info.month, date_info.year)
        	- date_info.day)
        local m = date_info.month + 1
        local y = date_info.year
        while m <= 14 do
            date = date - month_len(m, y)
            m = m + 1
        end
        while y < 63374 do
            date = date - year_len(y)
            y = y + 1
        end
    end
    return date
end

calendar.to = function(datestamp)
    local dow = weekdays[datestamp % 7]
    local y, m, d = 63374, 1, 1

    datestamp = datestamp - 78
    if datestamp >= 0 then
        while datestamp > year_len(y) do
            datestamp = datestamp - year_len(y)
            y = y + 1
        end
        while datestamp > month_len(m, y) do
            datestamp = datestamp - month_len(m, y)
            m = m + 1
        end
        d = d + datestamp
    else
        y, m, d = 63373, 14, 20
        -- the 1969 equinox was on 20/3, while the 1970 equinox was on 21/3
        -- but before 06:00, so the year 63373 is the ordinary 365 days long.
        datestamp = -(datestamp + 1)
        while datestamp >= year_len(y) do
            datestamp = datestamp - year_len(y);
            y = y - 1
        end
        while datestamp >= month_len(m, y) do
            datestamp = datestamp - month_len(m, y)
            m = m - 1
            d = month_len(m, y)
        end
        d = d - datestamp
    end

    return {year = y, month = m, day = d, weekday = dow}
end

calendar.to_formatted = function(datestamp, opts)
    -- en: Ursnés 10 Ḑekḑiņț 63430
    -- ad-latin: Ursnés 12 Ḑekḑiņț 173706
    -- ad: 12 ... 173706
    opts = opts or
    	{style = "ad-latin", short = false}

    local date = calendar.to(datestamp)
    return string.format("%s %s %s %s", day_names.en[date.weekday],
    	date.day, month_names.en[date.month], date.year)
end

return calendar