Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
You must create an account or log in to edit.

Module:Keppel date: Difference between revisions

From Amaranth Legacy, available at amaranth-legacy.community
Content deleted Content added
No edit summary
No edit summary
Line 5: Line 5:
local yesno = require('Module:Yesno')
local yesno = require('Module:Yesno')


-- year calculations
-- calculations
--- Earth
local function isEarthLeapYear(year)
local function isEarthLeapYear(year)
-- every 4 years
-- every 4 years
Line 14: Line 15:


local function getEarthYearLength(year)
local function getEarthYearLength(year)
-- if it's a leap year, add one day
local yearLength = 365
if isEarthLeapYear(year) then yearLength = yearLength + 1 end
return 365 + (isEarthLeapYear(year) and 1 or 0)
return yearLength
end
end


--- Keppel
local function isLeapYear1(year)
local function isKeppelLeapYearCycle1(year)
-- every 4 years (offset 2)
-- every 4 years (offset 2)
return year % 4 == 2
return year % 4 == 2
end
end


local function isLeapYear2(year)
local function isKeppelLeapYearCycle2(year)
-- every 239 years (offset 65)
-- every 239 years (offset 65)
return year % 239 == 65
return year % 239 == 65
end
end


local function getYearLength(year)
local function getKeppelYearLength(year)
-- if it's a leap year (cycle 1), add one day
local yearLength = 389
-- if it's a leap year (cycle 2), add one day
if isLeapYear1(year) then yearLength = yearLength + 1 end
return 389 + (isKeppelLeapYearCycle1(year) and 1 or 0) + (isKeppelLeapYearCycle2(year) and 1 or 0)
if isLeapYear2(year) then yearLength = yearLength + 1 end
return yearLength
end
end


local function getYdayOffset(earthYear)
local function getKeppelYearOffset(earthYear)
-- if it's an Earth leap year, add one day for February 29
local ydayOffset = 78
-- March 20 (day 78 or 79) is Liliyogh 1 (day 1)
if isEarthLeapYear(earthYear) then ydayOffset = ydayOffset + 1 end -- February 29
return 78 + (isEarthLeapYear(earthYear) and 1 or 0)
return ydayOffset
end
end


local function getKeppelYear(earthYear)
-- lythryds
-- offset of 892 years
return earthYear - 892
end

local function getLythryd(yday)
-- length is 32 days
return math.floor((yday - 1) / 32) + 1
end

local function getKeppelDay(yday)
-- see previous function
return math.floor(yday - 1) % 32 + 1
end

-- data
--- lythryds
local lythryds = {
local lythryds = {
'Liliyogh',
'Liliyogh',
Line 59: Line 75:
}
}


-- ochtdays
--- ochtdays
local ochtdays = {
local ochtdays = {
'Astresday',
'Astresday',
Line 71: Line 87:
}
}


--- sun signs (see [[Seventeen Suns]])
-- https://amaranth-legacy.community/Seventeen_Suns
local sun_signs = {
local sun_signs = {
'[[File:Keppel-astrology-Alcaernon.png|32px|alt=]] Alcaernon',
'[[File:Keppel-astrology-Alcaernon.png|32px|alt=]] Alcaernon',
Line 92: Line 108:
}
}


-- exported functions
-- date converter
function p.convert(time)
function p.convert(time)
-- get the current date
-- extract from time
local date = os.date('*t', time)
local year, yday, hour, min, sec = table.unpack(os.date('*t', time))
-- add the time to yday
-- add the fractional part of the day of year
date.yday = date.yday + (date.hour / 24) + (date.min / (24 * 60)) + (date.sec / (24 * 60 * 60))
yday = yday + (hour / 24) + (min / (24 * 60)) + (sec / (24 * 60 * 60))
-- add the year length to the date table
date.yearLength = getEarthYearLength(date.year)


-- year is Earth year minus 892
-- get the year length
local year = date.year - 892
local yearLength = getEarthYearLength(year)
local yearLength = getYearLength(year)


-- convert years to Keppel years
-- if yday is before the start, it's the previous year
local yday = date.yday - getYdayOffset(date.year)
local keppelYear = getKeppelYear(year)
-- get the Keppel year length
if yday < date.yearLength / yearLength then
local keppelYearLength = getKeppelYearLength(year)
year = year - 1
-- convert day of year to Keppel day of year
yearLength = getYearLength(year)
local keppelYday = yday - getKeppelYearOffset(year)
end


