Məzmuna keç

Modul:Wikidata/date

Vikipediya, azad ensiklopediya
Sənədləşdirmə

Vikiverilənlərdən doğum və vəfat tarixlərini götürmək üçün istifadə olunan modul.

  • p.dateOfBirth ← {{wikidata/p569}}
  • p.dateOfDeath ← {{wikidata/p570}}
-- Vikidata tarixlərinin nizamlanması

local nowLabel = '<abbr class="abbr" title="hal-hazırda">h.&nbsp;h.</abbr>'
local abbrbc = '<abbr class="abbr" title="eradan əvvəl">e.&nbsp;ə.</abbr>'

local moduleDates = require( "Modul:Dates" )
local Qualifiers = require( 'Module:Wikidata/qualifiers' )
local moduleWikidata = require( "Modul:Wikidata" )
local Ordinal = require( "Modul:Ordinal" )
local moduleRoman = require( "Modul:RomanNumber" )
local dateCat = require("Modul:Infocards/dateCat")
local annotationSequence = 0

local 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
		copy = orig
	end
	return copy
end

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

	local shift = 0
	if ( bStructure.year < 0 and dStructure.year > 0 ) then
		shift = -1
	end

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

	return nil
end

local function ageCurrent ( bTable )
	local possibleAge = "NYA"

	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

local function age ( bTable, dTable )
	local possibleAge = "NYA"

	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
			if ( bValue.calendar == 'julian' and dValue.calendar == 'gregorian' ) then
				local shift = math.floor(bStructure.year/100-2) - math.floor(bStructure.year/400)
				bStructure.day = bStructure.day + shift
			end

			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

local function lastDayOfMonth(y, m)
	return tonumber(os.date("*t", os.time{ year = y, month = m + 1, day = 0 }).day)
end

local function makeBoundsFromPrecision(structure, precision)
	if not structure or not precision or precision < 9 then
		return nil, nil
	end
	local earliest = deepcopy(structure)
	local latest   = deepcopy(structure)

	if precision == 9 then
		earliest.month, earliest.day = 1, 1
		latest.month,   latest.day   = 12, 31
	elseif precision == 10 then
		earliest.day = 1
		latest.day   = lastDayOfMonth(latest.year, latest.month)
	end

	return earliest, latest
end

local function mergeBoundsFromTable(t)
	if not t or #t == 0 then return nil, nil end
	local globalEarliest, globalLatest = nil, nil
	for _, v in ipairs(t) do
		if v.unknown then return nil, nil end
		local e, l = makeBoundsFromPrecision(v.structure, v.precision)
		if not e then return nil, nil end
		if not globalEarliest or os.time(e) < os.time(globalEarliest) then globalEarliest = e end
		if not globalLatest   or os.time(l) > os.time(globalLatest)   then globalLatest   = l end
	end
	return globalEarliest, globalLatest
end

local function ageBetween(bEarliest, bLatest, dEarliest, dLatest)
	local minAge = ageImpl(bLatest, 11, dEarliest, 11)
	local maxAge = ageImpl(bEarliest, 11, dLatest, 11)
	return minAge, maxAge
end

local function ageRange(bTable, dTable)
	local bE, bL = mergeBoundsFromTable(bTable)
	local dE, dL = mergeBoundsFromTable(dTable)
	if not bE or not dE then return nil end
	local minAge, maxAge = ageBetween(bE, bL, dE, dL)
	if not minAge or not maxAge then return nil end
	return minAge, maxAge
end

local function ageRangeCurrent(bTable)
	local bE, bL = mergeBoundsFromTable(bTable)
	if not bE then return nil end
	local now = os.date("*t")
	local minAge = ageImpl(bL, 11, now, 11)
	local maxAge = ageImpl(bE, 11, now, 11)
	if not minAge or not maxAge then return nil end
	return minAge, maxAge
end

local function parseISO8601Date(str)
	local pattern = "(%-?%d+)%-(%d+)%-(%d+)T"
	local Y, M, D = mw.ustring.match( str, pattern )
	return tonumber(Y), tonumber(M), tonumber(D)
end
 
local function parseISO8601Time(str)
	local pattern = "T(%d+):(%d+):(%d+)"
	local H, M, S = mw.ustring.match( str, pattern)
	return tonumber(H), tonumber(M), tonumber(S)
end
 
local function parseISO8601Offset(str)
	if str:sub(-1)=="Z" then return 0,0 end
 
	local pattern = "([-+])(%d%d):?(%d?%d?)$"
	local sign, oh, om = mw.ustring.match( str, pattern) 
	sign, oh, om = sign or "+", oh or "00", om or "00"
 
	return tonumber(sign .. oh), tonumber(sign .. om)
end

local function parseISO8601(str)
	if 'table' == type(str) then
		if str.args and str.args[1] then
			str = '' .. str.args[1]
		else
			return 'unknown argument type: ' .. type( str ) .. ': ' .. table.tostring( str )
		end
	end

	local Y,M,D = parseISO8601Date(str)
	local h,m,s = parseISO8601Time(str)
	local oh,om = parseISO8601Offset(str)

	if not Y or not M or not D or not h or not m or not s or not oh or not om then
		return nil
	end

	return tonumber(os.time({ year=Y, month=M, day=D, hour=(h - oh), min=(m - om), sec=s }))
end

local function parseClaim ( claim )
	if ( claim.mainsnak.snaktype == "value" ) then
		local timeISO8601 = string.gsub( string.gsub( tostring( claim.mainsnak.datavalue.value.time ), '-00%-', '-01-' ), '-00T', '-01T' )
		local unixtime = parseISO8601( timeISO8601 )
		local structure = os.date("*t", unixtime)
		local precision = tonumber( claim.mainsnak.datavalue.value.precision )
		local calendarmodel = 'gregorian'
		if (mw.ustring.find(claim.mainsnak.datavalue.value.calendarmodel, 'Q1985786', 1, true)) then
			calendarmodel = 'julian'
		end
		local item = { structure=structure, precision=precision, calendar = calendarmodel }
		return item
	elseif ( claim.mainsnak.snaktype == "novalue" ) then
		return { unknown="novalue" }
	else
		return { unknown="unknown" }
	end
end

