Moduledocumentatie​[bekijk] [bewerk] [ververs] [geschiedenis]

Module voor kalenderberekeningen.

Functies:

Maakt gebruik van:

-- year numbers use ISO 8601 numbering
local p = {}

local BC = " v.Chr."
local AD = ""
local BC_LABEL = " v.C."	-- only used for centuries
local AD_LABEL = " n.C."	-- only used for centuries
local SEP = " · "

local INFOBOX_WIDTH = 'width:' .. mw.getCurrentFrame():expandTemplate{title = 'Infobox/breedte', args = {}} .. 'px;'
local TITLEBARCOLOR = 'background-color:' .. mw.getCurrentFrame():expandTemplate{title = 'Navigatie/titelbalkkleur', args = {}} .. '; color:inherit;'

-- {label, linkPrefix}
-- iedereen wordt uitgenodigd dit lijstje uit te breiden!
local themesTab = {
	{"Lijst van landen", "Lijst van landen in"},
	{"Lijst van staatshoofden en regeringsleiders", "Lijst van staatshoofden en regeringsleiders in"},
	{"Lijst van regeringsleiders van afhankelijke territoria", "Lijst van regeringsleiders van afhankelijke territoria in"},
	{"Geboren", "Lijst van personen geboren in"},
	{"Overleden", "Lijst van personen overleden in"},
	{"Machthebbers", "Machthebbers in"},
	{"Aardbevingen", "Lijst van aardbevingen in"},
	{"Atlantisch orkaanseizoen"},
	{"Orkaanseizoen van de Grote Oceaan"},
	{"Tyfoonseizoen van de Grote Oceaan"},
	{"Wetenschap", "Wetenschap in"},
	{"Auto's", "Europese auto in"}, --hierop staat navigatie naar andere werelddelen
	{"Luchtvaart", "Luchtvaart in"},
	{"Film", "Film in"},
	{"Muziek", "Muziek in"},
	{"Sport", "Sport in"},
	{"Sportkalender"},
	{"Sport (categorie)", ":Categorie:Sport in"},
}

-- lijst van overgangskalenders
-- [jaartal] = {gebiedsnaam 1, gebiedsnaam 2, enz.}
-- gebiedsnamen moeten overeenkomen met wat tussen eventuele haakjes staat in de artikeltitel
local transitionTab = {
	[1582] = {"Zuid-Europa", "Frankrijk", "Brabant, Zeeland", "Zuidelijke Nederlanden"},
	[1583] = {"Holland", "Groningen", "Augsburg", "Trier", "Oostenrijk west", "Gulik-Berg", "Keulen, Aken", "Würzburg", "Mainz", "Münster, Kleef, Baden", "Oostenrijk oost"},
	[1584] = {"Bohemen, Moravië", "katholiek Zwitserland", "Lausitz, Silezië", "Westfalen"},
	[1585] = {"Paderborn"},
	[1587] = {"Hongarije"},
	[1590] = {"Transsylvanië"},
	[1594] = {"Groningen"},
	[1610] = {"Pruisen"},
	[1631] = {"Hildesheim"},
	[1682] = {"Elzas"},
	[1700] = {"Duitsland, Denemarken, Noorwegen", "Gelderland", "Utrecht, Overijssel"},
	[1701] = {"Friesland, Groningen, protestants Zwitserland", "Drenthe"},
	[1710] = {"vasteland van Nova Scotia"},
	[1712] = {"Zweden"},
	[1752] = {"Britse Rijk"},
	[1753] = {"Zweden"},
	[1800] = {"Litouwen"},
	[1867] = {"Alaska"},
	[1912] = {"Albanië"},
	[1915] = {"Litouwen"},
	[1916] = {"Bulgarije"},
	[1918] = {"Estland, Rusland"},
	[1919] = {"Koninkrijk der Serven, Kroaten en Slovenen", "Roemenië"},
	[1923] = {"Griekenland"}
}

-- local functions

local function link(title, label)
	if not label then
		return '[[' .. title .. ']]'
	else
		return '[[' .. title .. '|' .. label .. ']]'
	end