-- if day of year is before the start, use the previous year
-- calculate the yday
if keppelYday < yearLength / keppelYearLength then
yday = (yday / date.yearLength * yearLength - 1) % yearLength + 1
keppelYear = keppelYear - 1
keppelYearLength = getKeppelYearLength(keppelYearLength)
end


-- stretch day of year to the Keppel year
-- a lythryd is 32 days
keppelYday = (keppelYday / yearLength * keppelYearLength - 1) % keppelYearLength + 1
local lythryd = math.floor((yday - 1) / 32) + 1


-- to get the day of the lythryd, subtract the days in previous lythryds
-- get the lythryd
local day = math.floor(yday - 1) % 32 + 1
local lythryd = getLythryd(keppelYday)
-- get the Keppel day

local keppelDay = getKeppelDay(keppelYday)
-- get the time as well
-- get the Keppel time
local ydayTime = select(2, math.modf(yday))
local seconds = select(1, math.modf(ydayTime * 86400))
local keppelYdayFractional = select(2, math.modf(keppelYday))
local minutes = select(1, math.modf(seconds / 60))
local keppelHour = select(1, math.modf(keppelYdayFractional * 24))
local hour = select(1, math.modf(minutes / 60))
local keppelMin = select(1, math.modf(keppelYdayFractional * 24 * 60)) % 60
local keppelSec = select(1, math.modf(keppelYdayFractional * 24 * 60 * 60)) % 60
local minute = minutes % 60
local second = seconds % 60


return {
return {
year = year,
year = keppelYear,
yday = yday,
yday = keppelYday,
lythryd = lythryd,
lythryd = lythryd,
day = day,
day = keppelDay,
hour = hour,
hour = keppelHour,
minute = minute,
min = keppelMin,
second = second
sec = keppelSec
}
}
end
end
Line 142: Line 157:
function p.invoke(frame)
function p.invoke(frame)
local args = getArgs(frame)
local args = getArgs(frame)

-- construct time from args
local time
local time
if args['year'] and args['month'] and args['day'] then
if args['year'] and args['month'] and args['day'] then
Line 149: Line 166:
day = args['day'],
day = args['day'],
hour = args['hour'] or 0,
hour = args['hour'] or 0,
minute = args['minute'] or 0,
min = args['min'] or 0,
second = args['second'] or 0
sec = args['sec'] or 0
}
}
elseif args['time'] then
elseif args['time'] then
Line 166: Line 183:
local args = getArgs(frame)
local args = getArgs(frame)


-- get result
local result = p.invoke(frame)
local result = p.invoke(frame)
local year
-- format result year
result.year = result.year <= 0 and (math.abs(result.year) + 1) .. ' AT' or result.year .. ' LE'
if result.year <= 0 then
year = (math.abs(result.year) + 1) .. ' AT'
else
year = result.year .. ' LE'
end


if yesno(args['year_only'] or false) then
if yesno(args['year_only'] or false) then
Line 187: Line 201:
lythryds[result.lythryd],
lythryds[result.lythryd],
result.day,
result.day,
year
result.year
)
)


Line 203: Line 217:
formatted,
formatted,
result.hour,
result.hour,
result.minute,
result.min,
result.second
result.sec
)
)
end
end

Revision as of 18:02, March 20, 2026

Converts the current (or provided) date to a Keppel date. Used by Template:Keppel date.

Formula