local function dateCalendar( value )
	if value.calendarmodel and
		mw.ustring.find( value.calendarmodel, 'Q1985786', 1, true )
	then
		return 'julian'
	end
	return 'gregorian'
end

local function dateEntry( statement, order )
	local snak = statement and statement.mainsnak
	local value = snak and snak.snaktype == 'value' and
		snak.datavalue and snak.datavalue.value
	if not value or not value.time then return nil end
	local year, month, day = mw.ustring.match(
		value.time, '^([+-]?%d+)%-(%d%d)%-(%d%d)T'
	)
	local precision = tonumber( value.precision )
	if not year or not precision or precision < 9 or precision > 11 then
		return nil
	end
	return {
		statement = statement,
		sources = { statement },
		circumstanceSources = { statement },
		order = order,
		year = tonumber( year ),
		month = tonumber( month ),
		day = tonumber( day ),
		precision = precision,
		calendar = dateCalendar( value ),
	}
end

local function dateDayNumber( year, month, day, calendar )
	local a = math.floor( ( 14 - month ) / 12 )
	local y = year + 4800 - a
	local m = month + 12 * a - 3
	if calendar == 'julian' then
		return day + math.floor( ( 153 * m + 2 ) / 5 ) +
			365 * y + math.floor( y / 4 ) - 32083
	end
	return day + math.floor( ( 153 * m + 2 ) / 5 ) +
		365 * y + math.floor( y / 4 ) - math.floor( y / 100 ) +
		math.floor( y / 400 ) - 32045
end

local function julianDateFromDayNumber( number )
	local c = number + 32082
	local d = math.floor( ( 4 * c + 3 ) / 1461 )
	local e = c - math.floor( 1461 * d / 4 )
	local m = math.floor( ( 5 * e + 2 ) / 153 )
	return {
		year = d - 4800 + math.floor( m / 10 ),
		month = m + 3 - 12 * math.floor( m / 10 ),
		day = e - math.floor( ( 153 * m + 2 ) / 5 ) + 1,
	}
end

local function entryValueKey( entry, precision )
	precision = precision or entry.precision
	local parts = entry.comparison or entry
	local key = tostring( parts.year )
	if precision >= 10 then key = key .. ':' .. tostring( parts.month ) end
	if precision >= 11 then key = key .. ':' .. tostring( parts.day ) end
	return key
end

local function hasBoundaryQualifiers( statement )
	local qualifiers = statement.qualifiers
	return qualifiers and
		( qualifiers.P1319 and qualifiers.P1319[ 1 ] or
		  qualifiers.P1326 and qualifiers.P1326[ 1 ] )
end

local function dateValueKey( value )
	if not value or not value.time or not value.precision then return nil end
	local year, month, day = mw.ustring.match(
		value.time, '^([+-]?%d+)%-(%d%d)%-(%d%d)T'
	)
	local precision = tonumber( value.precision )
	if not year or not precision then return nil end
	local key = dateCalendar( value ) .. ':' .. precision .. ':' .. year
	if precision >= 10 then key = key .. ':' .. month end
	if precision >= 11 then key = key .. ':' .. day end
	return key
end

local function preferBoundaryClaims( claims )
	local boundaries = {}
	for _, statement in ipairs( claims or {} ) do
		for _, property in ipairs( { 'P1319', 'P1326' } ) do
			for _, qualifier in ipairs(
				( statement.qualifiers and statement.qualifiers[ property ] ) or {}
			) do
				local key = dateValueKey(
					qualifier.datavalue and qualifier.datavalue.value
				)
				if key then boundaries[ key ] = true end
			end
		end
	end
	local result = {}
	local changed = false
	for _, statement in ipairs( claims or {} ) do
		local value = statement.mainsnak and statement.mainsnak.datavalue and
			statement.mainsnak.datavalue.value
		local redundant = not hasBoundaryQualifiers( statement ) and
			boundaries[ dateValueKey( value ) ]
		if redundant then
			changed = true
		else
			table.insert( result, statement )
		end
	end
	return result, changed
end

local function mergeDateEntries( claims )
	local raw = {}
	local julianWritten = {}
	for order, statement in ipairs( claims or {} ) do
		if hasBoundaryQualifiers( statement ) then return nil end
		local entry = dateEntry( statement, order )
		if not entry then return nil end
		table.insert( raw, entry )
		if entry.calendar == 'julian' then
			julianWritten[
				entry.precision .. ':' .. entryValueKey( entry )
			] = true
		end
	end

	local merged = {}
	local byValue = {}
	local julianByWritten = {}
	for _, entry in ipairs( raw ) do
		if entry.calendar == 'julian' then
			julianByWritten[
				entry.precision .. ':' .. entryValueKey( entry )
			] = entry
		end
	end
	for _, entry in ipairs( raw ) do
		local writtenKey = entry.precision .. ':' .. entryValueKey( entry )
		if entry.calendar == 'gregorian' and julianWritten[ writtenKey ] then
			table.insert(
				julianByWritten[ writtenKey ].circumstanceSources,
				entry.statement
			)
		else
			local key
			if entry.precision == 11 then
				key = 'day:' .. dateDayNumber(
					entry.year, entry.month, entry.day, entry.calendar
				)
			else
				key = entry.calendar .. ':' .. writtenKey
			end
			local existing = byValue[ key ]
			if existing then
				table.insert( existing.sources, entry.statement )
				for _, source in ipairs( entry.circumstanceSources ) do
					table.insert( existing.circumstanceSources, source )
				end
				if entry.calendar == 'julian' and
					existing.calendar ~= 'julian'
				then
					existing.statement = entry.statement
					existing.year = entry.year
					existing.month = entry.month
					existing.day = entry.day
					existing.calendar = entry.calendar
				end
			else
				byValue[ key ] = entry
				table.insert( merged, entry )
			end
		end
	end

	local hasJulian = false
	for _, entry in ipairs( merged ) do
		if entry.calendar == 'julian' then hasJulian = true break end
	end
	for _, entry in ipairs( merged ) do
		entry.comparison = {
			year = entry.year,
			month = entry.month,
			day = entry.day,
		}
		if hasJulian and entry.calendar == 'gregorian' and
			entry.precision == 11
		then
			entry.comparison = julianDateFromDayNumber( dateDayNumber(
				entry.year, entry.month, entry.day, entry.calendar
			) )
		end
	end
	table.sort( merged, function( left, right )
		return left.order < right.order
	end )
	return merged
