Modul:Wikidata/date
Görünüş
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}}
- p.formatBirthDate ← Module:Wikidata ← p.dateOfBirth ← {{wikidata/p569}}
- p.formatDeathDate ← Module:Wikidata ← p.dateOfDeath ← {{wikidata/p570}}
-- Vikidata tarixlərinin nizamlanması
local nowLabel = '<abbr class="abbr" title="hal-hazırda">h. h.</abbr>'
local abbrbc = '<abbr class="abbr" title="eradan əvvəl">e. ə.</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 tezi ' .. 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 geci ' .. 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'] = ' və ya '
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'] = ' və ya ';
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, ' ', ' ' )
value = mw.ustring.gsub( value, ' ', ' ' )
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 .. '|]]</span>' ..
'<abbr title="' .. title .. '" class="nowrap rt-annotationLabel">' ..
visible .. '</abbr></sup><span style="display:none;"><span id="' ..
annotationId .. '">' ..
mw.text.listToText(
rich,
options.separator,
' və ya '
) .. '</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,
' və ya '
)
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,
' və ya '
)
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,
' və ya '
)
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