\begin{aligned} y_\oplus &= \text{Earth year} \\ d_\oplus &= \text{Earth day of year (fractional)} \\ d_{\oplus_\text{max}}(y_\oplus) &= \begin{cases} 366 & (y_\oplus = 0 \pmod{4} \text{ and } y_\oplus \neq 0 \pmod{100}) \text{ or } y_\oplus = 0 \pmod{400} \\ 365 & \text{otherwise} \end{cases} \\ \text{offset}(y_\oplus) &= d_{\oplus_\text{max}}(y_\oplus) - 287 \\ d_{\text{K}_\text{max}}(y_\text{K}) &= \begin{cases} 391 & y_\text{K} = 65 \pmod{239} \text{ and } y_\text{K} = 2 \pmod{4} \\ 390 & y_\text{K} = 65 \pmod{239} \text{ or } y_\text{K} = 2 \pmod{4} \\ 389 & \text{otherwise} \end{cases} \\ y_\text{K}(y_\oplus) &= y_\oplus - 892 \\ y_\text{K} &= \begin{cases} y_\text{K}(y_\oplus) & d_\oplus - \text{offset}(y_\oplus) \geq \frac{d_{\oplus_\text{max}}(y_\oplus)}{d_{\text{K}_\text{max}}(y_\text{K}(y_\oplus))} \\ y_\text{K}(y_\oplus) - 1 & d_\oplus - \text{offset}(y_\oplus) < \frac{d_{\oplus_\text{max}}(y_\oplus)}{d_{\text{K}_\text{max}}(y_\text{K}(y_\oplus))} \end{cases} \\ d_\text{K} &= (\frac{d_\oplus - \text{offset}(y_\oplus)}{d_{\oplus_\text{max}}(y_\oplus)} \times d_{\text{K}_\text{max}}(y_\text{K}) - 1) \bmod{d_{\text{K}_\text{max}}(y_\text{K})} + 1 \\ L_\text{K} &= \lfloor \frac{d_\text{K} - 1}{32} \rfloor + 1 \\ d_{\text{K}_L} &= \lfloor (d_\text{K} - 1) \bmod{32} \rfloor + 1 \end{aligned}


local p = {}

-- libraries
local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')

-- calculations
--- Earth
local function isEarthLeapYear(year)
	-- every 4 years
	-- except for every 100 years
	-- except for every 400 years
	return (year % 400 == 0) or (year % 100 ~= 0 and year % 4 == 0)
end

local function getEarthYearLength(year)
	-- if it's a leap year, add one day
	return 365 + (isEarthLeapYear(year) and 1 or 0)
end

--- Keppel
local function isKeppelLeapYearCycle1(year)
	-- every 4 years (offset 2)
	return year % 4 == 2
end

local function isKeppelLeapYearCycle2(year)
	-- every 239 years (offset 65)
	return year % 239 == 65
end

local function getKeppelYearLength(year)
	-- if it's a leap year (cycle 1), add one day
	-- if it's a leap year (cycle 2), add one day
	return 389 + (isKeppelLeapYearCycle1(year) and 1 or 0) + (isKeppelLeapYearCycle2(year) and 1 or 0)
end

local function getKeppelYearOffset(earthYear)
	-- if it's an Earth leap year, add one day for February 29
	-- March 20 (day 78 or 79) is Liliyogh 1 (day 1)
	return 78 + (isEarthLeapYear(earthYear) and 1 or 0)
end

local function getKeppelYear(earthYear)
	-- offset of 892 years
	return earthYear - 892
end

local function getLythryd(yday)
	-- length is 32 days
	return math.floor((yday - 1) / 32) + 1
end

local function getKeppelDay(yday)
	-- see previous function
	return math.floor(yday - 1) % 32 + 1
end

-- data
--- lythryds
local lythryds = {
	'Liliyogh',
	'Avonslau',
	'Bovvilag',
	'Haelaidhe',
	'Gildorne',
	'Auvhlaus',
	'Ludervinn',
	'Glausonn',
	'Yahataidh',
	'Serelakkan',
	'Frosma',
	'Tegeirukk',
	'Intercal'
}

--- ochtdays
local ochtdays = {
	'Astresday',
	'Solsday',
	'Embresday',
	'Jadesday',
	'Ryvysday',
	'Tyrrhsday',
	'Lysisday',
	'Octresday'
}