end

local function entriesAreCompatible( sharper, broader )
	local sharp = sharper.comparison or sharper
	local broad = broader.comparison or broader
	if sharp.year ~= broad.year then return false end
	if broader.precision >= 10 and sharp.month ~= broad.month then
		return false
	end
	if broader.precision >= 11 and sharp.day ~= broad.day then
		return false
	end
	return true
end

local function collapsedDateEntry( entries )
	local sharpest = 9
	for _, entry in ipairs( entries ) do
		sharpest = math.max( sharpest, entry.precision )
	end
	local sharpValues = {}
	local sharpByValue = {}
	for _, entry in ipairs( entries ) do
		if entry.precision == sharpest then
			local key = entryValueKey( entry, sharpest )
			if not sharpByValue[ key ] then
				sharpByValue[ key ] = entry
				table.insert( sharpValues, entry )
			end
		end
	end
	if #sharpValues == 1 then
		local compatible = true
		for _, entry in ipairs( entries ) do
			if not entriesAreCompatible( sharpValues[ 1 ], entry ) then
				compatible = false
				break
			end
		end
		if compatible then return sharpValues[ 1 ] end
	end

	local first = entries[ 1 ]
	local commonPrecision = 9
	local monthKey
	local monthMatches = true
	for _, entry in ipairs( entries ) do
		if entry.precision >= 10 then
			local key = entryValueKey( entry, 10 )
			if monthKey and key ~= monthKey then monthMatches = false end
			monthKey = monthKey or key
		end
	end
	if monthKey and monthMatches then commonPrecision = 10 end
	if commonPrecision == 10 then
		local dayKey
		local dayMatches = true
		for _, entry in ipairs( entries ) do
			if entry.precision >= 11 then
				local key = entryValueKey( entry, 11 )
				if dayKey and key ~= dayKey then dayMatches = false end
				dayKey = dayKey or key
			end
		end
		if dayKey and dayMatches then commonPrecision = 11 end
	end

	local representative = first
	for _, entry in ipairs( entries ) do
		if entry.calendar == 'julian' then
			representative = entry
			break
		end
	end
	local result = {}
	for key, value in pairs( representative ) do result[ key ] = value end
	result.precision = commonPrecision
	result.sources = {}
	result.circumstanceSources = {}
	result.variants = {}
	result.order = first.order
	for _, entry in ipairs( entries ) do
		result.order = math.min( result.order, entry.order )
		if entry.precision >= commonPrecision then
			table.insert( result.variants, entry )
			for _, source in ipairs( entry.sources ) do
				table.insert( result.sources, source )
			end
			for _, source in ipairs( entry.circumstanceSources ) do
				table.insert( result.circumstanceSources, source )
			end
		end
	end
	if commonPrecision == sharpest or #result.variants < 2 then
		result.variants = nil
	end
	return result
end

local function consolidateDateClaims( claims )
	local entries = mergeDateEntries( claims )
	if not entries then return nil end
	local years = {}
	local yearOrder = {}
	for _, entry in ipairs( entries ) do
		local year = ( entry.comparison or entry ).year
		if not years[ year ] then
			years[ year ] = {}
			table.insert( yearOrder, year )
		end
		table.insert( years[ year ], entry )
	end
	local result = {}
	for _, year in ipairs( yearOrder ) do
		table.insert( result, collapsedDateEntry( years[ year ] ) )
	end
	table.sort( result, function( left, right )
		return left.order < right.order
	end )
	return result
end

local function syntheticDateStatement( entry )
	local statement = deepcopy( entry.statement )
	statement.mainsnak.datavalue.value.precision = entry.precision
	statement.references = {}
	for _, source in ipairs( entry.sources ) do
		for _, reference in ipairs( source.references or {} ) do
			table.insert( statement.references, reference )
		end
	end
	statement.qualifiers = deepcopy( statement.qualifiers or {} )
	statement.qualifiers.P1480 = nil
	if next( statement.qualifiers ) == nil then statement.qualifiers = nil end
	return statement
end

local function parseProperty ( context, options, propertyId )
	if ( not context ) then error( 'context not specified'); end
	if ( not options ) then error( 'options not specified'); end
	if ( not options.entity ) then error( 'options.entity is missing'); end
	if ( not propertyId ) then error( 'propertyId not specified'); end

	local claims = context.selectClaims( options, propertyId )
	if not claims then
		return nil
	end

	local consolidated = consolidateDateClaims( claims )
	if consolidated then
		claims = {}
		for _, entry in ipairs( consolidated ) do
			table.insert( claims, syntheticDateStatement( entry ) )
		end
	end

	local result = {}
	for _, claim in ipairs( claims ) do
		table.insert( result, parseClaim( claim ) )
	end
	return result
end

local getQualifierWithDataValue = Qualifiers.getFirstWithDataValue

local p = {}

local function formatDecade( time, categoryNamePrefix )
	if ( time.year < 0 ) then
		local year = math.floor( math.abs(time.year) / 10 ) * 10
		if ( categoryNamePrefix ) then
			return '[[e.ə. ' .. inYear(year) .. ' illər|' .. abbrbc .. ' ' .. inYear(year) .. ' illər]][[Kateqoriya:e.ə. ' .. inYear(year) .. ' illərdə ' .. categoryNamePrefix .. ']]'
		else
			return 'e.ə.' .. year .. ''
		end
	else
		local year = math.floor( time.year / 10 ) * 10
		if ( categoryNamePrefix ) then
			return '[[' .. inYear(year) .. ' illər]][[Kateqoriya:' .. inYear(year) .. ' illərdə ' .. categoryNamePrefix .. ']]'
		else
			return '' .. year
		end
	end
end

