Модул:Wikidata/date: Тафовут байни таҳрирҳо
Зоҳир
Content deleted Content added
No edit summary |
No edit summary |
||
(11 intermediate revisions by the same user not shown) | |||
Сатри 1: | Сатри 1: | ||
--settings |
--settings |
||
local categoryUnknownBirthDate = '[[Гурӯҳ:Ашхосе, ки |
local categoryUnknownBirthDate = '[[Гурӯҳ:Ашхосе, ки таърихи таваллудашон оварда нашудааст]]'; |
||
local categoryUnknownDeathDate = '[[Гурӯҳ:Ашхосе, ки |
local categoryUnknownDeathDate = '[[Гурӯҳ:Ашхосе, ки таърихи даргузашташон оварда нашудааст]]'; |
||
local categoryBigCurrentAge = '[[Гурӯҳ: |
local categoryBigCurrentAge = '[[Гурӯҳ:Википедия:Мақолаҳо дар бораи ашхоси бо синну соли калони ҷорӣ]]' |
||
local categoryBigDeathAge = '[[Гурӯҳ: |
-- local categoryBigDeathAge = '[[Гурӯҳ:Википедия:Мақолаҳо дар бораи ашхоси солманд дар замони даргузашт]]' //deleted -d.bratchuk 05-07-2016 |
||
local categoryBiographiesOfLivingPersons = '[[Гурӯҳ:Википедия:Зиндагиномаи муосирон]]' |
|||
local categoryRecentlyDeceased = '[[Гурӯҳ:Википедия:Ашхосе, ки то як соли пеш даргузаштанд]]' |
|||
local nowLabel = 'то ҳол' |
|||
local moduleDates = require( "Module:Dates" ) |
local moduleDates = require( "Module:Dates" ) |
||
local moduleWikidata = require( "Module:Wikidata" ) |
local moduleWikidata = require( "Module:Wikidata" ) |
||
function deepcopy(orig) |
local function deepcopy(orig) |
||
local orig_type = type(orig) |
local orig_type = type(orig) |
||
local copy |
local copy |
||
Сатри 21: | Сатри 24: | ||
end |
end |
||
return copy |
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 |
end |
||
-- accepts table of time+precision values |
-- accepts table of time+precision values |
||
function ageCurrent ( bTable ) |
local function ageCurrent ( bTable ) |
||
local possibleAge = "NYA" -- it meansm "Not Yet Assigned", not what you imagined! |
local possibleAge = "NYA" -- it meansm "Not Yet Assigned", not what you imagined! |
||
Сатри 50: | Сатри 92: | ||
-- accepts tables of time+precision values |
-- accepts tables of time+precision values |
||
function age ( bTable, dTable ) |
local function age ( bTable, dTable ) |
||
local possibleAge = "NYA" -- it meansm "Not Yet Assigned", not what you imagined! |
local possibleAge = "NYA" -- it meansm "Not Yet Assigned", not what you imagined! |
||
Сатри 66: | Сатри 108: | ||
local dStructure = dValue.structure |
local dStructure = dValue.structure |
||
local dPrecision = dValue.precision |
local dPrecision = dValue.precision |
||
if ( bValue.calendar == 'julian' and dValue.calendar == 'gregorian' ) then |
|||
-- to calculate age, need to adjust bStructure to gregorian calendar |
|||
local shift = math.floor(bStructure.year/100-2) - math.floor(bStructure.year/400) |
|||
-- TODO: re-implement this properly |
|||
bStructure.day = bStructure.day + shift |
|||
end |
|||
local calculatedAge = ageImpl ( bStructure, bPrecision, dStructure, dPrecision ) |
local calculatedAge = ageImpl ( bStructure, bPrecision, dStructure, dPrecision ) |
||
Сатри 81: | Сатри 129: | ||
end |
end |
||
local function parseISO8601Date(str) |
|||
function ageImpl ( bStructure, bPrecision, dStructure, dPrecision ) |
|||
local pattern = "(%-?%d+)%-(%d+)%-(%d+)T" |
|||
if ( not bStructure or not dStructure or bPrecision < 10 or dPrecision < 10 ) then |
|||
local Y, M, D = mw.ustring.match( str, pattern ) |
|||
return nil |
|||
return tonumber(Y), tonumber(M), tonumber(D) |
|||
end |
|||
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 |
|||
local function parseISO8601Time(str) |
|||
if ( bStructure.month < dStructure.month ) then |
|||
local pattern = "T(%d+):(%d+):(%d+)%Z" |
|||
return dStructure.year - bStructure.year |
|||
local H, M, S = mw.ustring.match( str, pattern) |
|||
end |
|||
return tonumber(H), tonumber(M), tonumber(S) |
|||
if ( bStructure.month == dStructure.month ) then |
|||
end |
|||
if ( bStructure.day <= dStructure.day ) then |
|||
return dStructure.year - bStructure.year |
|||
local function parseISO8601Offset(str) |
|||
else |
|||
if str:sub(-1)=="Z" then return 0,0 end -- ends with Z, Zulu time |
|||
return dStructure.year - bStructure.year - 1 |
|||
end |
|||
-- matches ±hh:mm, ±hhmm or ±hh; else returns nils |
|||
end |
|||
local pattern = "([-+])(%d%d):?(%d?%d?)$" |
|||
if ( bStructure.month > dStructure.month ) then |
|||
local sign, oh, om = mw.ustring.match( str, pattern) |
|||
return dStructure.year - bStructure.year - 1 |
|||
sign, oh, om = sign or "+", oh or "00", om or "00" |
|||
end |
|||
return tonumber(sign .. oh), tonumber(sign .. om) |
|||
return nil |
|||
end |
end |
||
local function parseISO8601(str) |
|||
-- returns table of time+precision values for specified property |
|||
if 'table' == type(str) then |
|||
function parseProperty ( context, options, propertyId ) |
|||
if str.args and str.args[1] then |
|||
if ( not context ) then error( 'context not specified'); end; |
|||
str = '' .. str.args[1] |
|||
if ( not options ) then error( 'options not specified'); end; |
|||
else |
|||
if ( not options.entity ) then error( 'options.entity is missing'); end; |
|||
return 'unknown argument type: ' .. type( str ) .. ': ' .. table.tostring( str ) |
|||
if ( not propertyId ) then error( 'propertyId not specified'); end; |
|||
end |
|||
end |
|||
local Y,M,D = parseISO8601Date(str) |
|||
local claims = context.selectClaims( options, propertyId ); |
|||
local h,m,s = parseISO8601Time(str) |
|||
if not claims then |
|||
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 |
return nil |
||
end |
end |
||
return tonumber(os.time({year=Y, month=M, day=D, hour=(h+oh), min=(m+om), sec=s})) |
|||
local result = {} |
|||
for key, claim in pairs( claims ) do |
|||
table.insert ( result, parseClaim( claim ) ); |
|||
end |
|||
return result |
|||
end |
end |
||
function parseClaim ( claim ) |
local function parseClaim ( claim ) |
||
if ( claim.mainsnak.snaktype == "value" ) then |
if ( claim.mainsnak.snaktype == "value" ) then |
||
-- The calendar model used for saving the data is always the proleptic Gregorian calendar according to ISO 8601. |
-- The calendar model used for saving the data is always the proleptic Gregorian calendar according to ISO 8601. |
||
Сатри 141: | Сатри 179: | ||
local structure = os.date("*t", unixtime) |
local structure = os.date("*t", unixtime) |
||
local precision = tonumber( claim.mainsnak.datavalue.value.precision ) |
local precision = tonumber( claim.mainsnak.datavalue.value.precision ) |
||
local calendarmodel = 'gregorian'; |
|||
local item = { structure=structure, precision=precision } |
|||
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; |
return item; |
||
elseif ( claim.mainsnak.snaktype == "novalue" ) then |
elseif ( claim.mainsnak.snaktype == "novalue" ) then |
||
Сатри 150: | Сатри 192: | ||
return { unknown="unknown" }; |
return { unknown="unknown" }; |
||
end |
end |
||
end |
|||
-- returns table of time+precision values for specified property |
|||
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 result = {} |
|||
for key, claim in pairs( claims ) do |
|||
table.insert ( result, parseClaim( claim ) ); |
|||
end |
|||
return result |
|||
end |
end |
||
-- проверка на совпадающие даты с разной моделью календаря |
-- проверка на совпадающие даты с разной моделью календаря |
||
function checkDupDates( t ) |
local function checkDupDates( t ) |
||
if #t > 1 then |
if #t > 1 then |
||
local removed = false; |
local removed = false; |
||
Сатри 188: | Сатри 249: | ||
-- returns first qualifier of specified propertyId |
-- returns first qualifier of specified propertyId |
||
function |
local function getQualifierWithDataValue( statement, qualifierPropertyId ) |
||
if ( statement.qualifiers |
if ( statement.qualifiers |
||
and statement.qualifiers[qualifierPropertyId] ) then |
and statement.qualifiers[qualifierPropertyId] ) then |
||
Сатри 194: | Сатри 255: | ||
for _, qualifier in ipairs( qualifiers ) do |
for _, qualifier in ipairs( qualifiers ) do |
||
if (qualifier.datavalue) then |
if (qualifier.datavalue) then |
||
return qualifier |
return qualifier; |
||
end |
end |
||
end |
end |
||
Сатри 203: | Сатри 264: | ||
local p = {} |
local p = {} |
||
local function formatDecade( time, categoryNamePrefix ) |
|||
function p.formatDateOfBirthClaim( context, options, statement ) |
|||
if ( time.year < 0 ) then |
|||
local year = math.floor( math.abs(time.year) / 10 ) * 10; |
|||
if ( categoryNamePrefix ) then |
|||
return year .. '-уми то м. [[Category:' .. categoryNamePrefix .. ' солҳои ' .. year .. '-уми то м.]]'; |
|||
else |
|||
return '' .. year .. ' то м.'; |
|||
end |
|||
else |
|||
local year = math.floor( time.year / 10 ) * 10; |
|||
if ( categoryNamePrefix ) then |
|||
return year .. '-ум[[Category:' .. categoryNamePrefix .. ' солҳои ' .. year .. '-ум]]'; |
|||
else |
|||
return '' .. year; |
|||
end |
|||
end |
|||
end |
|||
local function formatCentury( time, categoryNamePrefix ) |
|||
local moduleRoman = require( "Module:RomanNumber" ) |
|||
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 '[[асри ' .. century .. ' то м.]][[Category:' .. categoryNamePrefix .. ' асри ' .. century .. ' то м.]]' |
|||
else |
|||
return '[[асри ' .. century .. ' то м.]]' |
|||
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 .. ']][[Category:' .. categoryNamePrefix .. ' асри ' .. century .. ']]' |
|||
else |
|||
return '[[асри ' .. century .. ']]' |
|||
end |
|||
end |
|||
end |
|||
local function formatMillenium( time, categoryNamePrefix ) |
|||
if ( time.year < 0 ) then |
|||
local millenium = math.floor( (math.abs( time.year) - 1) / 1000 ) + 1; |
|||
if ( categoryNamePrefix ) then |
|||
if ( millenium == 2 ) then |
|||
return '[[ҳазорсолаи ' .. millenium .. ' то м.]][[Category:' .. categoryNamePrefix .. ' ҳазорсолаи ' .. millenium .. ' то м.]]' |
|||
else |
|||
return '[[ҳазорсолаи ' .. millenium .. ' то м.]][[Category:' .. categoryNamePrefix .. ' ҳазорсолаи ' .. millenium .. ' то м.]]' |
|||
end |
|||
else |
|||
return '[[ҳазорсолаи ' .. millenium .. ' то м.]]' |
|||
end |
|||
else |
|||
local millenium = math.floor( (time.year - 1) / 1000 ) + 1; |
|||
if ( categoryNamePrefix ) then |
|||
if ( millenium == 2 ) then |
|||
return '[[ҳазорсолаи ' .. millenium .. ']][[Category:' .. categoryNamePrefix .. ' ҳазорсолаи ' .. millenium .. ']]' |
|||
else |
|||
return '[[ҳазорсолаи ' .. millenium .. ']][[Category:' .. categoryNamePrefix .. ' ҳазорсолаи ' .. millenium .. ']]' |
|||
end |
|||
else |
|||
return '[[ҳазорсолаи ' .. millenium .. ']]' |
|||
end |
|||
end |
|||
end |
|||
local function formatDateImpl( value, options, microformatClass, categoryPrefix, leftBracket, rightBracket ) |
|||
if ( not value ) then error( 'value not specified'); end; |
|||
if ( not options ) then error( 'options not specified'); end; |
|||
-- The calendar model used for saving the data is always the proleptic Gregorian calendar according to ISO 8601. |
|||
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, infoclass, categoryPrefix, leftBracket, rightBracket ) |
|||
end |
|||
-- year and month only |
|||
if precision == 10 then |
|||
local tCopy = deepcopy( structure ) |
|||
tCopy.day = nil |
|||
return moduleDates.formatWikiImpl(tCopy, tCopy, infoclass, categoryPrefix, leftBracket, rightBracket ) |
|||
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 ) |
|||
else |
|||
return p.formatAsJulian( unixtime, infoclass, categoryPrefix, leftBracket, rightBracket ) |
|||
end |
|||
end |
|||
local function formatApproximateDateClaim( context, options, statement ) |
|||
if ( not context ) then error( 'context not specified'); end; |
if ( not context ) then error( 'context not specified'); end; |
||
if ( not options ) then error( 'options 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 options.entity ) then error( 'options.entity is missing'); end; |
||
if ( not statement ) then error( 'statement not specified'); end; |
if ( not statement ) then error( 'statement not specified'); end; |
||
if options.nocat then categoryUnknownBirthDate = "" 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 ) |
|||
local value = 'на пештар аз ' .. 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 ) |
|||
local value = 'на дертар аз ' .. context.wrapSnak( formattedDate, qNotLaterThan.hash ) |
|||
table.insert( results, context.wrapQualifier( value, 'P1326' ) ); |
|||
end |
|||
return mw.text.listToText( results, ' и ' , ' и ' ) .. categoryUnknownBirthDate; |
|||
end |
|||
return nil |
|||
end |
|||
function p.formatDateOfBirthClaim( context, options, statement ) |
|||
if ( statement.mainsnak.snaktype == 'somevalue' ) then |
|||
local value = formatApproximateDateClaim( context, options, statement ) |
|||
local qNotSoonerThan = getQualifierDataValue( statement, 'P1319' ); |
|||
if value then |
|||
local qNotLaterThan = getQualifierDataValue( statement, 'P1326' ); |
|||
return value |
|||
if ( qNotSoonerThan or qNotLaterThan ) then |
|||
local results = {}; |
|||
if ( qNotSoonerThan ) then |
|||
table.insert( results, 'қабл аз ' .. formatDateImpl( qNotSoonerThan.value, {}, nil, nil ) ); |
|||
end |
|||
if ( qNotLaterThan ) then |
|||
table.insert( results, 'пас аз ' .. formatDateImpl( qNotLaterThan.value, {}, nil, nil ) ); |
|||
end |
|||
return mw.text.listToText( results, ' ва ' , ' ва ' ) .. categoryUnknownBirthDate; |
|||
end |
|||
end |
end |
||
Сатри 228: | Сатри 426: | ||
options['value-function'] = 'formatBirthDate'; |
options['value-function'] = 'formatBirthDate'; |
||
options.i18n.somevalue = '\'\'номаълум\'\'' .. categoryUnknownBirthDate; |
options.i18n.somevalue = '\'\'номаълум\'\'' .. categoryUnknownBirthDate; |
||
options.i18n.approximate = '<span style="border-bottom: 1px dotted; cursor: help;" title="наздики">наз. </span>'; |
|||
local result = context.formatStatementDefault( context, options, statement ); |
local result = context.formatStatementDefault( context, options, statement ); |
||
Сатри 237: | Сатри 434: | ||
local age = ageCurrent( bTable ) |
local age = ageCurrent( bTable ) |
||
if ( age ) then |
if ( age ) then |
||
result = result .. ' <span style="white-space:nowrap;">(' .. age .. ' ' .. mw.language.new( 'tg' ):plural( age, 'сол', 'сол', 'сола') .. ')</span>' |
if ( options.suppressAge == nil or options.suppressAge == '' ) then |
||
result = result .. ' <span style="white-space:nowrap;">(' .. age .. ' ' .. mw.language.new( 'tg' ):plural( age, 'сол', 'сол', 'сола') .. ')</span>' |
|||
end |
|||
if ( age > 150 and not options.nocat ) then |
|||
if ( not options.nocat ) then |
|||
result = result .. categoryBigCurrentAge; |
|||
if ( age > 115 ) then |
|||
result = result .. categoryBigCurrentAge; |
|||
else |
|||
result = result .. categoryBiographiesOfLivingPersons; |
|||
end |
|||
end |
|||
end |
end |
||
end |
end |
||
Сатри 248: | Сатри 451: | ||
function p.formatDateOfDeathClaim( context, options, statement ) |
function p.formatDateOfDeathClaim( context, options, statement ) |
||
local value = formatApproximateDateClaim( context, options, statement ) |
|||
if ( not context ) then error( 'context not specified'); end; |
|||
if value then |
|||
if ( not options ) then error( 'options not specified'); end; |
|||
return value |
|||
if ( not options.entity ) then error( 'options.entity is missing'); end; |
|||
if ( not statement ) then error( 'statement not specified'); end; |
|||
if ( statement.mainsnak.snaktype == 'somevalue' ) then |
|||
local qNotSoonerThan = getQualifierDataValue( statement, 'P1319' ); |
|||
local qNotLaterThan = getQualifierDataValue( statement, 'P1326' ); |
|||
if ( qNotSoonerThan or qNotLaterThan ) then |
|||
local results = {}; |
|||
if ( qNotSoonerThan ) then |
|||
table.insert( results, 'бар вақт ' .. formatDateImpl( qNotSoonerThan.value, {}, nil, nil ) ); |
|||
end |
|||
if ( qNotLaterThan ) then |
|||
table.insert( results, 'бе вақт ' .. formatDateImpl( qNotLaterThan.value, {}, nil, nil ) ); |
|||
end |
|||
return mw.text.listToText( results, ' и ' , ' и ' ) .. categoryUnknownDeathDate; |
|||
end |
|||
end |
end |
||
Сатри 272: | Сатри 460: | ||
options['value-function'] = 'formatDeathDate'; |
options['value-function'] = 'formatDeathDate'; |
||
options.i18n.somevalue = '\'\'номаълум\'\'' .. categoryUnknownDeathDate; |
options.i18n.somevalue = '\'\'номаълум\'\'' .. categoryUnknownDeathDate; |
||
options.i18n.approximate = '<span style="border-bottom: 1px dotted; cursor: help;" title="около">ок. </span>'; |
|||
local result = context.formatStatementDefault( context, options, statement ); |
local result = context.formatStatementDefault( context, options, statement ); |
||
Сатри 281: | Сатри 468: | ||
local age = age( bTable, dTable ) |
local age = age( bTable, dTable ) |
||
if ( age ) then |
if ( age ) then |
||
result = result .. ' <span style="white-space:nowrap;">(' .. age .. ' ' .. mw.language.new( 'tg' ):plural( age, 'сол', 'сол', 'сола') .. ')</span>' |
if ( options.suppressAge == nil or options.suppressAge == '' ) then |
||
result = result .. ' <span style="white-space:nowrap;">(' .. age .. ' ' .. mw.language.new( 'tg' ):plural( age, 'сол', 'сол', 'сола') .. ')</span>' |
|||
end |
|||
if ( age > 150 and (not context.options or not context.options.nocat) ) then |
|||
end |
|||
result = result .. categoryBigDeathAge; |
|||
-- returns category to recently deceased persons |
|||
local unixAvailable, unixDateOfDeath = pcall(function() |
|||
local r = os.time(dTable[1].structure) |
|||
if ( r ~= os.time() ) then |
|||
return r |
|||
end |
|||
error() |
|||
end) |
|||
if ( unixAvailable and os.time() - unixDateOfDeath < 31536000 and not options.nocat ) then |
|||
result = result .. categoryRecentlyDeceased |
|||
end |
end |
||
end |
end |
||
Сатри 297: | Сатри 495: | ||
if ( not value ) then error( 'value 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 |
if ( options.nocat ) then |
||
return formatDateImpl( value, options, |
return formatDateImpl( value, options, microformatClass, nil, options.leftBracket, options.rightBracket ) |
||
else |
else |
||
return formatDateImpl( value, options, |
return formatDateImpl( value, options, microformatClass, 'Зодагони', options.leftBracket, options.rightBracket ) |
||
end |
end |
||
end |
end |
||
Сатри 310: | Сатри 512: | ||
if ( not value ) then error( 'value not specified'); end; |
if ( not value ) then error( 'value not specified'); end; |
||
local microformatClass = nil |
|||
if ( options.nocat ) then |
|||
if options.microformat ~= '-' then |
|||
return formatDateImpl( value, options, 'dday', nil ) |
|||
microformatClass = options.microformat or 'dday' |
|||
end |
|||
if ( options.nocat and options.nocat ~= '' ) then |
|||
return formatDateImpl( value, options, microformatClass, nil, options.leftBracket, options.rightBracket ) |
|||
else |
else |
||
return formatDateImpl( value, options, |
return formatDateImpl( value, options, microformatClass, 'Даргузаштагони', options.leftBracket, options.rightBracket ) |
||
end |
end |
||
end |
end |
||
Сатри 323: | Сатри 529: | ||
if ( not value ) then error( 'value not specified'); end; |
if ( not value ) then error( 'value not specified'); end; |
||
local microformatClass = options. |
local microformatClass = options.microformat or nil; |
||
if ( options.nocat ) then |
if ( options.nocat and options.nocat ~= '' ) then |
||
return formatDateImpl( value, options, microformatClass, nil ) |
return formatDateImpl( value, options, microformatClass, nil, options.leftBracket, options.rightBracket ) |
||
else |
else |
||
local categoryPrefix = options.categoryPrefix or nil; |
local categoryPrefix = options.categoryPrefix or nil; |
||
return formatDateImpl( value, options, microformatClass, categoryPrefix ) |
return formatDateImpl( value, options, microformatClass, categoryPrefix, options.leftBracket, options.rightBracket ) |
||
end |
end |
||
end |
end |
||
function |
function p.formatDateIntervalProperty( context, options ) |
||
if ( not |
if ( not context ) then error( 'context not specified' ); end; |
||
if ( not options ) then error( 'options not specified'); end; |
if ( not options ) then error( 'options not specified' ); end; |
||
if ( not options.entity ) then error( 'options.entity missing' ); end; |
|||
-- Получение нужных утверждений |
|||
-- The calendar model used for saving the data is always the proleptic Gregorian calendar according to ISO 8601. |
|||
local WDS = require( 'Module:WikidataSelectors' ); |
|||
local timeISO8601 = string.gsub( string.gsub( tostring( value.time ), '-00%-', '-01-' ), '-00T', '-01T' ) |
|||
local |
local fromProperty = options.property |
||
if options.from and options.from ~= '' then |
|||
fromProperty = options.from |
|||
local structure = os.date("*t", unixtime) |
|||
local precision = tonumber( value.precision ) |
|||
if precision == 7 then |
|||
return formatCentury(structure, categoryPrefix) |
|||
end |
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 '' |
|||
return formatDecade(structure, categoryPrefix) |
|||
end |
|||
local formattedFromClaims = {} |
|||
if precision == 9 then |
|||
if fromClaims then |
|||
local tCopy = deepcopy( structure ) |
|||
for i, claim in ipairs( fromClaims ) do |
|||
tCopy.day = nil |
|||
local formattedStatement = context.formatStatement( options, claim ) |
|||
tCopy.month = nil |
|||
if formattedStatement then |
|||
return moduleDates.formatWikiImpl(tCopy, tCopy, infoclass, categoryPrefix) |
|||
formattedStatement = '<span class="wikidata-claim" data-wikidata-property-id="' .. string.upper( options.property ) .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. formattedStatement .. '</span>' |
|||
end |
|||
table.insert( formattedFromClaims, formattedStatement ) |
|||
end |
|||
end |
|||
end |
|||
local formattedToClaims = {} |
|||
-- year and month only |
|||
local toOptions = deepcopy( options ) |
|||
if precision == 10 then |
|||
toOptions.property = options.to |
|||
local tCopy = deepcopy( structure ) |
|||
toOptions.novalue = nowLabel |
|||
tCopy.day = nil |
|||
if toClaims then |
|||
return moduleDates.formatWikiImpl(tCopy, tCopy, infoclass, categoryPrefix) |
|||
for i, claim in ipairs( toClaims ) do |
|||
end |
|||
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 |
local out = '' |
||
local fromOut = mw.text.listToText( formattedFromClaims, options.separator, options.conjunction ) |
|||
if (mw.ustring.find(value.calendarmodel, 'Q1985786', 1, true)) then |
|||
local toOut = mw.text.listToText( formattedToClaims, options.separator, options.conjunction ) |
|||
calendarmodel = 'julian'; |
|||
end |
|||
if fromOut ~= '' or toOut ~= '' then |
|||
if fromOut ~= '' then |
|||
out = fromOut |
|||
return moduleDates.formatWikiImpl( structure, structure, microformatClass, categoryPrefix ) |
|||
else |
|||
return p.formatAsJulian( unixtime, infoclass, categoryPrefix ) |
|||
end |
|||
end |
|||
function formatDecade( time, categoryNamePrefix ) |
|||
local year = math.floor( time.year / 10 ) * 10; |
|||
if ( categoryNamePrefix ) then |
|||
return year .. '[[Гурӯҳ:' .. categoryNamePrefix .. ' соли ' .. year .. ']]'; |
|||
else |
|||
return '' .. year; |
|||
end |
|||
end |
|||
function formatCentury( time, categoryNamePrefix ) |
|||
local moduleRoman = require( "Module:RomanNumber" ) |
|||
if ( time.year < 0 ) then |
|||
local century = math.floor( (math.abs( time.year) - 1) / 100 ) + 1; |
|||
if ( moduleRoman ) then |
|||
century = moduleRoman.toRomanNumber( century ); |
|||
end |
|||
if ( categoryNamePrefix ) then |
|||
return '[[асри ' .. century .. ' то милод]][[Гурӯҳ:' .. categoryNamePrefix .. ' соли ' .. century .. ' то милод]]' |
|||
else |
else |
||
out = '?' |
|||
return '[[асри ' .. century .. ' то милод]]' |
|||
end |
end |
||
else |
|||
if toOut ~= '' then |
|||
local century = math.floor( (time.year - 1) / 100 ) + 1; |
|||
out = out .. ' — ' .. toOut |
|||
if ( moduleRoman ) then |
|||
century = moduleRoman.toRomanNumber( century ); |
|||
end |
|||
if ( categoryNamePrefix ) then |
|||
return '[[асри ' .. century .. ']][[Гурӯҳ:' .. categoryNamePrefix .. ' асри ' .. century .. ']]' |
|||
else |
else |
||
if withinClaims ~= nil then |
|||
return '[[асри ' .. century .. ']]' |
|||
out = 'аз ' .. out |
|||
else |
|||
out = out .. ' — ' .. nowLabel |
|||
end |
|||
end |
end |
||
end |
end |
||
end |
|||
if out ~= '' then |
|||
function parseISO8601Date(str) |
|||
if options.before then |
|||
local pattern = "(%-?%d+)%-(%d+)%-(%d+)T" |
|||
out = options.before .. out |
|||
local Y, M, D = mw.ustring.match( str, pattern ) |
|||
end |
|||
return tonumber(Y), tonumber(M), tonumber(D) |
|||
if options.after then |
|||
end |
|||
out = out .. options.after |
|||
function parseISO8601Time(str) |
|||
local pattern = "T(%d+):(%d+):(%d+)%Z" |
|||
local H, M, S = mw.ustring.match( str, pattern) |
|||
return tonumber(H), tonumber(M), tonumber(S) |
|||
end |
|||
function parseISO8601Offset(str) |
|||
if str:sub(-1)=="Z" then return 0,0 end -- ends with Z, Zulu time |
|||
-- matches ±hh:mm, ±hhmm or ±hh; else returns nils |
|||
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 |
|||
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 |
||
end |
end |
||
local Y,M,D = parseISO8601Date(str) |
|||
return out |
|||
local h,m,s = parseISO8601Time(str) |
|||
local oh,om = parseISO8601Offset(str) |
|||
return tonumber(os.time({year=Y, month=M, day=D, hour=(h+oh), min=(m+om), sec=s})) |
|||
end |
end |
||
local lowestBoundary = parseISO8601('-900-02-20T00:00:00Z') |
local lowestBoundary = parseISO8601('-900-02-20T00:00:00Z') |
||
local mainBoundary = parseISO8601('1582-10- |
local mainBoundary = parseISO8601('1582-10-05T00:00:00Z') |
||
local lastBoundary = parseISO8601('1918-01- |
local lastBoundary = parseISO8601('1918-01-31T00:00:00Z'); |
||
boundaries = { |
local boundaries = { |
||
-- from (G) till next will be diff(G = J + diff), at current |
-- from (G) till next will be diff(G = J + diff), at current |
||
{ lowestBoundary, |
{ lowestBoundary, -9 }, |
||
{ parseISO8601('-700-02- |
{ parseISO8601('-700-02-29T00:00:00Z'), -8 }, |
||
{ parseISO8601('-600-02- |
{ parseISO8601('-600-02-29T00:00:00Z'), -7 }, |
||
{ parseISO8601('-500-02- |
{ parseISO8601('-500-02-29T00:00:00Z'), -6 }, |
||
{ parseISO8601('-300-02- |
{ parseISO8601('-300-02-29T00:00:00Z'), -5 }, |
||
{ parseISO8601('-200-02- |
{ parseISO8601('-200-02-29T00:00:00Z'), -4 }, |
||
{ parseISO8601('-100-02- |
{ parseISO8601('-100-02-29T00:00:00Z'), -3 }, |
||
{ parseISO8601('0000-00-00T00:00:00Z'), -2 }, |
{ parseISO8601('0000-00-00T00:00:00Z'), -2 }, |
||
{ parseISO8601('0100-02- |
{ parseISO8601('0100-02-29T00:00:00Z'), -1 }, |
||
{ parseISO8601('0200-02- |
{ parseISO8601('0200-02-29T00:00:00Z'), 0 }, |
||
{ parseISO8601('0300- |
{ parseISO8601('0300-02-29T00:00:00Z'), 1 }, |
||
{ parseISO8601('0500- |
{ parseISO8601('0500-02-29T00:00:00Z'), 2 }, |
||
{ parseISO8601('0600- |
{ parseISO8601('0600-02-29T00:00:00Z'), 3 }, |
||
{ parseISO8601('0700- |
{ parseISO8601('0700-02-29T00:00:00Z'), 4 }, |
||
{ parseISO8601('0900- |
{ parseISO8601('0900-02-29T00:00:00Z'), 5 }, |
||
{ parseISO8601('1000- |
{ parseISO8601('1000-02-29T00:00:00Z'), 6 }, |
||
{ parseISO8601('1100- |
{ parseISO8601('1100-02-29T00:00:00Z'), 7 }, |
||
{ parseISO8601('1300- |
{ parseISO8601('1300-02-29T00:00:00Z'), 8 }, |
||
{ parseISO8601('1400- |
{ parseISO8601('1400-02-29T00:00:00Z'), 9 }, |
||
{ parseISO8601('1500- |
{ parseISO8601('1500-02-29T00:00:00Z'), 10 }, |
||
{ parseISO8601('1700- |
{ parseISO8601('1700-02-29T00:00:00Z'), 11 }, |
||
{ parseISO8601('1800- |
{ parseISO8601('1800-02-29T00:00:00Z'), 12 }, |
||
{ parseISO8601('1900- |
{ parseISO8601('1900-02-29T00:00:00Z'), 13 }, |
||
{ lastBoundary, '' }, |
{ lastBoundary, '' }, |
||
}; |
}; |
||
-- Передаваемое время обязано быть по |
-- Передаваемое время обязано быть по Юлианскому календарю (старому стилю) |
||
function p.formatAsJulian( |
function p.formatAsJulian( julTime, infocardClass, categoryNamePrefix, leftBracket, rightBracket ) |
||
if 'table'==type( |
if 'table' == type( julTime ) then |
||
if |
if julTime.args and julTime.args[1] then |
||
julTime = tonumber( julTime.args[1] ) |
|||
else |
else |
||
return 'unknown argument type: ' .. type( |
return 'unknown argument type: ' .. type( julTime ) .. ': ' .. table.tostring( julTime ) |
||
end |
end |
||
end |
end |
||
local t = os.date("*t", |
local t = os.date( "*t", julTime ) |
||
if ( |
if ( julTime <= lowestBoundary ) then |
||
return "'' |
return "''таърихи носаҳеҳ (саҳеҳии дастнорас)''"; |
||
end |
end |
||
if ( |
if ( julTime >= lastBoundary ) then |
||
return "'' |
return "''таърихи носаҳеҳ (тақвими юлианӣ пас аз 1918-01-26 ба кор бурда мешавад)''"; |
||
end |
end |
||
Сатри 501: | Сатри 669: | ||
local b1 = boundaries[i][1]; |
local b1 = boundaries[i][1]; |
||
local b2 = boundaries[i + 1][1]; |
local b2 = boundaries[i + 1][1]; |
||
if ( b1 <= |
if ( b1 <= julTime and julTime < b2 ) then |
||
local b1s = os.date("*t", b1) |
local b1s = os.date( "*t", b1 ) |
||
if ( b1s.year == t.year and b1s.month == t.month and b1s.day == t.day) then |
if ( b1s.year == t.year and b1s.month == t.month and b1s.day == t.day) then |
||
if ( |
if ( julTime < mainBoundary ) then |
||
-- only julian |
-- only julian |
||
return moduleDates.formatWikiImpl( {year=t.year, month=2, day=29}, {year=t.year, month=2, day=29}, infocardClass, categoryNamePrefix ); |
return moduleDates.formatWikiImpl( {year=t.year, month=2, day=29}, {year=t.year, month=2, day=29}, infocardClass, categoryNamePrefix, leftBracket, rightBracket ); |
||
else |
else |
||
--julian and grigorian |
--julian and grigorian |
||
return moduleDates.formatWikiImpl( {year=t.year, month=2, day=29}, t, infocardClass, categoryNamePrefix ) |
return moduleDates.formatWikiImpl( {year=t.year, month=2, day=29}, t, infocardClass, categoryNamePrefix, leftBracket, rightBracket ) |
||
end |
end |
||
else |
else |
||
local |
local gregTime = os.date( "*t", julTime + boundaries[i][2] * 24 * 60 * 60 ); |
||
if ( |
if ( julTime < mainBoundary ) then |
||
-- only julian |
-- only julian |
||
return moduleDates.formatWikiImpl( |
return moduleDates.formatWikiImpl( t, t, infocardClass, categoryNamePrefix, leftBracket, rightBracket ); |
||
else |
else |
||
--julian and grigorian |
--julian and grigorian |
||
return moduleDates.formatWikiImpl( |
return moduleDates.formatWikiImpl( t, gregTime, infocardClass, categoryNamePrefix, leftBracket, rightBracket ) |
||
end |
end |
||
end |
end |
||
Сатри 524: | Сатри 692: | ||
end |
end |
||
if ( |
if ( julTime >= lastBoundary ) then |
||
return "''хато дар модули |
return "''хато дар модули Модул:Wikidata/date (тағйири табдили тақвим ёфт нашуд)''"; |
||
end |
end |
||
end |
end |
Нусхаи кунунӣ то 06:06, 23 феврали 2023
Вычисляет и отображает даты рождения и смерти из Викидода с поддержкой отображения дат по старому стилю, если в Викиданных указана модель пролептического юлианского календаря (d:Q1985786).
Вызов всех функций данного шаблона осуществляется только из промежуточных шаблонов wikidata/pNNN:
- p.dateOfBirth ← {{wikidata/p569}}
- p.dateOfDeath ← {{wikidata/p570}}
- p.formatBirthDate ← Модул:Wikidata ← p.dateOfBirth ← {{wikidata/p569}}
- p.formatDeathDate ← Модул:Wikidata ← p.dateOfDeath ← {{wikidata/p570}}
Вызов функций шаблонов из других модулей и шаблонов запрещён и делается на страх и риск авторов соответствующих «костылей», вместе с возлаганием на них обязательств по поддержке в случае изменений названий модуля, названий функций или спецификаций вызовов.
Санҷишҳо
[вироиши манбаъ]12 тестов провалено.
test_formatAsJulian:
Текст | Ожидаемое значение | Фактическое значение | |
---|---|---|---|
{{#invoke:Wikidata/date | formatAsJulian |-14826758400}} | 28 феврали 1500 | 28 феврал 1500 | |
{{#invoke:Wikidata/date | formatAsJulian |-14826672000}} | 29 феврали 1500 | 29 феврал 1500 | |
{{#invoke:Wikidata/date | formatAsJulian |-14826585600}} | 1 марти 1500 | 2 март 1500 | |
{{#invoke:Wikidata/date | formatAsJulian |-11670220800}} | 28 феврал (9 марти) 1600 | 9 (19) март 1600 | |
{{#invoke:Wikidata/date | formatAsJulian |-11670134400}} | 29 феврал (10 марти) 1600 | 10 (20) март 1600 | |
{{#invoke:Wikidata/date | formatAsJulian |-11670048000}} | 1 (11) марти 1600 | 11 (21) март 1600 | |
{{#invoke:Wikidata/date | formatAsJulian | -8514460800}} | 28 феврал (10 марти) 1700 | 10 (21) март 1700 | |
{{#invoke:Wikidata/date | formatAsJulian | -8514374400}} | 29 феврал (11 марти) 1700 | 11 (22) март 1700 | |
{{#invoke:Wikidata/date | formatAsJulian | -8514288000}} | 1 (12) марти 1700 | 12 (23) март 1700 | |
{{#invoke:Wikidata/date | formatAsJulian | -2208988800}} | 20 декабри 1899 (1 январи 1900) | 1 (13) январ 1900 | |
{{#invoke:Wikidata/date | formatAsJulian | -1734480000}} | 2 (15) январи 1915 | 15 (28) январ 1915 | |
{{#invoke:Wikidata/date | formatAsJulian | 946684800}} | некорректная дата (юлианский не используется после 1918-01-26) | таърихи носаҳеҳ (тақвими юлианӣ пас аз 1918-01-26 ба кор бурда мешавад) |
--settings
local categoryUnknownBirthDate = '[[Гурӯҳ:Ашхосе, ки таърихи таваллудашон оварда нашудааст]]';
local categoryUnknownDeathDate = '[[Гурӯҳ:Ашхосе, ки таърихи даргузашташон оварда нашудааст]]';
local categoryBigCurrentAge = '[[Гурӯҳ:Википедия:Мақолаҳо дар бораи ашхоси бо синну соли калони ҷорӣ]]'
-- local categoryBigDeathAge = '[[Гурӯҳ:Википедия:Мақолаҳо дар бораи ашхоси солманд дар замони даргузашт]]' //deleted -d.bratchuk 05-07-2016
local categoryBiographiesOfLivingPersons = '[[Гурӯҳ:Википедия:Зиндагиномаи муосирон]]'
local categoryRecentlyDeceased = '[[Гурӯҳ:Википедия:Ашхосе, ки то як соли пеш даргузаштанд]]'
local nowLabel = 'то ҳол'
local moduleDates = require( "Module:Dates" )
local moduleWikidata = require( "Module:Wikidata" )
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 -- number, string, boolean, etc
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
-- accepts table of time+precision values
local 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
local 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
if ( bValue.calendar == 'julian' and dValue.calendar == 'gregorian' ) then
-- to calculate age, need to adjust bStructure to gregorian calendar
local shift = math.floor(bStructure.year/100-2) - math.floor(bStructure.year/400)
-- TODO: re-implement this properly
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 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+)%Z"
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 -- ends with Z, Zulu time
-- matches ±hh:mm, ±hhmm or ±hh; else returns nils
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
-- The calendar model used for saving the data is always the proleptic Gregorian calendar according to ISO 8601.
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
-- novalue
return { unknown="novalue" };
else
--unknown
return { unknown="unknown" };
end
end
-- returns table of time+precision values for specified property
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 result = {}
for key, claim in pairs( claims ) do
table.insert ( result, parseClaim( claim ) );
end
return result
end
-- проверка на совпадающие даты с разной моделью календаря
local 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
-- returns first qualifier of specified propertyId
local function getQualifierWithDataValue( statement, qualifierPropertyId )
if ( statement.qualifiers
and statement.qualifiers[qualifierPropertyId] ) then
local qualifiers = statement.qualifiers[qualifierPropertyId];
for _, qualifier in ipairs( qualifiers ) do
if (qualifier.datavalue) then
return qualifier;
end
end
end
return nil;
end
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 year .. '-уми то м. [[Category:' .. categoryNamePrefix .. ' солҳои ' .. year .. '-уми то м.]]';
else
return '' .. year .. ' то м.';
end
else
local year = math.floor( time.year / 10 ) * 10;
if ( categoryNamePrefix ) then
return year .. '-ум[[Category:' .. categoryNamePrefix .. ' солҳои ' .. year .. '-ум]]';
else
return '' .. year;
end
end
end
local function formatCentury( time, categoryNamePrefix )
local moduleRoman = require( "Module:RomanNumber" )
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 '[[асри ' .. century .. ' то м.]][[Category:' .. categoryNamePrefix .. ' асри ' .. century .. ' то м.]]'
else
return '[[асри ' .. century .. ' то м.]]'
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 .. ']][[Category:' .. categoryNamePrefix .. ' асри ' .. century .. ']]'
else
return '[[асри ' .. century .. ']]'
end
end
end
local function formatMillenium( time, categoryNamePrefix )
if ( time.year < 0 ) then
local millenium = math.floor( (math.abs( time.year) - 1) / 1000 ) + 1;
if ( categoryNamePrefix ) then
if ( millenium == 2 ) then
return '[[ҳазорсолаи ' .. millenium .. ' то м.]][[Category:' .. categoryNamePrefix .. ' ҳазорсолаи ' .. millenium .. ' то м.]]'
else
return '[[ҳазорсолаи ' .. millenium .. ' то м.]][[Category:' .. categoryNamePrefix .. ' ҳазорсолаи ' .. millenium .. ' то м.]]'
end
else
return '[[ҳазорсолаи ' .. millenium .. ' то м.]]'
end
else
local millenium = math.floor( (time.year - 1) / 1000 ) + 1;
if ( categoryNamePrefix ) then
if ( millenium == 2 ) then
return '[[ҳазорсолаи ' .. millenium .. ']][[Category:' .. categoryNamePrefix .. ' ҳазорсолаи ' .. millenium .. ']]'
else
return '[[ҳазорсолаи ' .. millenium .. ']][[Category:' .. categoryNamePrefix .. ' ҳазорсолаи ' .. millenium .. ']]'
end
else
return '[[ҳазорсолаи ' .. millenium .. ']]'
end
end
end
local function formatDateImpl( value, options, microformatClass, categoryPrefix, leftBracket, rightBracket )
if ( not value ) then error( 'value not specified'); end;
if ( not options ) then error( 'options not specified'); end;
-- The calendar model used for saving the data is always the proleptic Gregorian calendar according to ISO 8601.
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, infoclass, categoryPrefix, leftBracket, rightBracket )
end
-- year and month only
if precision == 10 then
local tCopy = deepcopy( structure )
tCopy.day = nil
return moduleDates.formatWikiImpl(tCopy, tCopy, infoclass, categoryPrefix, leftBracket, rightBracket )
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 )
else
return p.formatAsJulian( unixtime, infoclass, categoryPrefix, leftBracket, rightBracket )
end
end
local function formatApproximateDateClaim( context, options, statement )
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 categoryUnknownBirthDate = "" 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 )
local value = 'на пештар аз ' .. 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 )
local value = 'на дертар аз ' .. context.wrapSnak( formattedDate, qNotLaterThan.hash )
table.insert( results, context.wrapQualifier( value, 'P1326' ) );
end
return mw.text.listToText( results, ' и ' , ' и ' ) .. categoryUnknownBirthDate;
end
return nil
end
function p.formatDateOfBirthClaim( context, options, statement )
local value = formatApproximateDateClaim( context, options, statement )
if value then
return value
end
options['conjunction'] = ' ё ';
options['value-module'] = 'Wikidata/date';
options['value-function'] = 'formatBirthDate';
options.i18n.somevalue = '\'\'номаълум\'\'' .. categoryUnknownBirthDate;
local result = context.formatStatementDefault( context, options, statement );
local bTable = { parseClaim( statement ) };
local dTable = parseProperty ( context, options, 'P570' )
if ( bTable and not dTable ) then
local age = ageCurrent( bTable )
if ( age ) then
if ( options.suppressAge == nil or options.suppressAge == '' ) then
result = result .. ' <span style="white-space:nowrap;">(' .. age .. ' ' .. mw.language.new( 'tg' ):plural( age, 'сол', 'сол', 'сола') .. ')</span>'
end
if ( not options.nocat ) then
if ( age > 115 ) then
result = result .. categoryBigCurrentAge;
else
result = result .. categoryBiographiesOfLivingPersons;
end
end
end
end
return result;
end
function p.formatDateOfDeathClaim( context, options, statement )
local value = formatApproximateDateClaim( context, options, statement )
if value then
return value
end
options['conjunction'] = ' ё ';
options['value-module'] = 'Wikidata/date';
options['value-function'] = 'formatDeathDate';
options.i18n.somevalue = '\'\'номаълум\'\'' .. categoryUnknownDeathDate;
local result = context.formatStatementDefault( context, options, statement );
local bTable = parseProperty ( context, options, 'P569' )
local dTable = { parseClaim( statement ) };
if ( bTable and dTable ) then
local age = age( bTable, dTable )
if ( age ) then
if ( options.suppressAge == nil or options.suppressAge == '' ) then
result = result .. ' <span style="white-space:nowrap;">(' .. age .. ' ' .. mw.language.new( 'tg' ):plural( age, 'сол', 'сол', 'сола') .. ')</span>'
end
end
-- returns category to recently deceased persons
local unixAvailable, unixDateOfDeath = pcall(function()
local r = os.time(dTable[1].structure)
if ( r ~= os.time() ) then
return r
end
error()
end)
if ( unixAvailable and os.time() - unixDateOfDeath < 31536000 and not options.nocat ) then
result = result .. categoryRecentlyDeceased
end
end
return result;
end
-- Reentry point for Wikidata Snak formatting
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 )
else
return formatDateImpl( value, options, microformatClass, 'Зодагони', options.leftBracket, options.rightBracket )
end
end
-- Reentry point for Wikidata Snak formatting
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 )
else
return formatDateImpl( value, options, microformatClass, 'Даргузаштагони', options.leftBracket, options.rightBracket )
end
end
-- Reentry point for Wikidata Snak formatting -- default one
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 )
else
local categoryPrefix = options.categoryPrefix or nil;
return formatDateImpl( value, options, microformatClass, categoryPrefix, options.leftBracket, options.rightBracket )
end
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
if withinClaims ~= 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
local lowestBoundary = parseISO8601('-900-02-20T00:00:00Z')
local mainBoundary = parseISO8601('1582-10-05T00:00:00Z')
local lastBoundary = parseISO8601('1918-01-31T00:00:00Z');
local boundaries = {
-- from (G) till next will be diff(G = J + diff), at current
{ 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 )
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 "''таърихи носаҳеҳ (саҳеҳии дастнорас)''";
end
if ( julTime >= lastBoundary ) then
return "''таърихи носаҳеҳ (тақвими юлианӣ пас аз 1918-01-26 ба кор бурда мешавад)''";
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
-- only julian
return moduleDates.formatWikiImpl( {year=t.year, month=2, day=29}, {year=t.year, month=2, day=29}, infocardClass, categoryNamePrefix, leftBracket, rightBracket );
else
--julian and grigorian
return moduleDates.formatWikiImpl( {year=t.year, month=2, day=29}, t, infocardClass, categoryNamePrefix, leftBracket, rightBracket )
end
else
local gregTime = os.date( "*t", julTime + boundaries[i][2] * 24 * 60 * 60 );
if ( julTime < mainBoundary ) then
-- only julian
return moduleDates.formatWikiImpl( t, t, infocardClass, categoryNamePrefix, leftBracket, rightBracket );
else
--julian and grigorian
return moduleDates.formatWikiImpl( t, gregTime, infocardClass, categoryNamePrefix, leftBracket, rightBracket )
end
end
end
end
if ( julTime >= lastBoundary ) then
return "''хато дар модули Модул:Wikidata/date (тағйири табдили тақвим ёфт нашуд)''";
end
end
return p