--- sun signs (see [[Seventeen Suns]])
local sun_signs = {
	'[[File:Keppel-astrology-Alcaernon.png|32px|alt=]] Alcaernon',
	'[[File:Keppel-astrology-Eumrakh.png|32px|alt=]] Eumrakh',
	'[[File:Keppel-astrology-Aureolin.png|32px|alt=]] Aureolin',
	'[[File:Keppel-astrology-Pereptia.png|32px|alt=]] Pereptia',
	'[[File:Keppel-astrology-Sechmas.png|32px|alt=]] Sechmas',
	'[[File:Keppel-astrology-Mananakus.png|32px|alt=]] Mananakus',
	'[[File:Keppel-astrology-Luxor.png|32px|alt=]] Luxor',
	'[[File:Keppel-astrology-Illyre.png|32px|alt=]] Illyre',
	'[[File:Keppel-astrology-Glauryuz.png|32px|alt=]] Glauryuz',
	'[[File:Keppel-astrology-Schismata.png|32px|alt=]] Schismata',
	'[[File:Keppel-astrology-Annrava.png|32px|alt=]] Annrava',
	'[[File:Keppel-astrology-Yahasain.png|32px|alt=]] Yahasain',
	'[[File:Keppel-astrology-Regalion.png|32px|alt=]] Regalion',
	'[[File:Keppel-astrology-Vaalgrota.png|32px|alt=]] Vaalgrota',
	'[[File:Keppel-astrology-Cancrus.png|32px|alt=]] Cancrus',
	'[[File:Keppel-astrology-Eremoor.png|32px|alt=]] Eremoor',
	'[[File:Keppel-astrology-Haerox.png|32px|alt=]] Haerox'
}

-- exported functions
function p.convert(time)
	-- extract from time
	local year, yday, hour, min, sec = table.unpack(os.date('*t', time))
	-- add the fractional part of the day of year
	yday = yday + (hour / 24) + (min / (24 * 60)) + (sec / (24 * 60 * 60))

	-- get the year length
	local yearLength = getEarthYearLength(year)

	-- convert years to Keppel years
	local keppelYear = getKeppelYear(year)
	-- get the Keppel year length
	local keppelYearLength = getKeppelYearLength(year)
	-- convert day of year to Keppel day of year
	local keppelYday = yday - getKeppelYearOffset(year)

	-- if day of year is before the start, use the previous year
	if keppelYday < yearLength / keppelYearLength then
		keppelYear = keppelYear - 1
		keppelYearLength = getKeppelYearLength(keppelYearLength)
	end

	-- stretch day of year to the Keppel year
	keppelYday = (keppelYday / yearLength * keppelYearLength - 1) % keppelYearLength + 1

	-- get the lythryd
	local lythryd = getLythryd(keppelYday)
	-- get the Keppel day
	local keppelDay = getKeppelDay(keppelYday)
	-- get the Keppel time
	local keppelYdayFractional = select(2, math.modf(keppelYday))
	local keppelHour = select(1, math.modf(keppelYdayFractional * 24))
	local keppelMin = select(1, math.modf(keppelYdayFractional * 24 * 60)) % 60
	local keppelSec = select(1, math.modf(keppelYdayFractional * 24 * 60 * 60)) % 60

	return {
		year = keppelYear,
		yday = keppelYday,
		lythryd = lythryd,
		day = keppelDay,
		hour = keppelHour,
		min = keppelMin,
		sec = keppelSec
	}
end

function p.invoke(frame)
	local args = getArgs(frame)

	-- construct time from args
	local time
	if args['year'] and args['month'] and args['day'] then
		time = os.time{
			year = args['year'],
			month = args['month'],
			day = args['day'],
			hour = args['hour'] or 0,
			min = args['min'] or 0,
			sec = args['sec'] or 0
		}
	elseif args['time'] then
		time = args['time']
	elseif args[1] then
		time = args[1]
	else
		time = os.time()
	end

	return p.convert(time)
end

function p.main(frame)
	local args = getArgs(frame)

	-- get result
	local result = p.invoke(frame)
	-- format result year
	result.year = result.year <= 0 and (math.abs(result.year) + 1) .. ' AT' or result.year .. ' LE'

	if yesno(args['year_only'] or false) then
		return year
	elseif yesno(args['month_day_only'] or false) then
		return string.format(
			'%s %d',
			lythryds[result.lythryd],
			result.day
		)
	else
		local formatted = string.format(
			'%s %d, %s',
			lythryds[result.lythryd],
			result.day,
			result.year
		)

		if yesno(args['show_ochtday'] or false) then
			formatted = string.format(
				'%s, %s',
				ochtdays[(result.day - 1) % 8 + 1],
				formatted
			)
		end

		if yesno(args['show_time'] or false) then
			formatted = string.format(
				'%s %02d:%02d:%02d',
				formatted,
				result.hour,
				result.min,
				result.sec
			)
		end

		if yesno(args['show_sun_sign'] or false) then
			formatted = string.format(
				'%s (%s)',
				formatted,
				sun_signs[math.floor(result.yday / 24) + 1]
			)
		end

		return formatted
	end
end

return p