local function formatCentury( time, categoryNamePrefix )
if ( time.year < 0 ) then
    local century = math.floor( (math.abs( time.year) - 1) / 100 ) + 1;
    local infix = '  ';
    if century == 2 then infix = '  '; end;
    if ( moduleRoman ) then
        century = moduleRoman.toRomanNumber( century )
    end
    if ( categoryNamePrefix ) then
        return '[[e.ə. ' .. century .. ' əsr|' .. abbrbc .. ' ' ..  century .. ' əsr]][[Kateqoriya:e.ə. ' .. century .. ' əsrdə ' .. categoryNamePrefix .. ']]'
    else
        return '[[e.ə. ' .. century .. ' əsr| ' .. century .. ' əsr]]'
    end
else
    local century = math.floor( (time.year - 1) / 100 ) + 1
    local infix = '  '
    if (century == 2) then infix = ' ' end;
    if ( moduleRoman ) then
        century = moduleRoman.toRomanNumber( century )
    end
    if ( categoryNamePrefix ) then
        return '[[' .. century .. ' əsr]][[Kateqoriya:' .. century .. ' əsrdə ' .. categoryNamePrefix .. ']]'
    else
        return '[[' .. century .. ' əsr]]'
		end
	end
end

local function formatMillenium( time, categoryNamePrefix )
	if ( time.year < 0 ) then
		local millenium = math.floor( (math.abs( time.year) - 1) / 1000 ) + 1
        local infix = '  '
        if millenium == 2 then infix = '  '; end
		if ( moduleRoman ) then
			millenium = moduleRoman.toRomanNumber( millenium )
		end
		if ( categoryNamePrefix ) then
			if ( millenium == 2 ) then
				return '[[e.ə. ' .. millenium .. ' minillik|' .. abbrbc .. ' ' ..  millenium .. ' minillik]][[Kateqoriya:e.ə. ' .. millenium .. ' minillikdə ' .. categoryNamePrefix .. ']]'
			else	
				return '[[e.ə. ' .. millenium .. ' minillik|' .. abbrbc .. ' ' ..  millenium .. ' minillik]][[Kateqoriya:e.ə. ' .. millenium .. ' minillikdə ' .. categoryNamePrefix .. ']]'
			end	
		else
			return '[[e.ə. ' .. millenium .. ' minillik|' .. abbrbc .. ' ' ..  millenium .. ' minillik]]'
		end
	else
		local millenium = math.floor( (time.year - 1) / 1000 ) + 1
        local infix = '  ';
        if (millenium == 2) then infix = ' ' end
		if ( moduleRoman ) then
			millenium = moduleRoman.toRomanNumber( millenium )
		end
		if ( categoryNamePrefix ) then
			if ( millenium == 2 ) then
				return '[[' .. millenium .. ' minillik]][[Kateqoriya:' .. millenium .. ' minillikdə ' .. categoryNamePrefix .. ']]'
			else
				return '[[' .. millenium .. ' minillik]][[Kateqoriya:' .. millenium .. ' minillikdə ' .. categoryNamePrefix .. ']]'
			end
		else
			return '[[' .. millenium .. ' minillik]]'
		end
	end
end

local function formatDateImpl( value, options, microformatClass, categoryPrefix, leftBracket, rightBracket, nolinks )
	if ( not value ) then error( 'value not specified'); end
	if ( not options ) then error( 'options not specified'); end

	local timeISO8601 = string.gsub( string.gsub( tostring( value.time ), '-00%-', '-01-' ), '-00T', '-01T' )
	local unixtime = parseISO8601( timeISO8601 )
	
	if not unixtime then
		return ''
	end

	local structure = os.date("*t", unixtime)
	local precision = tonumber( value.precision )
	
	if precision <= 6 then
		return formatMillenium(structure, categoryPrefix)
	end	
	if precision == 7 then
		return formatCentury(structure, categoryPrefix)
	end

	if precision == 8 then
		return formatDecade(structure, categoryPrefix)
	end

	if precision == 9 then
		local tCopy = deepcopy( structure )
		tCopy.day = nil
		tCopy.month = nil
		return moduleDates.formatWikiImpl(tCopy, tCopy, microformatClass, categoryPrefix, leftBracket, rightBracket, nolinks )
	end

	if precision == 10 then
		local tCopy = deepcopy( structure )
		tCopy.day = nil
		return moduleDates.formatWikiImpl(tCopy, tCopy, microformatClass, categoryPrefix, leftBracket, rightBracket, nolinks )
	end

	local calendarmodel = 'gregorian'
	if (mw.ustring.find(value.calendarmodel, 'Q1985786', 1, true)) then
		calendarmodel = 'julian'
	end

	if (calendarmodel == 'gregorian') then
		return moduleDates.formatWikiImpl( structure, structure, microformatClass, categoryPrefix, leftBracket, rightBracket, nolinks )
	else
		return p.formatAsJulian( unixtime, microformatClass, categoryPrefix, leftBracket, rightBracket, nolinks )
	end
end

local function formatApproximateDateClaim( context, options, statement, unknownDateCategory )
	if ( not context ) then error( 'context not specified'); end
	if ( not options ) then error( 'options not specified'); end
	if ( not options.entity ) then error( 'options.entity is missing'); end
	if ( not statement ) then error( 'statement not specified'); end
	if options.nocat then unknownDateCategory = "" end
	
	local qNotSoonerThan = getQualifierWithDataValue( statement, 'P1319' )
	local qNotLaterThan = getQualifierWithDataValue( statement, 'P1326' )
	if ( qNotSoonerThan or qNotLaterThan ) then
		local results = {}
		if ( qNotSoonerThan ) then
			local formattedDate = formatDateImpl( qNotSoonerThan.datavalue.value, {}, nil, nil, options.leftBracket, options.rightBracket, options.nolinks )
			local value = 'ən&nbsp;tezi&nbsp;' .. context.wrapSnak( formattedDate, qNotSoonerThan.hash )
			table.insert( results, context.wrapQualifier( value, 'P1319' ) )
		end
		if ( qNotLaterThan ) then
			local formattedDate = formatDateImpl( qNotLaterThan.datavalue.value, {}, nil, nil, options.leftBracket, options.rightBracket, options.nolinks )
			local value = 'ən&nbsp;geci&nbsp;' .. context.wrapSnak( formattedDate, qNotLaterThan.hash )
			table.insert( results, context.wrapQualifier( value, 'P1326' ) )
		end
		return mw.text.listToText( results, ' və ' , ' və ' ) .. unknownDateCategory .. context.formatRefs( options, statement )
	end
	
	return nil