end

local function epoch(year)
	if year > 0 then
		return AD
	else
		return BC
	end
end

local function yearInEpoch(year)
	if year <= 0 then
		year = -year + 1	-- 0 becomes 1 [BC]
	end
	return year
end

local function centuryInEpoch(year)
	return math.floor((yearInEpoch(year) - 1) / 100) + 1
end

local function decade(year)
	return math.floor(yearInEpoch(year) / 10)
end

-- e.g. "22 v.Chr."
local function yearString(year)
	return yearInEpoch(year) .. epoch(year)
end

-- e.g. "[[22 v.Chr.]]"
local function yearLink(year, label)
	local y = yearInEpoch(year)
	if not label and y ~= 1 then
		label = y
	end
	if year <= -999 then
		return label
	else
		return link(y .. epoch(year), label)
	end
end

-- e.g. "29-20 v.Chr."
local function decadeString(year)
	local decade = decade(year)
	local epoch = epoch(year)
	local r
	if epoch == BC then
		if decade == 0 then
			r = "9-1" .. epoch
		else
			r = decade .. "9-" .. decade .. "0" .. epoch
		end
	else
		if decade == 0 then
			r = "1-9" .. epoch
		else
			r = decade .. "0-" .. decade .. "9" .. epoch
		end
	end
	return r	
end

-- e.g. "[[29-20 v.Chr.|29-20]]"
local function decadeLink(year)
	local decade = decade(year)
	local epoch = epoch(year)
	local r
	if epoch == BC then
		if decade == 0 then
			r = link("9-1" .. epoch)
		else
			r = decade .. "9-" .. decade .. "0"
			r = link(r .. epoch, r)
		end
	else
		if decade == 0 then
			r = link("1-9" .. epoch)
		else
			r = decade .. "0-" .. decade .. "9"
			r = link(r .. epoch, r)
		end
	end
	return r	
end

-- e.g. "1e eeuw v.Chr."
local function centuryString(year)
	return centuryInEpoch(year) .. "e eeuw" .. epoch(year)
end

-- e.g. "[[1e eeuw v.Chr.|1e eeuw]]"
local function centuryLink(year, epochLabel)
	local prefix = centuryInEpoch(year) .. "e eeuw"
	local title = prefix .. epoch(year)
	local label
	if epochLabel then
		label = prefix .. epochLabel
	end
	return link(title, label)
end

local function bc(year)
	return -year + 1
end

-- convert text to ISO year number
local function yearNumber(yearStr)
    local i = mw.ustring.find(yearStr, BC, 1, true)
    local r
    if i then
    	r = bc(mw.ustring.sub(yearStr, 1, i))
    else
    	r = tonumber(yearStr)
    end
    return r
end

local function centuries(year)
	local r
	if centuryInEpoch(year) == 1 then
		if epoch(year) == BC then
			r = centuryLink(-150, '')       .. SEP .. "'''" ..
				centuryLink( -50, BC_LABEL) .. "'''" .. SEP ..
				centuryLink(  50, AD_LABEL)
		else
			r = centuryLink(-50, BC_LABEL) .. SEP .. "'''" ..
				centuryLink( 50, AD_LABEL) .. "'''" .. SEP ..
				centuryLink(150, '')
		end
	else
		r = ''
		local first = -1
		local last = 1
		for co = first, last do
			local cl = centuryLink(year + co * 100, '')
			if (co == 0) then
				r = r .. "'''" .. cl .. "'''"
			else
				r = r .. cl
			end
			if (co ~= last) then
				r = r .. SEP
			end
		end
	end
	return r
end

local function decades(year)
	local first = -1
	local last = 1
	local r = ''
	for offset = first, last do
		local f
		if (year >= bc(9) and year <= 9) and (offset == 1 or offset == -1) then
			f = 9
		else
			f = 10
		end
		local ds = decadeLink(year + offset * f)
		if (offset == 0) then
			r = r .. "'''" .. ds .. "'''"
		else
			r = r .. ds
		end
		if (offset ~= last) then
			r = r .. SEP
		end
	end
	return r
