Вычисляет и отображает даты рождения и смерти из Викиданных с поддержкой отображения дат по старому стилю, если в Викиданных указана модель пролептического юлианского календаря (d:Q1985786).


local moduleDates = require( "Module:Dates" )

function deepcopy(orig)
    local orig_type = type(orig)
    local copy
    if orig_type == 'table' then
        copy = {}
        for orig_key, orig_value in next, orig, nil do
            copy[deepcopy(orig_key)] = deepcopy(orig_value)
        end
        setmetatable(copy, deepcopy(getmetatable(orig)))
    else -- number, string, boolean, etc
        copy = orig
    end
    return copy
end

function formatDate( value, infoclass, categoryPrefix, unknownCategory )
	if value.unknown == 'novalue' then
		return ''
	elseif value.unknown == 'unknown' then
		local result = "''биллибэт''"
		if ( unknownCategory ) then
			result = result .. "[[" .. unknownCategory.. "]]"
		end
		return result
	end

	-- year only
	if value.precision == 9 then
		local tCopy = deepcopy( value.structure )
		tCopy.day = nil
		tCopy.month = nil
		return moduleDates.formatWikiImpl(tCopy, tCopy, infoclass, categoryPrefix)
	end
	-- year and month only
	if value.precision == 10 then
		local tCopy = deepcopy( value.structure )
		tCopy.day = nil
		return moduleDates.formatWikiImpl(tCopy, tCopy, infoclass, categoryPrefix)
	end

	if (value.calendarmodel == 'gregorian') then
    	return moduleDates.formatWikiImpl( value.structure, value.structure, infocardClass, categoryPrefix )
    else
		return moduleDates.formatWiki( value.time, infoclass, categoryPrefix )
	end
end

-- accepts table of time+precision values
function ageCurrent ( bTable )
	local possibleAge = "NYA" -- it meansm "Not Yet Assigned", not what you imagined!

	for bKey, bValue in pairs(bTable) do
		if ( bValue.unknown ) then
			return nil
		end
		local bStructure = bValue.structure
		local bPrecision = bValue.precision

		local dStructure = os.date( "*t" )

		local calculatedAge = ageImpl ( bStructure, bPrecision, dStructure, 11 )
		if ( possibleAge == "NYA" ) then
			possibleAge = calculatedAge
		else
			if ( possibleAge ~= calculatedAge ) then
				possibleAge = nil
			end
		end
	end

	return possibleAge
end

-- accepts tables of time+precision values
function age ( bTable, dTable )
	local possibleAge = "NYA" -- it meansm "Not Yet Assigned", not what you imagined!

	for bKey, bValue in pairs( bTable ) do
		if ( bValue.unknown ) then
			return nil
		end
		local bStructure = bValue.structure
		local bPrecision = bValue.precision

		for dKey, dValue in pairs( dTable ) do
			if ( dValue.unknown ) then
				return nil
			end
			local dStructure = dValue.structure
			local dPrecision = dValue.precision

			local calculatedAge = ageImpl ( bStructure, bPrecision, dStructure, dPrecision )
			if ( possibleAge == "NYA" ) then
				possibleAge = calculatedAge
			else
				if ( possibleAge ~= calculatedAge ) then
					possibleAge = nil
				end
			end
		end
	end

	return possibleAge
end

function ageImpl ( bStructure, bPrecision, dStructure, dPrecision )
	if ( not bStructure or not dStructure or bPrecision < 10 or dPrecision < 10 ) then
		return nil
	end

 	if ( bPrecision == 10 or dPrecision == 10 ) then
 		if ( bStructure.month < dStructure.month ) then
 			return dStructure.year - bStructure.year
 		end
 		if ( bStructure.month == dStructure.month ) then
 			return nil
 		end
 		if ( bStructure.month > dStructure.month ) then
 			return dStructure.year - bStructure.year - 1
 		end
 	end
 
  	if ( bStructure.month < dStructure.month ) then
 		return dStructure.year - bStructure.year
 	end
 	if ( bStructure.month == dStructure.month ) then
	  	if ( bStructure.day <= dStructure.day ) then
	 		return dStructure.year - bStructure.year
	 	else 
	 		return dStructure.year - bStructure.year - 1
 		end
 	end
 	if ( bStructure.month > dStructure.month ) then
 		return dStructure.year - bStructure.year - 1
 	end

	return nil
end