end

local function appendLivingAge( result, bTable, options )
	local ageExact = ageCurrent( bTable )
	if ageExact then
		if options.suppressAge == nil or options.suppressAge == '' then
			result = result .. ' <span style="white-space:nowrap; font-size:95%;">(' .. ageExact .. '\194\160yaş)</span>'
			if ageExact >= 100 then
				result = result .. dateCat.categoryCentenarians
			end
		end
		if not options.nocat then
			if ageExact >= 90 and ageExact < 100 then
				result = result .. dateCat.categoryBigCurrentAge
			elseif ageExact >= 0 then
				result = result .. dateCat.categoryBiographiesOfLivingPersons
			else
				result = result .. dateCat.categoryNegativeAge
			end
		end
		return result
	end

	local minAge, maxAge = ageRangeCurrent( bTable )
	if not minAge or not maxAge or
		( options.suppressAge ~= nil and options.suppressAge ~= '' )
	then
		return result
	end
	if minAge == maxAge then
		result = result .. ' <span style="white-space:nowrap; font-size:95%;">(' .. minAge .. '\194\160yaş)</span>'
		if not options.nocat then
			if minAge >= 90 and minAge < 100 then
				result = result .. dateCat.categoryBigCurrentAge
			elseif minAge >= 0 then
				result = result .. dateCat.categoryBiographiesOfLivingPersons
			else
				result = result .. dateCat.categoryNegativeAge
			end
			if minAge >= 100 then
				result = result .. dateCat.categoryCentenarians
			end
		end
	else
		result = result .. ' <span style="white-space:nowrap; font-size:95%;">(' .. minAge .. '–' .. maxAge .. '\194\160yaş)</span>'
		if not options.nocat then
			result = result .. dateCat.categoryBiographiesOfLivingPersons
			if minAge >= 90 and maxAge < 100 then
				result = result .. dateCat.categoryBigCurrentAge
			end
			if minAge >= 100 and maxAge >= 100 then
				result = result .. dateCat.categoryCentenarians
			end
			if maxAge < 0 then
				result = result .. dateCat.categoryNegativeAge
			end
		end
	end
	return result
end

local function appendDeathAge( result, bTable, dTable, options )
	local ageExact = age( bTable, dTable )
	if ageExact then
		if options.suppressAge == nil or options.suppressAge == '' then
			result = result .. ' <span style="white-space:nowrap; font-size:95%;">(' .. ageExact .. '\194\160yaşında)</span>' .. '[[Kateqoriya:' .. ageExact .. ' yaşında vəfat edənlər]]'
			if ageExact >= 100 then
				result = result .. dateCat.categoryCentenarians
			end
		end
		if not options.nocat and ageExact < 0 then
			result = result .. dateCat.categoryNegativeAge
		end
	else
		local minAge, maxAge = ageRange( bTable, dTable )
		if minAge and maxAge and
			( options.suppressAge == nil or options.suppressAge == '' )
		then
			if minAge == maxAge then
				result = result .. ' <span style="white-space:nowrap; font-size:95%;">(' .. minAge .. '\194\160yaşında)</span>' .. '[[Kateqoriya:' .. minAge .. ' yaşında vəfat edənlər]]'
				if minAge >= 100 then
					result = result .. dateCat.categoryCentenarians
				end
				if not options.nocat and minAge < 0 then
					result = result .. dateCat.categoryNegativeAge
				end
			else
				result = result .. ' <span style="white-space:nowrap; font-size:95%;">(' .. minAge .. '–' .. maxAge .. '\194\160yaşında)</span>'
				if not options.nocat and minAge >= 100 and maxAge >= 100 then
					result = result .. dateCat.categoryCentenarians
				end
				if not options.nocat and maxAge < 0 then
					result = result .. dateCat.categoryNegativeAge
				end
			end
		end
	end

	local unixAvailable, unixDateOfDeath = pcall( function()
		local value = os.time( dTable[ 1 ].structure )
		if value ~= os.time() then return value end
		error()
	end )
	if unixAvailable and os.time() - unixDateOfDeath < 31536000 and
		not options.nocat
	then
		result = result .. dateCat.categoryRecentlyDeceased
	end
	return result
end

	function p.formatDateOfBirthClaim( context, options, statement )
	local value = formatApproximateDateClaim( context, options, statement, dateCat.categoryUnknownBirthDate)
	if value then
		return value
	end

    options['conjunction'] = '&#32;və ya&#32;'
    options['value-module'] = 'Wikidata/date'
    options['value-function'] = 'formatBirthDate'
    options.i18n.somevalue = '\'\'bilinmir\'\'' .. dateCat.categoryUnknownBirthDate
	local result = context.formatStatementDefault( context, options, statement )

	local bTable = { parseClaim( statement ) }
	local dTable = parseProperty ( context, options, 'P570' )

	if bTable and not dTable then
		result = appendLivingAge( result, bTable, options )
	end

	return result
end

function p.formatDateOfDeathClaim( context, options, statement )
	local value = formatApproximateDateClaim( context, options, statement, dateCat.categoryUnknownDeathDate )
	if value then
		return value
	end

    options['conjunction'] = '&#32;və ya&#32;';
    options['value-module'] = 'Wikidata/date';
    options['value-function'] = 'formatDeathDate';
    options.i18n.somevalue = '\'\'bilinmir\'\'' .. dateCat.categoryUnknownDeathDate
	local result = context.formatStatementDefault( context, options, statement )

	local bTable = parseProperty ( context, options, 'P569' )
	local dTable = { parseClaim( statement ) };

	if bTable and dTable then
		result = appendDeathAge( result, bTable, dTable, options )
	end

	return result
end

function p.formatBirthDate( context, options, value )
	if ( not context ) then error( 'context not specified'); end
	if ( not options ) then error( 'options not specified'); end
	if ( not value ) then error( 'value not specified'); end
	
	local microformatClass = nil
	if options.microformat ~= '-' then
		microformatClass = options.microformat or 'bday'
	end
	if ( options.nocat ) then
		return formatDateImpl( value, options, microformatClass, nil, options.leftBracket, options.rightBracket, options.nolinks )
	else
		return formatDateImpl( value, options, microformatClass, 'doğulanlar', options.leftBracket, options.rightBracket, options.nolinks )
	end