end

local function years(year)
	local first = -3;
	local last = 3;
	local r = ''
	for yo = first, last do
		local label
		if (yo == first) then
			label = "<<"
		elseif (yo == first + 1) then
			label = "<"
		elseif (yo == last - 1) then
			label = ">"
		elseif (yo == last) then
			label = ">>"
		end
		local yl = yearLink(year + yo, label);
		if (yo == 0) then
			r = r .. "'''" .. yl .. "'''"
		else
			r = r .. yl
		end
		if (yo ~= last) then
			r = r .. SEP
		end
	end
	return r
end

local monthName = {'januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december'}
local monthAbbr = {'jan', 'feb', 'mrt', 'apr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'}
local function months(year)
	if year >= 1900 and year <= tonumber(os.date("%Y")) then
		local r = ""
		for i = 1, 12 do
			r = r .. link(monthName[i] .. ' ' .. year, monthAbbr[i])
			if i == 6 then
				r = r .. ' <br />'
			elseif i ~= 12 then
				r = r .. ' · '
			end
		end
		return r
	end
end

local function duo(year, offset)
	if year > offset then
		return (year - offset) .. " – " .. (year - offset + 1)
	elseif year == offset then
		return 1
	end
end

-- for Roman and Armenian numerals
local function nonPositionalDigit(tab, year, div)
	if year < div then
		return ''
	end
	return tab[math.floor(year / div) % (#tab + 1)] or ''
end

-- for Eastern Arabic and Arabic-Indian numerals
local function positionalDigit(zero, year)
	year = tostring(year)
	local r = ""
	for i = 1, #year do
		r = r .. mw.ustring.char(string.byte(year, i) + zero - 0x30)	-- maakt gebruik van Unicode-codepoints
	end
	return r
end

local function duoPositionalDigit(zero, year, offset)
	if year > offset then
		return "<br />" .. positionalDigit(zero, year - offset) .. " – " .. positionalDigit(zero, year - offset + 1)
	elseif year == offset then
		return " " .. positionalDigit(zero, 1)
	end
end

local ro4 = {'M', 'MM', 'MMM', 'MMMM'}									-- thousands
local ro3 = {'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM'}	-- hundreds
local ro2 = {'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'} 	-- tens
local ro1 = {'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'}	-- ones
local function romanNumeral(i)
	if i > 0 and i < 5000 then
		local ro =
			nonPositionalDigit(ro4, i, 1000) ..
			nonPositionalDigit(ro3, i,  100) ..
			nonPositionalDigit(ro2, i,   10) ..
			nonPositionalDigit(ro1, i,    1)
		return ro
	end
end

-- Ab urbe condita
local function auc(year)
	if year > bc(754) then
		year = year + 753
		return year .. " '''" .. romanNumeral(year) .. "'''"
	end
end

local ar5 = {'Օ', 'Ֆ'}										-- ten-thousands
local ar4 = {'Ռ', 'Ս', 'Վ', 'Տ', 'Ր', 'Ց', 'Ւ', 'Փ', 'Ք'}	-- thousands
local ar3 = {'Ճ', 'Մ', 'Յ', 'Ն', 'Շ', 'Ո', 'Չ', 'Պ', 'Ջ'}	-- hundreds
local ar2 = {'Ժ', 'Ի', 'Լ', 'Խ', 'Ծ', 'Կ', 'Հ', 'Ձ', 'Ղ'}	-- tens
local ar1 = {'Ա', 'Բ', 'Գ', 'Դ', 'Ե', 'Զ', 'Է', 'Ը', 'Թ'}	-- ones
local function ak(year)
	if year > 0 and year < 30000 then
		return nonPositionalDigit(ar5, year, 10000) ..
			   nonPositionalDigit(ar4, year,  1000) ..
			   nonPositionalDigit(ar3, year,   100) ..
			   nonPositionalDigit(ar2, year,    10) ..
			   nonPositionalDigit(ar1, year,     1)
	end
end
local function armenian(year)
	year1 = math.floor((math.floor(year * 0.25 - 0.25) - math.floor(year * 0.01 - 0.01) + math.floor(year * 0.0025 - 0.0025)) / 365 + year - 551.8958904)
	year2 = math.floor((math.floor(year * 0.25)		   - math.floor(year * 0.01)		+ math.floor(year * 0.0025))		  / 365 + year - 550.8986301)
	if year1 > 0 and year1 ~= year2 then
		return year1 .. " – " .. year2 .. "<br /><small>''ԹՎ " .. ak(year1) .. " – " .. ak(year2) .. "''</small>"
	elseif year1 > 0 then
		return year1 .. " <small>''ԹՎ " .. ak(year1) .. "''</small>"
	elseif year1 == 0 then
		return year2 .. " <small>''ԹՎ " .. ak(year2) .. "''</small>"
	end
end

local cn10 = {'庚', '辛', '壬', '癸', '甲', '乙', '丙', '丁', '戊', '己'}
local cn12 = {'亥', '子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌'}
local function chinese(year)
	year = year + 2696
	return year .. ' – ' .. (year + 1) .. "<br />" .. link('Chinese astrologie', 
		cn10[ year      % 10 + 1] .. cn12[ year      % 12 + 1] .. ' – ' .. 
		cn10[(year + 1) % 10 + 1] .. cn12[(year + 1) % 12 + 1])
end

local function christian(year, gregcal)
	if year > 0 then
		local r
		if gregcal then
			r = link(gregcal, year)
		else
			r = tostring(year)
		end
		return r .. " '''" .. romanNumeral(year) .. "'''"
	end
end

local function ethiopian(year)
	return duo(year, 8)
end

local function hebrew(year)
	return duo(year, -3760)
end

local function vikram(year)
	return duo(year, -55)
end

local function shaka(year)
	return duo(year, 78)
end

local function kali(year)
	return duo(year, -3101)
end

local ir = 0x6f0 -- U+06F0 EXTENDED ARABIC-INDIC DIGIT ZERO
local function iranian(year)
	if year >= 622 then
		return duo(year, 622) .. duoPositionalDigit(ir, year, 622)
	end
end

local ar = 0x660 -- U+0660 ARABIC-INDIC DIGIT ZERO
local function islamic(year)
	local year1 = math.floor( 1.030684 * ( year - 621.5643 ) )
	local year2 = math.floor( 1.030684 * ( year - 621.5643 + 1 ) )
	if year > 622 then
		return year1 .. " – " .. year2 .. "<br />" .. positionalDigit(ar, year2) .. " – " .. positionalDigit(ar, year1) -- Oost-Arabische cijfers omgedraaid zodat dit visueel overeenkomt met West-Arabische cijfers erboven
	elseif year == 622 then
		return "1 ١"
	end
end

local function masonic(year)
	return duo(year, -3999)
end

local function themes(year)
	local r = ""
	for i = 1, #themesTab do
		local label = themesTab[i][1]
		local prefix = themesTab[i][2]
		local title = (prefix or label) .. ' ' .. year
		if mw.title.new(title).exists then
			r = r .. '|-\n|colspan="3"|' .. link(title, label) .. '\n'
		end
	end
	return r
end

local weekday = {'zon', 'maan', 'dins', 'woens', 'donder', 'vrij', 'zater'}
local CAL_ICON = '[[Bestand:Crystal Clear mimetype vcalendar.png|40px]]'
local function julianCalendar(year)
	if year > 3 and year < 1923 then
		local v
		if year % 4 == 0 then
			v = 'schrikkel'
		else
			v = 'gewoon '
		end
		local wd = weekday[(3 + math.floor((year + 1) * 5 / 4 + 0.5)) % 7 + 1]
		local title = 'kalender van een ' .. v .. 'jaar dat op ' .. wd .. 'dag begint'
		local label = 'Juliaanse kalender van ' .. year
		return CAL_ICON .. " '''" .. link(title, label) .. "'''"
	end
end

local function transitionCalendar(year)
	local r = ""
	if transitionTab[year] then
		if table.maxn(transitionTab[year]) == 1 then
			r = link('Overgangskalender van ' .. year, transitionTab[year][1])
		elseif table.maxn(transitionTab[year]) > 1 then
			for i = 1, table.maxn(transitionTab[year]) do
				r = r .. link('Overgangskalender van ' .. year .. ' (' .. transitionTab[year][i] .. ')', transitionTab[year][i])
				if i ~= table.maxn(transitionTab[year]) then
					r = r .. ' · '
				end
			end
		end
	end
	if year > 1699 and year < 1712 then
		if r ~= "" then
			r = r .. ' · '
		end
		if year % 4 == 0 and year ~= 1700 then
			v = 'schrikkel'
		else
			v = 'gewoon '
		end
		local i
		if year == 1700 then
			i = 3
		else
			i = 2
		end
		local wd = weekday[(i + math.floor((year + 1) * 5 / 4 + 0.5)) % 7 + 1]
		r = r .. link('kalender van een ' .. v .. 'jaar dat op ' .. wd .. 'dag begint', 'Zweden')
	end
	return r
end

local function gregorianCalendar(year)
	if year > 1582 then
		local v
		if (year % 4)==0 and ((year % 100)~=0 or (year % 400)==0) then
			v = 'schrikkel'
		else
			v = 'gewoon '
		end
		local wd = weekday[(math.floor((year - 1) / 400) - math.floor((year - 1) / 100) + math.floor((year + 1) * 5 / 4 - 1.5)) % 7 + 1]
		local title = 'kalender van een ' .. v .. 'jaar dat op ' .. wd .. 'dag begint'
		local label = 'Gregoriaanse kalender van ' .. year
		return CAL_ICON .. " '''" .. link(title, label) .. "'''"
	end
end

local function row12(left, right, style)
	local r = '|-'
	if style then
		r = r .. ' style="' .. style .. ';"\n'
	else
		r = r .. '\n'
	end
	r = r .. '| align="right" | ' .. "<small>'''" .. left .. "'''</small>\n"
	r = r .. '| align="center" colspan="2" | ' .. right .. '\n'
	return r
end

local function row21(left, right, cellStyle)
	local cellArgs = 'style="' .. cellStyle .. '"'
	local r = '|- valign="top"\n'
	r = r .. '| ' .. cellArgs .. ' colspan="2" | ' .. left .. '\n'
	r = r .. '| ' .. cellArgs .. ' | ' .. right .. '\n'
	return r
end

local function row21a(left, right)
	return row21(left, right, 'border-top:solid 1px #ccd2d9; padding:0.4em 1em 0.4em 0;')
end

local function row21b(left, right)
	return row21(left, right, 'padding:0 1em 0 0;')
end

local function row3(text)
	return '|-\n| style="' .. TITLEBARCOLOR .. '" colspan="3" align="center" | ' .. text .. '\n'
end

local function zijbalk_jaar(yearStr, year, epo1, epo2)
	local r
	
	-- start table
	r = '{| class="toccolours vatop" border="0" cellpadding="2" cellspacing="0" ' .. 
		'align="right" style="margin:0 0 1em 2em; clear:right; font-size:90%; ' ..
		INFOBOX_WIDTH .. '\n'
	
	-- heading
	r = r .. '| style="' .. TITLEBARCOLOR .. '" colspan="3" align="center" | ' ..
		"<big>'''" .. yearInEpoch(year)
	if year <= bc(1) then
		r = r .. " voor Christus"
	end
	r = r .. "'''</big>\n"
	
	-- set width
	-- zo wordt de 2e kolom breder en komt de 1e kolom niet in de verdrukking
	r = r .. '|-\n|\n|width="90px" |\n|\n'
	
	-- navigation
	r = r .. row12('[[Lijst van eeuwen|Eeuwen]]:', centuries(year)) ..
		row12('[[Lijst van decennia|Decennia]]:', decades(year)) ..
		row12('Jaren:', years(year))
	local s
	s = months(year)
	if s then
		r = r .. row12('Maanden:', s)
	end
	
	-- conversion
	r = r .. row3("[[Bestand:Calendar-nl.svg]] '''Jaartelling in verschillende culturen'''") ..
		'|-\n|\n'
	-- vanaf hier moest eigenlijk uitklapbaar, maar dat heb ik nog niet aan de praat gekregen
	
	s = auc(year)
	if s then
		r = r .. row21a('[[Ab urbe condita (jaartelling)|Ab urbe condita]]:', s)
	end
	
	s = armenian(year)
	if s then
		r = r .. row21a('[[Armeense kalender|Armeense jaartelling]]:', s)
	end
	
	if epo1 and #epo1 > 0 then
		r = r .. '|- valign="top"\n' ..
			'| style="border-top:solid 1px #ccd2d9; padding:0.4em 1em 0.4em 0;" colspan="3" | [[Eponiemenlijsten|Assyrisch eponiem]]:\n' ..
			'|-\n' ..
			'| style="padding:0.4em 1em 0.4em 0; text-align:right;" colspan="3" | ' .. epo1
		if epo2 and #epo2 > 0 then
			r = r .. '<br />' .. epo2 .. '\n'
		end
	end
	
	s = chinese(year)
	if s then
		r = r .. row21a('[[Chinese kalender|Chinese jaartelling]]:', s)
	end
	
	s = christian(year)
	if s then
		r = r .. row21a('[[Christelijke jaartelling]]:', s)
	end
	
	s = ethiopian(year)
	if s then
		r = r .. row21a('[[Ethiopische kalender|Ethiopische jaartelling]]:', s)
	end
	
	s = hebrew(year)
	if s then
		r = r .. row21a('[[Joodse kalender|Hebreeuwse jaartelling]]:', s)
	end
	
	local hv = vikram(year)
	local hs = shaka(year)
	local hk = kali(year)
	if hv or hs or hk then
		r = r .. row21a('[[Hindoekalender]]s:', '')
		if hv then
			r = r .. row21b("- ''[[Vikram Samvat]]''", hv)
		end
		if hs then
			r = r .. row21b("- ''[[Indiase kalender|Shaka Samvat]]''", hs)
		end
		if hk then
			r = r .. row21b("- ''[[Kali yuga]]''", hk)
		end
	end
	
	s = iranian(year)
	if s then
		r = r .. row21a('[[Iraanse kalender|Iraanse jaartelling]]:', s)
	end
	
	s = islamic(year)
	if s then
		r = r .. row21a('[[Islamitische kalender|Islamitische jaartelling]]:', s)
	end
	
	s = masonic(year)
	if s then
		r = r .. row21a('[[Maçonnieke kalender|Maçonnieke jaartelling]]:', s)
	end
	
	-- XXX footnotes unused
	
	-- subjects by year
	s = themes(yearStr)
	if s and s ~= "" then
		r = r .. row3("[[Bestand:Nuvola apps kuser.svg|25px]] '''" .. 
			yearStr .. " naar onderwerp''' [[Bestand:Gnome-globe.svg|25px]]") .. s
	end
	
	-- calendars
	s = julianCalendar(year)
	if s then
		r = r .. row3(s)
	end
	s = transitionCalendar(year)
	if s and s ~= "" then
		r = r .. row3('Overgangskalenders:') .. row3("'''" .. s .. "'''")
	end
	s = gregorianCalendar(year)
	if s then
		r = r .. row3(s)
	end
	
	-- terminate table
	r = r .. '|}'
	return r
end


-- exported functions

-- argument is a year string, e.g. "22 v.Chr."
function p.zijbalk_jaar(frame)
	frame = frame:getParent()	-- intended to be called via a template
	
    local yearStr = frame.args[1]
    if not yearStr or #yearStr == 0 then
    	yearStr = tostring(mw.title.getCurrentTitle())
    end
    local yearNum = yearNumber(yearStr)
    if yearNum then
		local epo1 = frame.args['epo1']
		local epo2 = frame.args['epo2']
    	return zijbalk_jaar(yearStr, yearNum, epo1, epo2)
    else
    	return frame:expandTemplate{title='Error', args = {'Fout: ongeldig jaar: ' .. yearStr}}
	end
end

return p