-- returns table of time+precision values for specified property
function parseProperty ( propertyName )
	local entity = mw.wikibase.getEntityObject()
	if not entity or not entity.claims or not entity.claims[propertyName] then
		return nil
	end

	local result = {}
	for key, value in pairs( entity.claims[propertyName] ) do
		if ( value.mainsnak.snaktype == "value" ) then
			-- The calendar model used for saving the data is always the proleptic Gregorian calendar according to ISO 8601.
			local timeISO6801 = tostring( value.mainsnak.datavalue.value.time )
			local unixtime = moduleDates.parseISO8601( timeISO6801 )
			local structure = os.date("*t", unixtime)
			local precision = tonumber( value.mainsnak.datavalue.value.precision )
			local calendarmodel = 'gregorian';
			if (mw.ustring.find(value.mainsnak.datavalue.value.calendarmodel, 'Q1985786', 1, true)) then
				calendarmodel = 'julian';
			end
			local item = { time=unixtime, structure=structure, precision=precision, calendarmodel=calendarmodel }
			table.insert ( result, item )
		elseif ( value.mainsnak.snaktype == "somevalue" ) then
			--unknown 
			local item = { unknown="unknown" }
			table.insert ( result, item )
		elseif ( value.mainsnak.snaktype == "novalue" ) then
			-- novalue
			local item = { unknown="novalue" }
			table.insert ( result, item )
		end
	end
	return result
end

-- проверка на совпадающие даты с разной моделью календаря
function checkDupDates( t )
	if #t > 1 then
		local removed = false;
		local j = 1;
		-- проверка на совпадающие даты с разной моделью календаря
		while (j <= #t)  do
			local i = 1;
			while (i <= #t)  do
				if i ~= j then
					if (os.time(t[j].structure) == os.time(t[i].structure)) then
						if ((t[j].calendarmodel == 'gregorian') and 
							(t[i].calendarmodel == 'julian')) then
							removed = true;
							break;
						else
							table.remove(t, i)
						end
					else
					  i = i + 1;
					end
				else
					i = i + 1;
				end
			end
			if removed then
				removed = false;
				table.remove(t, j);
			else
				j = j+1;
			end
		end
	end
end

local p = {}

function p.dateOfBirth( )
    local appendToCategory = mw.title.getCurrentTitle():inNamespace ( 0 )

	local bTable = parseProperty ( "p569" )
	local dTable = parseProperty ( "p570" )

	if not bTable then
		return ''
	end
    checkDupDates(bTable);
	
	local result = ''
	for key, value in pairs(bTable) do
		if result ~= '' then
			result = result .. ' эбэтэр '
		end
		if ( appendToCategory ) then
			result = result .. formatDate(value, 'bday', 'Төрөөбүттэр ', 'Категория:Төрөөбүт күннэрэ быһаарыллыбатах дьон')
		else
			result = result .. formatDate(value, 'bday', nil, nil )
		end
	end

	if ( not dTable ) then
		local age = ageCurrent( bTable )
		if ( age ) then
			result = result .. ' <span style="white-space:nowrap;">(' .. age .. ' ' .. mw.language.new( 'ru' ):plural( age, 'сааһа', 'сааһа', 'сааһа') .. ')</span>'
		    if ( age > 150 and appendToCategory ) then
		        result = result .. '[[Категория:Бикипиэдьийэ:Статьи о персоналиях с большим текущим возрастом]]'
		    end
		end
	end

	return result
end

function p.dateOfDeath( )
    local appendToCategory = mw.title.getCurrentTitle():inNamespace ( 0 )

	local bTable = parseProperty ( "p569" )
	local dTable = parseProperty ( "p570" )

	if not dTable then
		return ''
	end
	checkDupDates(dTable);

	local result = ''
	for key, value in pairs( dTable ) do
		if result ~= '' then
			result = result .. ' эбэтэр '
		end
		if ( appendToCategory ) then
			result = result .. formatDate(value, 'dday', 'Өлбүттэр ', 'Категория:Өлбүт күннэрэ быһаарыллыбатах дьон')
		else
			result = result .. formatDate(value, 'dday', nil, nil )
		end
	end

	if ( bTable and dTable ) then
		local age = age( bTable, dTable )
		if ( age ) then
			result = result .. ' <span style="white-space:nowrap;">(' .. age .. ' ' .. mw.language.new( 'ru' ):plural( age, 'сааһыгар', 'сааһыгар', 'сааһыгар') .. ')</span>'
		    if ( age > 150 and appendToCategory ) then
		        result = result .. '[[Категория:Бикипиэдьийэ:Статьи о персоналиях с большим возрастом во время смерти]]'
		    end
		end
	end

	return result
end

return p