end

function p.formatDeathDate( context, options, value )
	if ( not context ) then error( 'context not specified'); end
	if ( not options ) then error( 'options not specified'); end
	if ( not value ) then error( 'value not specified'); end

	local microformatClass = nil
	if options.microformat ~= '-' then
		microformatClass = options.microformat or 'dday'
	end
	if ( options.nocat and options.nocat ~= '' ) then
		return formatDateImpl( value, options, microformatClass, nil, options.leftBracket, options.rightBracket, options.nolinks )
	else
		return formatDateImpl( value, options, microformatClass, 'vəfat edənlər', options.leftBracket, options.rightBracket, options.nolinks )
	end
end

function p.formatDate( context, options, value )
	if ( not context ) then error( 'context not specified'); end
	if ( not options ) then error( 'options not specified'); end
	if ( not value ) then error( 'value not specified'); end

	local microformatClass = options.microformat or nil
	if ( options.nocat and options.nocat ~= '' ) then
		return formatDateImpl( value, options, microformatClass, nil, options.leftBracket, options.rightBracket, options.nolinks )
	else
		local categoryPrefix = options.categoryPrefix or nil
		return formatDateImpl( value, options, microformatClass, categoryPrefix, options.leftBracket, options.rightBracket, options.nolinks )
	end
end

local function factoredYearEntries( entries )
	if #entries < 2 then return false end
	local first = entries[ 1 ]
	if first.precision ~= 11 or first.calendar ~= 'gregorian' then
		return false
	end
	local parts = first.comparison or first
	for i = 2, #entries do
		local entry = entries[ i ]
		local other = entry.comparison or entry
		if entry.precision ~= 11 or entry.calendar ~= 'gregorian' or
			other.month ~= parts.month or other.day ~= parts.day
		then
			return false
		end
	end
	return true
end

local function applyDateCircumstances( options, result, entries )
	local seen = {}
	local values = {}
	for _, entry in ipairs( entries ) do
		for _, source in ipairs(
			entry.circumstanceSources or entry.sources
		) do
			for _, circumstance in ipairs( Qualifiers.getSourcingCircumstances( source ) ) do
				if not seen[ circumstance ] then
					seen[ circumstance ] = true
					table.insert( values, circumstance )
				end
			end
		end
	end
	return Qualifiers.applyCircumstances( options, result, values )
end

local function formatDateEntryValue( context, options, entry, clean )
	local statement = syntheticDateStatement( entry )
	local valueOptions = context.cloneOptions( options )
	valueOptions.references = false
	valueOptions[ 'value-module' ] = 'Wikidata/date'
	if mw.ustring.upper( options.property ) == 'P569' then
		valueOptions[ 'value-function' ] = 'formatBirthDate'
	else
		valueOptions[ 'value-function' ] = 'formatDeathDate'
	end
	if clean then
		valueOptions.microformat = '-'
		valueOptions.nocat = true
		valueOptions.nolinks = true
	end
	local value = context.formatSnak(
		valueOptions,
		statement.mainsnak,
		{}
	)
	value = applyDateCircumstances(
		valueOptions,
		value,
		{ entry }
	)
	return value, statement
end

local function appendDateEntryAge( context, options, result, statement )
	if mw.ustring.upper( options.property ) == 'P569' then
		local deaths = parseProperty( context, options, 'P570' )
		if not deaths then
			result = appendLivingAge(
				result,
				{ parseClaim( statement ) },
				options
			)
		end
	else
		local births = parseProperty( context, options, 'P569' )
		if births then
			result = appendDeathAge(
				result,
				births,
				{ parseClaim( statement ) },
				options
			)
		end
	end
	return result
end

local function annotationPlainText( value )
	value = mw.ustring.gsub(
		value,
		'%[%[[^%]|]-|([^%]]-)%]%]',
		'%1'
	)
	value = mw.ustring.gsub( value, '%[%[([^%]]-)%]%]', '%1' )
	value = mw.ustring.gsub( value, '<[^>]*>', '' )
	value = mw.ustring.gsub( value, '&nbsp;', ' ' )
	value = mw.ustring.gsub( value, '&#32;', ' ' )
	return value
end

local function formatAnnotatedDateEntry( context, options, entry )
	local visible, statement = formatDateEntryValue(
		context,
		options,
		entry,
		false
	)
	local rich = {}
	local plain = {}
	for _, variant in ipairs( entry.variants ) do
		local value, variantStatement = formatDateEntryValue(
			context,
			options,
			variant,
			true
		)
		table.insert( plain, annotationPlainText( value ) )
		if options.references then
			value = value .. context.formatRefs(
				options,
				variantStatement
			)
		end
		table.insert( rich, value )
	end
	local title = mw.text.encode(
		mw.text.listToText( plain, options.separator, ' və ya ' ),
		'"&<>'
	)
	annotationSequence = annotationSequence + 1
	local annotationId = 'rt-annotation-' .. mw.ustring.gsub(
		tostring( options.entity.id or '' ) .. '-' ..
			tostring( options.property or '' ) .. '-' ..
			tostring( entry.statement.id or entry.order or '' ) .. '-' ..
			tostring( annotationSequence ),
		'[^%w%-_:.]',
		'-'
	)
	local result = '<sup id="' .. annotationId .. '-trigger" class="rt-annotatedText" style="font-size:inherit;line-height:inherit;vertical-align:baseline;">' ..
		'<span style="display:none;">[[#' .. annotationId .. '|&#xfeff;]]</span>' ..
		'<abbr title="' .. title .. '" class="nowrap rt-annotationLabel">' ..
		visible .. '</abbr></sup><span style="display:none;"><span id="' ..
		annotationId .. '">' ..
		mw.text.listToText(
			rich,
			options.separator,
			'&#32;və ya&#32;'
		) .. '</span></span>'
	return appendDateEntryAge(
		context,
		options,
		result,
		statement
	)
end

local function formatFactoredYears( context, options, entries )
	local first = entries[ 1 ].comparison or entries[ 1 ]
	local prefixStructure = { day = first.day, month = first.month }
	local prefix = moduleDates.formatWikiImpl(
		prefixStructure,
		prefixStructure,
		nil,
		nil,
		options.leftBracket,
		options.rightBracket,
		options.nolinks
	)
	local statements = {}
	local years = {}
	for _, entry in ipairs( entries ) do
		local statement = syntheticDateStatement( entry )
		table.insert( statements, statement )
		local yearStatement = deepcopy( statement )
		yearStatement.mainsnak.datavalue.value.precision = 9
		local yearOptions = context.cloneOptions( options )
		yearOptions.microformat = '-'
		yearOptions[ 'value-module' ] = 'Wikidata/date'
		if mw.ustring.upper( options.property ) == 'P569' then
			yearOptions[ 'value-function' ] = 'formatBirthDate'
		else
			yearOptions[ 'value-function' ] = 'formatDeathDate'
		end
		local year = context.formatSnak( yearOptions, yearStatement.mainsnak, {} )
		if options.references then
			year = year .. context.formatRefs( options, statement )
		end
		table.insert( years, year )
	end

	local result = prefix .. ' ' .. mw.text.listToText(
		years,
		options.separator,
		'&#32;və ya&#32;'
	)
	result = applyDateCircumstances( options, result, entries )
	local parsed = {}
	for _, statement in ipairs( statements ) do
		table.insert( parsed, parseClaim( statement ) )
	end
	if mw.ustring.upper( options.property ) == 'P569' then
		local deaths = parseProperty( context, options, 'P570' )
		if not deaths then
			result = appendLivingAge( result, parsed, options )
		end
	else
		local births = parseProperty( context, options, 'P569' )
		if births then
			result = appendDeathAge( result, births, parsed, options )
		end
	end
	return context.wrapStatement(
		result,
		options.property,
		entries[ 1 ].statement.id
	)
end

function p.formatDateProperty( context, options )
	if not context then error( 'context not specified' ) end
	if not options then error( 'options not specified' ) end
	if not options.entity then error( 'options.entity missing' ) end
	local selector = options.property .. ( options.rank or '' )
	local claims = context.selectClaims( options, selector )
	if not claims then return '' end
	local preferredClaims, boundaryPreferred = preferBoundaryClaims( claims )
	if boundaryPreferred then
		local formatted = {}
		for _, statement in ipairs( preferredClaims ) do
			local valueOptions = context.cloneOptions( options )
			local value = context.formatStatement( valueOptions, statement )
			if value and value ~= '' then
				table.insert( formatted, context.wrapStatement(
					value,
					options.property,
					statement.id
				) )
			end
		end
		local result = mw.text.listToText(
			formatted,
			options.separator,
			'&#32;və ya&#32;'
		)
		if result ~= '' then
			result = ( options.before or '' ) .. result .. ( options.after or '' )
		end
		return result
	end
	local entries = consolidateDateClaims( claims )
	if not entries then
		return context.formatPropertyDefault( context, options )
	end

	local result
	if factoredYearEntries( entries ) then
		result = formatFactoredYears( context, options, entries )
	else
		local formatted = {}
		for _, entry in ipairs( entries ) do
			local statement = syntheticDateStatement( entry )
			local valueOptions = context.cloneOptions( options )
			local value
			if entry.variants then
				value = formatAnnotatedDateEntry(
					context,
					valueOptions,
					entry
				)
			else
				value = context.formatStatement( valueOptions, statement )
			end
			if value and value ~= '' then
				if not entry.variants then
					value = applyDateCircumstances(
						valueOptions, value, { entry }
					)
				end
				table.insert( formatted, context.wrapStatement(
					value,
					options.property,
					statement.id
				) )
			end
		end
		result = mw.text.listToText(
			formatted,
			options.separator,
			'&#32;və ya&#32;'
		)
	end
	if result ~= '' then
		result = ( options.before or '' ) .. result .. ( options.after or '' )
	end
	return result
end

function p.formatDateIntervalProperty( context, options )
	if ( not context ) then error( 'context not specified' ); end
	if ( not options ) then error( 'options not specified' ); end
	if ( not options.entity ) then error( 'options.entity missing' ); end

	local WDS = require( 'Module:WikidataSelectors' )
	local fromProperty = options.property
	if options.from and options.from ~= '' then
		fromProperty = options.from
	end
	local fromClaims = WDS.filter( options.entity.claims, fromProperty )
	local toClaims = WDS.filter( options.entity.claims, options.to )
	local withinClaims = WDS.filter( options.entity.claims, options.within )

	if fromClaims == nil and toClaims == nil then
		return ''
	end

	local formattedFromClaims = {}
	if fromClaims then
		for i, claim in ipairs( fromClaims ) do
			local formattedStatement = context.formatStatement( options, claim )
			if formattedStatement then
				formattedStatement = '<span class="wikidata-claim" data-wikidata-property-id="' .. string.upper( options.property ) .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. formattedStatement .. '</span>'
				table.insert( formattedFromClaims, formattedStatement )
			end
		end
	end

	local formattedToClaims = {}
	local toOptions = deepcopy( options )
	toOptions.property = options.to
	toOptions.novalue = nowLabel
	if toClaims then
		for i, claim in ipairs( toClaims ) do
			local formattedStatement = context.formatStatement( toOptions, claim )
			if formattedStatement then
				formattedStatement = '<span class="wikidata-claim" data-wikidata-property-id="' .. string.upper( toOptions.property ) .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. formattedStatement .. '</span>'
				table.insert( formattedToClaims, formattedStatement )
			end
		end
	end

	local out = ''
	local fromOut = mw.text.listToText( formattedFromClaims, options.separator, options.conjunction )
	local toOut = mw.text.listToText( formattedToClaims, options.separator, options.conjunction )
	
	if fromOut ~= '' or toOut ~= '' then
		if fromOut ~= '' then
			out = fromOut
		else
			out = '?'
		end

		if toOut ~= '' then
			out = out .. '–' .. toOut
		else
			local withinClaims2 = nil
			if options.within then
				withinClaims2 = WDS.filter( options.entity.claims, options.within )
			end
			if withinClaims2 ~= nil then
				out = '' .. out
			else
				out = out .. '–' .. nowLabel
			end
		end
	end

	if out ~= '' then
		if options.before then
			out = options.before .. out
		end
		if options.after then
			out = out .. options.after
		end
	end

	return out
end

function p.formatYearIntervalProperty( context, options )
	if ( not context ) then error( 'context not specified' ); end
	if ( not options ) then error( 'options not specified' ); end
	if ( not options.entity ) then error( 'options.entity missing' ); end

	local WDS = require( 'Module:WikidataSelectors' )

	local function firstYear( selector )
		if not selector or selector == '' then return nil end
		local claims = WDS.filter( options.entity.claims, selector )
		if not claims or #claims == 0 then return nil end
		for _, claim in ipairs( claims ) do
			local ms = claim.mainsnak
			if ms and ms.snaktype == 'value'
				and ms.datavalue and ms.datavalue.value and ms.datavalue.value.time
			then
				return tonumber( ms.datavalue.value.time:match( '(%-?%d+)%-' ) ), claim
			end
		end
		return nil
	end

	local fromProperty = options.property
	if options.from and string.match( options.from, '^%s*[Pp]%d+' ) then
		fromProperty = options.from
	end

	local startYear, startClaim = firstYear( fromProperty )
	local endYear, endClaim = firstYear( options.to )
	local function wrapEndpoint( value, selector, claim )
		local property = string.upper( string.match( selector, '^%s*([Pp]%d+)' ) )
		return context.wrapStatement( value, property, claim.id )
	end

	local out = ''
	if startYear and endYear then
		out = wrapEndpoint( tostring( startYear ), fromProperty, startClaim ) .. '–' ..
			wrapEndpoint( tostring( endYear ), options.to, endClaim )
	elseif startYear then
		out = wrapEndpoint( Ordinal._ordinal( startYear ) .. ' ildən', fromProperty, startClaim )
	elseif endYear then
		out = wrapEndpoint( Ordinal._ordinal( endYear ) .. ' ilədək', options.to, endClaim )
	end

	if out ~= '' then
		if options.before then out = options.before .. out end
		if options.after  then out = out .. options.after  end
	end

	return out
end

local lowestBoundary = parseISO8601('-900-02-20T00:00:00Z')
local mainBoundary = parseISO8601('1582-10-05T00:00:00Z')
local lastBoundary = parseISO8601('1926-01-31T00:00:00Z')

local boundaries = {
	{ lowestBoundary,                       -9 },
	{ parseISO8601('-700-02-29T00:00:00Z'), -8 },
	{ parseISO8601('-600-02-29T00:00:00Z'), -7 },
	{ parseISO8601('-500-02-29T00:00:00Z'), -6 },
	{ parseISO8601('-300-02-29T00:00:00Z'), -5 },
	{ parseISO8601('-200-02-29T00:00:00Z'), -4 },
	{ parseISO8601('-100-02-29T00:00:00Z'), -3 },
	{ parseISO8601('0000-00-00T00:00:00Z'), -2 },
	{ parseISO8601('0100-02-29T00:00:00Z'), -1 },
	{ parseISO8601('0200-02-29T00:00:00Z'),  0 },
	{ parseISO8601('0300-02-29T00:00:00Z'),  1 },
	{ parseISO8601('0500-02-29T00:00:00Z'),  2 },
	{ parseISO8601('0600-02-29T00:00:00Z'),  3 },
	{ parseISO8601('0700-02-29T00:00:00Z'),  4 },
	{ parseISO8601('0900-02-29T00:00:00Z'),  5 },
	{ parseISO8601('1000-02-29T00:00:00Z'),  6 },
	{ parseISO8601('1100-02-29T00:00:00Z'),  7 },
	{ parseISO8601('1300-02-29T00:00:00Z'),  8 },
	{ parseISO8601('1400-02-29T00:00:00Z'),  9 },
	{ parseISO8601('1500-02-29T00:00:00Z'), 10 },
	{ parseISO8601('1700-02-29T00:00:00Z'), 11 },
	{ parseISO8601('1800-02-29T00:00:00Z'), 12 },
	{ parseISO8601('1900-02-29T00:00:00Z'), 13 },
	{ lastBoundary, '' },
}

function p.formatAsJulian( julTime, infocardClass, categoryNamePrefix, leftBracket, rightBracket, nolinks )
	if 'table' == type( julTime ) then
		if julTime.args and julTime.args[1] then
			julTime = tonumber( julTime.args[1] )
		else
			return 'unknown argument type: ' .. type( julTime ) .. ': ' .. table.tostring( julTime )
		end
	end

	local t = os.date( "*t", julTime )
	if ( julTime <= lowestBoundary ) then
		return "''yanlış tarix (etibarsız dəqiqlik)''"
	end
	if ( julTime >= lastBoundary ) then
		return "''yanlış tarix (yuli təqvimi 1926-01-01 tarixindən sonra istifadə olunmur)''"
	end

	for i=1,#boundaries,1 do
		local b1 = boundaries[i][1]
		local b2 = boundaries[i + 1][1]
		if ( b1 <= julTime and julTime < b2 ) then
			local b1s = os.date( "*t", b1 )
			if ( b1s.year == t.year and b1s.month == t.month and b1s.day == t.day) then
				if ( julTime < mainBoundary ) then
					return moduleDates.formatWikiImpl( {year=t.year, month=2, day=29}, {year=t.year, month=2, day=29}, infocardClass, categoryNamePrefix, leftBracket, rightBracket, nolinks )
				else
					return moduleDates.formatWikiImpl( {year=t.year, month=2, day=29}, t, infocardClass, categoryNamePrefix, leftBracket, rightBracket, nolinks )
				end
			else
				local gregTime = os.date( "*t", julTime + boundaries[i][2] * 24 * 60 * 60 )
				if ( julTime < mainBoundary ) then
					return moduleDates.formatWikiImpl( t, t, infocardClass, categoryNamePrefix, leftBracket, rightBracket, nolinks )
				else
					return moduleDates.formatWikiImpl( t, gregTime, infocardClass, categoryNamePrefix, leftBracket, rightBracket, nolinks )
				end
			end
		end
	end

	if ( julTime >= lastBoundary ) then
		return "''Modul:Wikidata/date daxilində xəta''"
	end
end

return p