Відмінності між версіями «Модуль:Dates»

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку
[перевірена версія][перевірена версія]
(додав обробку років до нашої ери для категорій дат народження та смерті)
(оновлення даних)
Рядок 1: Рядок 1:
  +
--[[ В этом модуле собраны функции, связанные с работой с датами.]]
--[[
 
  +
local monthg = {'січня', 'лютого', 'березня', 'квітня', 'травня', 'червня',
В это модуле собраны функции, связанные с работой с датами.
 
  +
'липня', 'серпня', "вересня", "жовтня", "листопада", "грудня"}
]]
 
  +
local monthg = {'січня', 'лютого', 'березня', 'квітня', 'травня', 'червня', 'липня', 'серпня', 'вересня',
 
'жовтня', 'листопада', 'грудня'}
 
 
 
local monthd = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
 
local monthd = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
  +
 
 
local function DecodeDate(d)-- Ч, М, Г, СЧ, СМ, СГ, хвост
 
local function DecodeDate(d)-- Ч, М, Г, СЧ, СМ, СГ, хвост
 
--дата: "%-?%d+"=год, "%d+%.%d+"=число месяца, "%d+%.%d+%.%-?%d+"=ЧМГ,
 
--дата: "%-?%d+"=год, "%d+%.%d+"=число месяца, "%d+%.%d+%.%-?%d+"=ЧМГ,
Рядок 33: Рядок 31:
 
end
 
end
 
end
 
end
  +
 
 
local function Diffy(d1,m1,y1,d0,m0,y0)--аналог Персона/Дата/Прошло лет
 
local function Diffy(d1,m1,y1,d0,m0,y0)--аналог Персона/Дата/Прошло лет
 
return y1-y0 - ( y1*y0<=0 and 1 or 0 ) - ( (m1<m0 or m1==m0 and d1<d0) and 1 or 0 )
 
return y1-y0 - ( y1*y0<=0 and 1 or 0 ) - ( (m1<m0 or m1==m0 and d1<d0) and 1 or 0 )
 
end
 
end
  +
 
 
local function Year0(y,t)-- аналог Год0
 
local function Year0(y,t)-- аналог Год0
 
if y>0 then return table.concat{
 
if y>0 then return table.concat{
'[[', tostring(y), '|', t and tostring(y)..'&nbsp;'..t or tostring(y), ']]'
+
'[[', tostring(y), ' рік|', t and tostring(y)..'&nbsp;'..t or tostring(y), ']]'
 
} else return table.concat{
 
} else return table.concat{
'[[', tostring(-y), ' до н. е.|',
+
'[[', tostring(-y), ' рік до н. е.|',
 
t and tostring(-y)..'&nbsp;'..t or tostring(-y),
 
t and tostring(-y)..'&nbsp;'..t or tostring(-y),
 
'&nbsp;до&nbsp;н.&nbsp;е.]]'
 
'&nbsp;до&nbsp;н.&nbsp;е.]]'
Рядок 48: Рядок 46:
 
end
 
end
 
end
 
end
  +
 
 
local function FormDate(j,m,y,oj,om,oy,mo)-- ~ Персона/Дата/Logic 4
 
local function FormDate(j,m,y,oj,om,oy,mo)-- ~ Персона/Дата/Logic 4
 
if j then
 
if j then
Рядок 54: Рядок 52:
 
if y then return
 
if y then return
 
string.format(
 
string.format(
'<span style="white-space:nowrap;">%s<span style="display:none">(<span class="%s">%04i-%02i-%02i</span>)</span></span>',
+
'<span class="nowrap">%s<span style="display:none">(<span class="%s">%04i-%02i-%02i</span>)</span></span>',
 
table.concat(
 
table.concat(
 
oj and (
 
oj and (
Рядок 60: Рядок 58:
 
oy and {-- ДД ММММ ГГГГ ([[ДД ММММ]] [[ГГГГ]])
 
oy and {-- ДД ММММ ГГГГ ([[ДД ММММ]] [[ГГГГ]])
 
oj,'&nbsp;',monthg[om],'&nbsp;',oy,
 
oj,'&nbsp;',monthg[om],'&nbsp;',oy,
'</span> <span style="white-space:nowrap;">([[',
+
'</span> <span class="nowrap">([[',
 
j, ' ', monthg[m],']] ',Year0(y),')'
 
j, ' ', monthg[m],']] ',Year0(y),')'
 
} or {-- ДД ММММ ([[ДД ММММ]]) [[ГГГГ]]
 
} or {-- ДД ММММ ([[ДД ММММ]]) [[ГГГГ]]
 
oj,'&nbsp;',monthg[om],' ([[',j,'&nbsp;',monthg[m],']]) ',Year0(y)
 
oj,'&nbsp;',monthg[om],' ([[',j,'&nbsp;',monthg[m],']]) ',Year0(y)
 
}
 
}
) or {-- [[ДД ММММ|ДД (ДД) ММММ]] [[ГГГГ]]
+
) or {-- ДД [[ДД ММММ|(ДД) ММММ]] [[ГГГГ]]
'[[',j,' ',monthg[m],'|',oj,'&nbsp;(',j,')&nbsp;',monthg[m],']] ',Year0(y)
+
oj,'&nbsp;[[',j,' ',monthg[m],'|','(',j,')&nbsp;',monthg[m],']] ',Year0(y)
 
}
 
}
 
) or {'[[',j,'&nbsp;',monthg[m],']]&nbsp;',Year0(y)}
 
) or {'[[',j,'&nbsp;',monthg[m],']]&nbsp;',Year0(y)}
Рядок 74: Рядок 72:
 
)--/string.format
 
)--/string.format
 
else return
 
else return
'<span style="white-space:nowrap;">' .. table.concat(
+
'<span class="nowrap">' .. table.concat(
 
oj and (
 
oj and (
 
om and {-- ДД ММММ ([[ДД ММММ]])
 
om and {-- ДД ММММ ([[ДД ММММ]])
 
oj,'&nbsp;',monthg[om],' ([[',j,'&nbsp;',monthg[m],']])</span>'
 
oj,'&nbsp;',monthg[om],' ([[',j,'&nbsp;',monthg[m],']])</span>'
} or {-- [[ДД ММММ|ДД (ДД) ММММ]]
+
} or {-- ДД [[ДД ММММ|(ДД) ММММ]]
'[[',j,' ',monthg[m],'|',oj,'&nbsp;(',j,')&nbsp;',monthg[m],']]</span>'
+
oj,'&nbsp;[[',j,' ',monthg[m],'|','(',j,')&nbsp;',monthg[m],']]</span>'
 
}
 
}
 
) or {'[[',j,'&nbsp;',monthg[m],']]</span>'}
 
) or {'[[',j,'&nbsp;',monthg[m],']]</span>'}
Рядок 86: Рядок 84:
 
else
 
else
 
return y and string.format(
 
return y and string.format(
'<span style="white-space:nowrap;">%s<span style="display:none;">(<span class="bday">%04i</span>)</span></span>',
+
'<span class="nowrap">%s<span style="display:none;">(<span class="bday">%04i</span>)</span></span>',
 
Year0(y,'рік'),y) or "''хибний формат''"
 
Year0(y,'рік'),y) or "''хибний формат''"
 
end
 
end
 
end
 
end
  +
 
 
local function GetDate(D)--dd.mm.-?yyyy или -?yyyy-mm-dd в три переменных d,m,y
 
local function GetDate(D)--dd.mm.-?yyyy или -?yyyy-mm-dd в три переменных d,m,y
 
local d,m,y = d:match('^%s*(%d%d?)[/.]([01]?%d)[/.](%-?%d+)')
 
local d,m,y = d:match('^%s*(%d%d?)[/.]([01]?%d)[/.](%-?%d+)')
Рядок 96: Рядок 94:
 
return tonumber(d),tonumber(m),tonumber(y)
 
return tonumber(d),tonumber(m),tonumber(y)
 
end
 
end
  +
 
 
local function Cmp(a,b)--Сравнивает две даты, результат соответственно -1, 0 или 1
 
local function Cmp(a,b)--Сравнивает две даты, результат соответственно -1, 0 или 1
 
local d1,m1,y1 = GetDate(a)
 
local d1,m1,y1 = GetDate(a)
Рядок 108: Рядок 106:
 
)
 
)
 
end
 
end
  +
 
 
local function Yyyymmdd(r)--Переводит русскую дату в YYYY,MM,DD
 
local function Yyyymmdd(r)--Переводит русскую дату в YYYY,MM,DD
local d,m,y,M=mw.ustring.match(r, "^%s*(%d%d?)%s+([а-яА-Я]+)%s+(%d+)")
+
local d, m, y, M = mw.ustring.match(r, "^%s*(%d%d?)%s+([а-яА-Я]+)%s+(%d+)")
 
if not m then return nil end
 
if not m then return nil end
m=mw.ustring.lower(m)
+
m = mw.ustring.lower(m)
  +
for i=1,12 do if m==monthg[i] then M=i;break end end--тупо перебор
 
  +
--тупо перебор
if not M then return nil end
 
  +
for i = 1, 12 do
return tonumber(y),M,tonumber(d)
 
  +
if m == monthg[i] then
  +
M = i
  +
break
  +
end
  +
end
  +
  +
if not M then
  +
return nil
  +
end
  +
return tonumber(y), M, tonumber(d)
 
end
 
end
  +
 
 
local p = {}
 
local p = {}
  +
 
 
p = {
 
p = {
  +
 
 
ifdate=function(f)-- Для шаблона "Если дата", имитирует старое поведение
 
ifdate=function(f)-- Для шаблона "Если дата", имитирует старое поведение
 
-- Аргументы передаются шаблону
 
-- Аргументы передаются шаблону
 
return f:getParent().args[ mw.ustring.match(frame.args[1],"^[ %d.%-−%()]*$") and 2 or 3 ]
 
return f:getParent().args[ mw.ustring.match(frame.args[1],"^[ %d.%-−%()]*$") and 2 or 3 ]
 
end;
 
end;
  +
 
DecodeDate=DecodeDate;Diffy=Diffy;Year0=Year0;GetDate=GetDate;Cmp=Cmp;
+
DecodeDate = DecodeDate;
  +
Diffy = Diffy;
Yyymmdd=Yyymmdd;
 
  +
Year0 = Year0;
 
  +
GetDate = GetDate;
diffy=function(f)-- принимает параметры #invoke в виде двух строк-дат
 
  +
Cmp = Cmp;
  +
Yyyymmdd = Yyyymmdd;
  +
  +
diffy = function(f)-- принимает параметры #invoke в виде двух строк-дат
 
local d1,m1,y1=DecodeDate(f.args[1]);
 
local d1,m1,y1=DecodeDate(f.args[1]);
 
local d0,m0,y0=DecodeDate(f.args[2])
 
local d0,m0,y0=DecodeDate(f.args[2])
 
return Diffy(d1,m1,y1,d0,m0,y0)
 
return Diffy(d1,m1,y1,d0,m0,y0)
 
end;
 
end;
  +
 
 
monthg=function(f) return monthg[ f.args[1] or f:getParent().args[1] ] end;--realmonth
 
monthg=function(f) return monthg[ f.args[1] or f:getParent().args[1] ] end;--realmonth
  +
 
 
persdate=function(f)-- Для шаблона Персона/Дата;{{#invoke:dates|persdate|nocat={{NAMESPACE}}}}
 
persdate=function(f)-- Для шаблона Персона/Дата;{{#invoke:dates|persdate|nocat={{NAMESPACE}}}}
 
local frame=f:getParent();
 
local frame=f:getParent();
Рядок 154: Рядок 166:
 
FormDate(j,m,y,oj,om,oy,mo),
 
FormDate(j,m,y,oj,om,oy,mo),
 
( (frame.args['nopersoncat'] or '')~='' or (f.args['nocat'] or '')~='' ) and '' or table.concat{
 
( (frame.args['nopersoncat'] or '')~='' or (f.args['nocat'] or '')~='' ) and '' or table.concat{
'[[К:Персоналии по алфавиту]]',
+
'[[Категорія:Персоналії за алфавітом]]',
 
j and string.format('[[Категорія:%s %i %s]]',catpref[mo],j,monthg[m]) or '',
 
j and string.format('[[Категорія:%s %i %s]]',catpref[mo],j,monthg[m]) or '',
y and string.format('[[Категорія:%s %s]]',catpref[mo],y) or ''
+
y and string.format('[[Категорія:%s в %s]]',catpref[mo],y,Year0(y,'році')) or ''
 
},--/table.concat внутр.
 
},--/table.concat внутр.
 
(function(F)--возраст
 
(function(F)--возраст
Рядок 181: Рядок 193:
 
}--/table.concat внеш.
 
}--/table.concat внеш.
 
end;
 
end;
  +
 
 
formdate=function(f) -- Формирует дату по 3--6 параметрам #invoke или шаблона
 
formdate=function(f) -- Формирует дату по 3--6 параметрам #invoke или шаблона
 
--не использовать с пустыми аргументами
 
--не использовать с пустыми аргументами
Рядок 191: Рядок 203:
 
end
 
end
 
end;
 
end;
  +
 
 
cmp=function(f)--Сравнивает две даты, результат соответственно -1, 0 или 1
 
cmp=function(f)--Сравнивает две даты, результат соответственно -1, 0 или 1
 
return Cmp(f.args[1],f.args[2])
 
return Cmp(f.args[1],f.args[2])
 
end;
 
end;
  +
 
 
G2J=function(f)--перевод григорианских дат в юлианские, возврат DD.MM.YYYY
 
G2J=function(f)--перевод григорианских дат в юлианские, возврат DD.MM.YYYY
 
--Не знает про 15 октября 1582 года, не работает до нашей эры и после ???99 года
 
--Не знает про 15 октября 1582 года, не работает до нашей эры и после ???99 года
Рядок 228: Рядок 240:
 
end
 
end
 
end;
 
end;
  +
 
  +
-- Переводить українську дату в YYYY-MM-DD. Повертає вихідне значення, якщо дата вже в цьому форматі
yyyymmdd = function(f)--Переводит русскую дату в YYYY-MM-DD
 
  +
yyyymmdd = function(f)
local y,m,d=Yyyymmdd(f.args[1])
 
  +
local date, hourmin = f.args[1]
return string.format('%4i-%02i-%02i',y,m,d)
 
  +
if mw.ustring.match(date, "^%s*%d+\-%d+\-%d+") then
  +
return date
  +
end
  +
hourmin = mw.ustring.match(date, "%s+%d+:%d+$")
  +
local y, m, d = Yyyymmdd(date)
  +
if not y then
  +
return '<span class="error">Помилка: некоректний формат дати.</span>'
  +
end
  +
return string.format('%4i-%02i-%02i', y, m, d) .. (hourmin or '')
 
end
 
end
 
}
 
}
  +
 
 
function table.val_to_str ( v )
 
function table.val_to_str ( v )
 
if "string" == type( v ) then
 
if "string" == type( v ) then
Рядок 247: Рядок 268:
 
end
 
end
 
end
 
end
  +
 
 
function table.key_to_str ( k )
 
function table.key_to_str ( k )
 
if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then
 
if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then
Рядок 255: Рядок 276:
 
end
 
end
 
end
 
end
  +
 
 
function table.tostring( tbl )
 
function table.tostring( tbl )
 
local result, done = {}, {}
 
local result, done = {}, {}
Рядок 270: Рядок 291:
 
return "{" .. table.concat( result, "," ) .. "}"
 
return "{" .. table.concat( result, "," ) .. "}"
 
end
 
end
  +
 
 
function parseISO8601Date(str)
 
function parseISO8601Date(str)
 
local pattern = "(%-?%d+)%-(%d+)%-(%d+)T"
 
local pattern = "(%-?%d+)%-(%d+)%-(%d+)T"
Рядок 276: Рядок 297:
 
return tonumber(Y), tonumber(M), tonumber(D)
 
return tonumber(Y), tonumber(M), tonumber(D)
 
end
 
end
  +
 
 
function parseISO8601Time(str)
 
function parseISO8601Time(str)
 
local pattern = "T(%d+):(%d+):(%d+)%Z"
 
local pattern = "T(%d+):(%d+):(%d+)%Z"
Рядок 282: Рядок 303:
 
return tonumber(H), tonumber(M), tonumber(S)
 
return tonumber(H), tonumber(M), tonumber(S)
 
end
 
end
  +
 
 
function parseISO8601Offset(str)
 
function parseISO8601Offset(str)
 
if str:sub(-1)=="Z" then return 0,0 end -- ends with Z, Zulu time
 
if str:sub(-1)=="Z" then return 0,0 end -- ends with Z, Zulu time
  +
 
 
-- matches ±hh:mm, ±hhmm or ±hh; else returns nils
 
-- matches ±hh:mm, ±hhmm or ±hh; else returns nils
 
local pattern = "([-+])(%d%d):?(%d?%d?)$"
 
local pattern = "([-+])(%d%d):?(%d?%d?)$"
 
local sign, oh, om = mw.ustring.match( str, pattern)
 
local sign, oh, om = mw.ustring.match( str, pattern)
 
sign, oh, om = sign or "+", oh or "00", om or "00"
 
sign, oh, om = sign or "+", oh or "00", om or "00"
  +
 
 
return tonumber(sign .. oh), tonumber(sign .. om)
 
return tonumber(sign .. oh), tonumber(sign .. om)
 
end
 
end
  +
 
 
function p.parseISO8601(str)
 
function p.parseISO8601(str)
 
if 'table'==type(str) then
 
if 'table'==type(str) then
Рядок 307: Рядок 328:
 
return tonumber(os.time({year=Y, month=M, day=D, hour=(h+oh), min=(m+om), sec=s}))
 
return tonumber(os.time({year=Y, month=M, day=D, hour=(h+oh), min=(m+om), sec=s}))
 
end
 
end
  +
 
 
local g2uBoundary1 = p.parseISO8601('1582-10-15T00:00:00Z')
 
local g2uBoundary1 = p.parseISO8601('1582-10-15T00:00:00Z')
 
local g2uBoundary2 = p.parseISO8601('1700-03-12T00:00:00Z')
 
local g2uBoundary2 = p.parseISO8601('1700-03-12T00:00:00Z')
 
local g2uBoundary3 = p.parseISO8601('1800-03-13T00:00:00Z')
 
local g2uBoundary3 = p.parseISO8601('1800-03-13T00:00:00Z')
 
local g2uBoundary4 = p.parseISO8601('1900-03-14T00:00:00Z')
 
local g2uBoundary4 = p.parseISO8601('1900-03-14T00:00:00Z')
local g2uBoundary5 = p.parseISO8601('1918-01-26T00:00:00Z') -- декрет Ленина
+
local g2uBoundary5 = p.parseISO8601('1918-01-26T00:00:00Z') -- декрет Леніна
  +
 
 
-- Передаваемое время обязано быть по Григорианскому календарю (новому стилю)
 
-- Передаваемое время обязано быть по Григорианскому календарю (новому стилю)
 
function p.formatWiki( time, infocardClass, categoryNamePrefix )
 
function p.formatWiki( time, infocardClass, categoryNamePrefix )
Рядок 325: Рядок 346:
 
local t = os.date("*t", time)
 
local t = os.date("*t", time)
 
if time < g2uBoundary1 then
 
if time < g2uBoundary1 then
  +
-- виводимо лише юліанський календар. Задавати тут григоріанський некоректно
-- выводим просто юлианский календарь. Задавать тут григорианский некорректно
 
 
return p.formatWikiImpl( t, t, infocardClass, categoryNamePrefix )
 
return p.formatWikiImpl( t, t, infocardClass, categoryNamePrefix )
 
end
 
end
+
  +
-- Спеціальні дати
-- Специальные даты
 
 
if t.year == 1700 and t.month == 3 and t.day == 11 then
 
if t.year == 1700 and t.month == 3 and t.day == 11 then
 
return p.formatWikiImpl( {year=1700, month=2, day=29}, t, infocardClass, categoryNamePrefix)
 
return p.formatWikiImpl( {year=1700, month=2, day=29}, t, infocardClass, categoryNamePrefix)
Рядок 339: Рядок 360:
 
return p.formatWikiImpl( {year=1900, month=2, day=29}, t, infocardClass, categoryNamePrefix )
 
return p.formatWikiImpl( {year=1900, month=2, day=29}, t, infocardClass, categoryNamePrefix )
 
end
 
end
  +
 
 
if g2uBoundary1 <= time and time < g2uBoundary2 then
 
if g2uBoundary1 <= time and time < g2uBoundary2 then
 
return p.formatWikiImpl( os.date("*t", time - 10 * 24 * 60 * 60), t, infocardClass, categoryNamePrefix )
 
return p.formatWikiImpl( os.date("*t", time - 10 * 24 * 60 * 60), t, infocardClass, categoryNamePrefix )
Рядок 352: Рядок 373:
 
return p.formatWikiImpl( os.date("*t", time - 13 * 24 * 60 * 60), t, infocardClass, categoryNamePrefix )
 
return p.formatWikiImpl( os.date("*t", time - 13 * 24 * 60 * 60), t, infocardClass, categoryNamePrefix )
 
end
 
end
  +
 
  +
--тільки Григоріанський календар
--только Григорианский календарь
 
 
return p.formatWikiImpl( t, t, infocardClass, categoryNamePrefix )
 
return p.formatWikiImpl( t, t, infocardClass, categoryNamePrefix )
 
end
 
end
  +
 
 
function ternary ( cond , T , F )
 
function ternary ( cond , T , F )
 
if cond then return T else return F end
 
if cond then return T else return F end
 
end
 
end
  +
 
local nominativeMonthes = {'січень', 'лютий', 'березень', 'квітень', 'травень', 'червень', 'липень', 'серпень', 'вересень',
+
local nominativeMonthes = {'січень', 'лютий', 'березень', 'квітень', 'травень', 'червень',
'жовтень', 'листопад', 'грудень'}
+
'липень', 'серпень', 'вересень', 'жовтень', 'листопад', 'грудень'}
  +
 
local genitivusMonthes = {'січня', 'лютого', 'березня', 'квітня', 'травня', 'червня', 'липня', 'серпня', 'вересня',
+
local genitivusMonthes = {'січня', 'лютого', 'березня', 'квітня', 'травня', 'червня',
'жовтня', 'листопада', 'грудня'}
+
'липня', 'серпня', 'вересня', 'жовтня', 'листопада', 'грудня'}
  +
 
 
function nominativeYear( year )
 
function nominativeYear( year )
 
if ( year >= 0 ) then
 
if ( year >= 0 ) then
return '[[' .. year .. ']]'
+
return '[[' .. year .. ' рік|' .. year .. ']]'
 
else
 
else
return '[[' .. ( 0 - year ) .. ' до н. е.]]'
+
return '[[' .. ( 0 - year ) .. ' рік до н. е.|' .. ( 0 - year ) .. ' до н. е.]]'
 
end
 
end
 
end
 
end
  +
 
 
function inYear( year )
 
function inYear( year )
 
if ( year >= 0 ) then
 
if ( year >= 0 ) then
Рядок 382: Рядок 403:
 
end
 
end
 
end
 
end
  +
 
 
-- рік для категорій народження та смерті
 
-- рік для категорій народження та смерті
 
function catbdYear( year )
 
function catbdYear( year )
Рядок 389: Рядок 410:
 
else
 
else
 
return '' .. ( 0 - year) .. ' до н. е.'
 
return '' .. ( 0 - year) .. ' до н. е.'
  +
 
end
 
end
 
end
 
end
  +
 
function p.formatWikiImpl( t1, t2, infocardClass, categoryNamePrefix )
+
function p.formatWikiImpl( t1, t2, infocardClass, categoryNamePrefix, brts )
 
local nd = t2.day;
 
local nd = t2.day;
 
local nm = t2.month;
 
local nm = t2.month;
Рядок 399: Рядок 421:
 
local om = ternary ( t1.month ~= t2.month , t1.month, nil );
 
local om = ternary ( t1.month ~= t2.month , t1.month, nil );
 
local oy = ternary ( t1.year ~= t2.year , t1.year, nil );
 
local oy = ternary ( t1.year ~= t2.year , t1.year, nil );
  +
 
  +
local bracket1 = "(";
  +
local bracket2 = ")";
  +
if ( brts == 1 ) then
  +
bracket1 = "&#91;"
  +
bracket2 = "&#93;"
  +
end
  +
  +
local JulianComment = function(s)
  +
return tostring(mw.html.create("abbr")
  +
:attr("title","за юліанським календарем")
  +
:wikitext(s)
  +
:done())
  +
end
  +
  +
 
local template =
 
local template =
 
(nd ~= nil and "1" or "") .. (nm ~= nil and "2" or "") .. (ny ~= nil and "3" or "") ..
 
(nd ~= nil and "1" or "") .. (nm ~= nil and "2" or "") .. (ny ~= nil and "3" or "") ..
 
(od ~= nil and "4" or "") .. (om ~= nil and "5" or "") .. (oy ~= nil and "6" or "")
 
(od ~= nil and "4" or "") .. (om ~= nil and "5" or "") .. (oy ~= nil and "6" or "")
 
 
local datePart = '<span style="white-space:nowrap;">'
+
local datePart = '<span class="nowrap">'
 
if (template == "12") then
 
if (template == "12") then
 
datePart = datePart .. string.format( "[[%d %s]]",
 
datePart = datePart .. string.format( "[[%d %s]]",
 
nd, genitivusMonthes[nm] )
 
nd, genitivusMonthes[nm] )
 
elseif (template == "23") then
 
elseif (template == "23") then
datePart = datePart .. string.format( "[[%s]] %s",
+
datePart = datePart .. string.format( "%s %s",
 
nominativeMonthes[nm], nominativeYear( ny ) )
 
nominativeMonthes[nm], nominativeYear( ny ) )
 
elseif (template == "3") then
 
elseif (template == "3") then
Рядок 417: Рядок 454:
 
nd, genitivusMonthes[nm], nominativeYear( ny ) )
 
nd, genitivusMonthes[nm], nominativeYear( ny ) )
 
elseif (template == "124") then
 
elseif (template == "124") then
datePart = datePart .. string.format( "<span title=\"за юліанським календарем\" class=\"explain\">%d</span> [[%d %s|(%d) %s]]",
+
datePart = datePart .. JulianComment(string.format( "%d", od )
  +
).. string.format( " [[%d %s|" .. bracket1 .. "%d" .. bracket2 .. " %s]]",
od, nd, genitivusMonthes[nm], nd, genitivusMonthes[nm] )
 
  +
nd, genitivusMonthes[nm], nd, genitivusMonthes[nm] )
 
elseif (template == "1234") then
 
elseif (template == "1234") then
datePart = datePart .. string.format( "<span title=\"за юліанським календарем\" class=\"explain\">%d</span> [[%d %s|(%d) %s]] %s",
+
datePart = datePart .. JulianComment(string.format( "%d", od )
  +
).. string.format( " [[%d %s|" .. bracket1 .. "%d" .. bracket2 .. " %s]] %s",
od, nd, genitivusMonthes[nm], nd, genitivusMonthes[nm], nominativeYear( ny ) )
 
  +
nd, genitivusMonthes[nm], nd, genitivusMonthes[nm], nominativeYear( ny ) )
 
elseif (template == "1245") then
 
elseif (template == "1245") then
datePart = datePart .. string.format( "<span title=\"за юліанським календарем\" class=\"explain\">%d %s</span> ([[%d %s]])",
+
datePart = datePart .. JulianComment(string.format( "%d %s", od, genitivusMonthes[om] )
od, genitivusMonthes[om], nd, genitivusMonthes[nm] )
+
).. string.format(" " .. bracket1 .. "[[%d %s]]" .. bracket2 .. "", nd, genitivusMonthes[nm] )
 
elseif (template == "12345") then
 
elseif (template == "12345") then
datePart = datePart .. string.format( "<span title=\"за юліанським календарем\" class=\"explain\">%d %s</span> ([[%d %s]]) %s",
+
datePart = datePart .. JulianComment(string.format( "%d %s", od, genitivusMonthes[om] )
od, genitivusMonthes[om], nd, genitivusMonthes[nm], nominativeYear( ny ) )
+
).. string.format(" " .. bracket1 .. "[[%d %s]]" .. bracket2 .. " %s", nd, genitivusMonthes[nm], nominativeYear( ny ) )
 
elseif (template == "123456") then
 
elseif (template == "123456") then
datePart = datePart .. string.format( '<span title=\"за юліанським календарем\" class=\"explain\">%d %s %d</span></span> <span style="white-space:nowrap;">([[%d %s]] %s)',
+
datePart = datePart .. JulianComment(string.format( "%d %s %d", od, genitivusMonthes[om], oy ))
  +
.. '</span> <span class="nowrap">'
od, genitivusMonthes[om], oy, nd, genitivusMonthes[nm], nominativeYear( ny ) )
 
  +
.. string.format(" " .. bracket1 .. "[[%d %s]] %s" .. bracket2 , nd, genitivusMonthes[nm], nominativeYear( ny ) )
 
else
 
else
 
datePart = datePart .. 'хибний формат'
 
datePart = datePart .. 'хибний формат'
Рядок 439: Рядок 479:
 
(nd ~= nil and "1" or "") .. (nm ~= nil and "2" or "") .. (ny ~= nil and "3" or "")
 
(nd ~= nil and "1" or "") .. (nm ~= nil and "2" or "") .. (ny ~= nil and "3" or "")
 
 
if infocardClass then
+
if infocardClass then
if (infocardTemplate == "123") then
+
if (infocardTemplate == "123") then
datePart = datePart .. string.format('<span style="display:none">(<span class="%s">%04d-%02d-%02d</span>)</span>', infocardClass, ny , nm , nd )
+
datePart = datePart .. string.format('<span style="display:none">(<span class="%s">%04d-%02d-%02d</span>)</span>', infocardClass , ny , nm , nd )
elseif (infocardTemplate == "23") then
+
elseif (infocardTemplate == "23") then
datePart = datePart .. string.format('<span style="display:none">(<span class="%s">%04d-%02d</span>)</span>', infocardClass, ny , nm )
+
datePart = datePart .. string.format('<span style="display:none">(<span class="%s">%04d-%02d</span>)</span>', infocardClass , ny , nm )
elseif (infocardTemplate == "3") then
+
elseif (infocardTemplate == "3") then
datePart = datePart .. string.format('<span style="display:none;">(<span class="%s">%04d</span>)</span>', infocardClass, ny )
+
datePart = datePart .. string.format('<span style="display:none;">(<span class="%s">%04d</span>)</span>', infocardClass , ny )
end
+
end
end
+
end
 
 
 
if categoryNamePrefix then
 
if categoryNamePrefix then
Рядок 460: Рядок 500:
 
return datePart
 
return datePart
 
end
 
end
  +
 
 
return p
 
return p

Версія за 00:05, 15 липня 2019

--[[ В этом модуле собраны функции, связанные с работой с датами.]]
local monthg = {'січня', 'лютого', 'березня', 'квітня', 'травня', 'червня',
    'липня', 'серпня', "вересня", "жовтня", "листопада", "грудня"}

local monthd = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}

local function DecodeDate(d)-- Ч, М, Г, СЧ, СМ, СГ, хвост
    --дата: "%-?%d+"=год, "%d+%.%d+"=число месяца, "%d+%.%d+%.%-?%d+"=ЧМГ,
    -- потом в скобках м.б. переопределено для старого стиля начиная с числа
    local nd=d:match("^[%d.-]*");
    local od=d:match("^[%d.-]*%s*%(%s*([%d.-]*)%s*%)");
    local tail = d:match("^[%d.-]+%s*%(%s*[%d.-]+%s*%)%s*(%S.*)") or d:match("^[%d.-]+%s*([^%s%d].*)");
    if nd:match('^%-?%d+$' ) then
        return nil, nil, tonumber(nd), nil, nil, od and tonumber(od:match("%-?%d+$")),tail
    else
        local j,m,y=nd:match("^(%d+)%.(%d+)%.?(%-?%d*)");
        if j then
            if od then
                local oj, om, oy = od:match("^(%d+)%.?(%d*)%.?(%-?%d*)");
                return j and tonumber(j),
                       m and tonumber(m),
                       y>'' and tonumber(y) or nil,
                      oj and tonumber(oj),
                      om>'' and tonumber(om) or nil,
                      oy>'' and tonumber(oy) or nil,
                      tail
            end
            return j and tonumber(j), m and tonumber(m), y>'' and tonumber(y) or nil, nil, nil, nil, tail
        else return nil
        end
    end
end

local function Diffy(d1,m1,y1,d0,m0,y0)--аналог Персона/Дата/Прошло лет
    return y1-y0 - ( y1*y0<=0 and 1 or 0 ) - ( (m1<m0 or m1==m0 and d1<d0) and 1 or 0 )
end

local function Year0(y,t)-- аналог Год0
    if y>0 then return table.concat{
        '[[', tostring(y), ' рік|', t and tostring(y)..'&nbsp;'..t or tostring(y), ']]'
    } else return table.concat{
        '[[', tostring(-y), ' рік до н. е.|', 
        t and tostring(-y)..'&nbsp;'..t or tostring(-y),
        '&nbsp;до&nbsp;н.&nbsp;е.]]'
    }
    end
end

local function FormDate(j,m,y,oj,om,oy,mo)-- ~ Персона/Дата/Logic 4
    if j then
        if not m then return "''хибний формат''" end
        if y then return
         string.format(
            '<span class="nowrap">%s<span style="display:none">(<span class="%s">%04i-%02i-%02i</span>)</span></span>',
            table.concat(
                oj and (
                    om and (
                        oy and {-- ДД ММММ ГГГГ ([[ДД ММММ]] [[ГГГГ]])
                            oj,'&nbsp;',monthg[om],'&nbsp;',oy,
                            '</span> <span class="nowrap">([[',
                            j, ' ', monthg[m],']] ',Year0(y),')'
                        } or {-- ДД ММММ ([[ДД ММММ]]) [[ГГГГ]]
                            oj,'&nbsp;',monthg[om],' ([[',j,'&nbsp;',monthg[m],']]) ',Year0(y)
                        }
                    ) or {-- ДД [[ДД ММММ|(ДД) ММММ]] [[ГГГГ]]
                        oj,'&nbsp;[[',j,' ',monthg[m],'|','(',j,')&nbsp;',monthg[m],']] ',Year0(y)
                    }
                ) or {'[[',j,'&nbsp;',monthg[m],']]&nbsp;',Year0(y)}
            ),--/table.concat
            ({['Народження']='bday',['Смерті']='dday'})[mo] or '',
            y,m,j
         )--/string.format
        else return
            '<span class="nowrap">' .. table.concat(
                oj and (
                    om and {-- ДД ММММ ([[ДД ММММ]])
                            oj,'&nbsp;',monthg[om],' ([[',j,'&nbsp;',monthg[m],']])</span>'
                    } or {-- ДД [[ДД ММММ|(ДД) ММММ]]
                        oj,'&nbsp;[[',j,' ',monthg[m],'|','(',j,')&nbsp;',monthg[m],']]</span>'
                    }
                ) or {'[[',j,'&nbsp;',monthg[m],']]</span>'}
            )
        end
    else
        return y and string.format(
            '<span class="nowrap">%s<span style="display:none;">(<span class="bday">%04i</span>)</span></span>',
            Year0(y,'рік'),y) or "''хибний формат''"
    end
end

local function GetDate(D)--dd.mm.-?yyyy или -?yyyy-mm-dd в три переменных d,m,y
    local d,m,y = d:match('^%s*(%d%d?)[/.]([01]?%d)[/.](%-?%d+)')
    if not d then y,m,d = D:match('^%s*(%-?%d+)[-\\]0*(1?%d)[-\\]0*(%d+)') end
    return tonumber(d),tonumber(m),tonumber(y)
end

local function Cmp(a,b)--Сравнивает две даты, результат соответственно -1, 0 или 1 
    local d1,m1,y1 = GetDate(a)
    local d2,m2,y2 = GetDate(b)
    return d1 and d2 and (--nil, если формат не опознан
        y1==y2 and (
            m1==m2 and (
                d1==d2 and 0 or d1<d2 and -1 or 1
            ) or m1<m2 and -1 or 1
        ) or y1<y2 and -1 or 1
    )
end

local function Yyyymmdd(r)--Переводит русскую дату в YYYY,MM,DD
    local d, m, y, M = mw.ustring.match(r, "^%s*(%d%d?)%s+([а-яА-Я]+)%s+(%d+)")
    if not m then return nil end
    m = mw.ustring.lower(m)

    --тупо перебор
    for i = 1, 12 do
    	if m == monthg[i] then
    		M = i
    		break
		end
	end

    if not M then
    	return nil
	end
    return tonumber(y), M, tonumber(d)
end

local p = {}

p = {

ifdate=function(f)-- Для шаблона "Если дата", имитирует старое поведение
 -- Аргументы передаются шаблону 
 return f:getParent().args[ mw.ustring.match(frame.args[1],"^[ %d.%-−%()]*$") and 2 or 3 ]
end;

DecodeDate = DecodeDate;
Diffy = Diffy;
Year0 = Year0;
GetDate = GetDate;
Cmp = Cmp;
Yyyymmdd = Yyyymmdd;

diffy = function(f)-- принимает параметры #invoke в виде двух строк-дат
    local d1,m1,y1=DecodeDate(f.args[1]);
    local d0,m0,y0=DecodeDate(f.args[2])
    return Diffy(d1,m1,y1,d0,m0,y0)
end;

monthg=function(f) return monthg[ f.args[1] or f:getParent().args[1] ] end;--realmonth

persdate=function(f)-- Для шаблона Персона/Дата;{{#invoke:dates|persdate|nocat={{NAMESPACE}}}}
 local frame=f:getParent();
 local catpref,mo,d,d2={['Народження']='Народились',['Смерті']='Померли'}, frame.args[1],frame.args[2],frame.args[3]
 local cat, j,m,y,oj,om,oy,tail, j2,m2,y2, age = ''
 if d then
     j,m,y,oj,om,oy,tail=DecodeDate(d:gsub('−','-'));
     if not (j or y) then
         return (frame.args.nocat and d or d..'[[Категорія:Вікіпедія:Статті з ручною вікіфікацією дат в картці]]')
     end
 end;
 if d2 then
     j2,m2,y2 = DecodeDate(d2:gsub('−','-'));
 end;
 return table.concat{
     FormDate(j,m,y,oj,om,oy,mo),
     ( (frame.args['nopersoncat'] or '')~='' or (f.args['nocat'] or '')~='' ) and '' or table.concat{
         '[[Категорія:Персоналії за алфавітом]]',
         j and string.format('[[Категорія:%s %i %s]]',catpref[mo],j,monthg[m]) or '',
         y and string.format('[[Категорія:%s в %s]]',catpref[mo],y,Year0(y,'році')) or ''
     },--/table.concat внутр.
     (function(F)--возраст
         if not F then return '' end;
         local n=F();
         return n and string.format(" (%i %s)%s",
             n,
             mw.getLanguage('uk'):plural(n,'рік','роки','років'),
             n>150 and '[[Категорія:Статті про персоналії з великим поточним віком]]' or ''
         ) or ''
     end)( ({
         ['Народження']=function()
             local now=os.date('*t');
             if (not d2 or d2=='') and j and m and y then
                 return Diffy(now.day,now.month,now.year,j,m,y)
             end
         end,
         ['Смерті']=function()
             return j and m and y and j2 and m2 and y2 and Diffy(j,m,y,j2,m2,y2);
         end,
     })[mo] ),--конец вызова функции возраста
     tail or '',
     cat
 }--/table.concat внеш.
end;

formdate=function(f) -- Формирует дату по 3--6 параметрам #invoke или шаблона
    --не использовать с пустыми аргументами
    if (f.args[1] or '')~='' and (f.args[2] or '')~='' or (f.args[3] or '')~='' then
        return FormDate(f.args[1],f.args[2],f.args[3],f.args[4],f.args[5],f.args[6],f.args['m'])
    else
        local tf=f:getParent();
        return FormDate(tf.args[1],tf.args[2],tf.args[3],tf.args[4],tf.args[5],tf.args[6],tf.args['m'])
    end
end;

cmp=function(f)--Сравнивает две даты, результат соответственно -1, 0 или 1
    return Cmp(f.args[1],f.args[2])
end;

G2J=function(f)--перевод григорианских дат в юлианские, возврат DD.MM.YYYY
--Не знает про 15 октября 1582 года, не работает до нашей эры и после ???99 года
--Если есть второй аргумент, преобразует только ДО этой даты включительно
--Если есть третий аргумент, результат форматирует под Персона/Дата
    local d,m,y=GetDate(f.args[1])
    if f.args[2] and Cmp(f.args[1],f.args[2])==1 then
        return string.format("%i.%i.%i",d,m,y)
    end
    local shift=math.floor(y/100)-math.floor(y/400)-2
    if d-shift>0 then
        return f.args[3] and string.format("%i.%i.%i (%i)",d,m,y,d-shift)
        or string.format("%i.%i.%i",d-shift,m,y)
    else
        if m==1 then
            return f.args[3]
            and string.format("%i.1.%i (%i.12.%i)",d,y,31+d-shift,y-1)
            or string.format("%i.12.%i",31+d-shift,y-1)
        elseif m==3 then
            return f.args[3] and string.format("%i.3.%i (%i.2)", d,y,
                (y%4==0 and 29 or 28)+d-shift-(y%100==0 and y%400~=0 and 1 or 0)
            )
            or string.format("%i.2.%i",
                (y%4==0 and 29 or 28)+d-shift-(y%100==0 and y%400~=0 and 1 or 0)
            ,y)
        else
            return f.args[3] and string.format(
                "%i.%i.%i (%i.%i)", d,m,y, monthd[m-1]+d-shift,m-1
            )
            or string.format("%i.%i.%i",monthd[m-1]+d-shift,m-1,y)
        end
    end
end;

-- Переводить українську дату в YYYY-MM-DD. Повертає вихідне значення, якщо дата вже в цьому форматі
yyyymmdd = function(f)
    local date, hourmin = f.args[1]
    if mw.ustring.match(date, "^%s*%d+\-%d+\-%d+") then
    	return date
	end
    hourmin = mw.ustring.match(date, "%s+%d+:%d+$")
    local y, m, d = Yyyymmdd(date)
    if not y then
    	return '<span class="error">Помилка: некоректний формат дати.</span>'
	end
    return string.format('%4i-%02i-%02i', y, m, d) .. (hourmin or '')
end
}

function table.val_to_str ( v )
  if "string" == type( v ) then
    v = string.gsub( v, "\n", "\\n" )
    if string.match( string.gsub(v,"[^'\"]",""), '^"+$' ) then
      return "'" .. v .. "'"
    end
    return '"' .. string.gsub(v,'"', '\\"' ) .. '"'
  else
    return "table" == type( v ) and table.tostring( v ) or
      tostring( v )
  end
end

function table.key_to_str ( k )
  if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then
    return k
  else
    return "[" .. table.val_to_str( k ) .. "]"
  end
end

function table.tostring( tbl )
  local result, done = {}, {}
  for k, v in ipairs( tbl ) do
    table.insert( result, table.val_to_str( v ) )
    done[ k ] = true
  end
  for k, v in pairs( tbl ) do
    if not done[ k ] then
      table.insert( result,
        table.key_to_str( k ) .. "=" .. table.val_to_str( v ) )
    end
  end
  return "{" .. table.concat( result, "," ) .. "}"
end

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

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 p.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)
	return tonumber(os.time({year=Y, month=M, day=D, hour=(h+oh), min=(m+om), sec=s}))
end

local g2uBoundary1 = p.parseISO8601('1582-10-15T00:00:00Z')
local g2uBoundary2 = p.parseISO8601('1700-03-12T00:00:00Z')
local g2uBoundary3 = p.parseISO8601('1800-03-13T00:00:00Z')
local g2uBoundary4 = p.parseISO8601('1900-03-14T00:00:00Z')
local g2uBoundary5 = p.parseISO8601('1918-01-26T00:00:00Z') -- декрет Леніна

-- Передаваемое время обязано быть по Григорианскому календарю (новому стилю)
function p.formatWiki( time, infocardClass, categoryNamePrefix )
	if 'table'==type( time ) then
		if time.args and time.args[1] then
			time = tonumber( time.args[1] )
		else
			return 'unknown argument type: ' .. type( time ) .. ': ' .. table.tostring( time )
		end
	end
	local t = os.date("*t", time)
	if time < g2uBoundary1 then
		-- виводимо лише юліанський календар. Задавати тут григоріанський некоректно
		return p.formatWikiImpl( t, t, infocardClass, categoryNamePrefix )
	end
	
	-- Спеціальні дати
	if t.year == 1700 and t.month == 3 and t.day == 11 then
		return p.formatWikiImpl( {year=1700, month=2, day=29}, t, infocardClass, categoryNamePrefix)
	end
	if t.year == 1800 and t.month == 3 and t.day == 12 then
		return p.formatWikiImpl( {year=1800, month=2, day=29}, t, infocardClass, categoryNamePrefix )
	end
	if t.year == 1900 and t.month == 3 and t.day == 13 then
		return p.formatWikiImpl( {year=1900, month=2, day=29}, t, infocardClass, categoryNamePrefix )
	end

	if g2uBoundary1 <= time and time < g2uBoundary2 then
		return p.formatWikiImpl( os.date("*t", time - 10 * 24 * 60 * 60), t, infocardClass, categoryNamePrefix )
	end
	if g2uBoundary2 <= time and time < g2uBoundary3 then
		return p.formatWikiImpl( os.date("*t", time - 11 * 24 * 60 * 60), t, infocardClass, categoryNamePrefix )
	end
	if g2uBoundary3 <= time and time < g2uBoundary4 then
		return p.formatWikiImpl( os.date("*t", time - 12 * 24 * 60 * 60), t, infocardClass, categoryNamePrefix )
	end
	if g2uBoundary4 <= time and time < g2uBoundary5 then
		return p.formatWikiImpl( os.date("*t", time - 13 * 24 * 60 * 60), t, infocardClass, categoryNamePrefix )
	end

	--тільки Григоріанський календар
	return p.formatWikiImpl( t, t, infocardClass, categoryNamePrefix )
end

function ternary ( cond , T , F )
    if cond then return T else return F end
end

local nominativeMonthes = {'січень', 'лютий', 'березень', 'квітень', 'травень', 'червень',
    'липень', 'серпень', 'вересень', 'жовтень', 'листопад', 'грудень'}
    
local genitivusMonthes = {'січня', 'лютого', 'березня', 'квітня', 'травня', 'червня',
    'липня', 'серпня', 'вересня', 'жовтня', 'листопада', 'грудня'}

function nominativeYear( year )
    if ( year >= 0 ) then
        return '[[' .. year .. ' рік|' .. year .. ']]'
    else
        return '[[' .. ( 0 - year ) .. ' рік до н. е.|' .. ( 0 - year ) .. ' до н. е.]]'
    end
end

function inYear( year )
    if ( year >= 0 ) then
        return '' .. year .. ' році'
    else
        return '' .. ( 0 - year) .. ' році до н. е.'
    end
end

-- рік для категорій народження та смерті
function catbdYear( year )
    if ( year >= 0 ) then
        return '' .. year .. ''
    else
        return '' .. ( 0 - year) .. ' до н. е.'
	
    end
end

function p.formatWikiImpl( t1, t2, infocardClass, categoryNamePrefix, brts )
    local nd = t2.day;
    local nm = t2.month;
    local ny = t2.year;
    local od = ternary ( t1.day ~= t2.day , t1.day, nil );
    local om = ternary ( t1.month ~= t2.month , t1.month, nil );
    local oy = ternary ( t1.year ~= t2.year , t1.year, nil );

	local bracket1 = "(";
	local bracket2 = ")";
	if ( brts == 1 ) then
		bracket1 = "&#91;"
		bracket2 = "&#93;"
	end

	local JulianComment = function(s)
		return tostring(mw.html.create("abbr")
			:attr("title","за юліанським календарем")
			:wikitext(s)
			:done())
	end

	
    local template =
        (nd ~= nil and "1" or "") .. (nm ~= nil and "2" or "") .. (ny ~= nil and "3" or "") ..
        (od ~= nil and "4" or "") .. (om ~= nil and "5" or "") .. (oy ~= nil and "6" or "")
 
    local datePart = '<span class="nowrap">'
    if (template == "12") then
        datePart = datePart .. string.format( "[[%d %s]]",
        								nd, genitivusMonthes[nm] )
    elseif (template == "23") then
        datePart = datePart .. string.format( "%s %s",
        								nominativeMonthes[nm], nominativeYear( ny ) )
    elseif (template == "3") then
        datePart = datePart .. nominativeYear( ny )
    elseif (template == "123") then
        datePart = datePart .. string.format( "[[%d %s]] %s",
                                        nd, genitivusMonthes[nm], nominativeYear( ny ) )
    elseif (template == "124") then
        datePart = datePart .. JulianComment(string.format( "%d", od )
							).. string.format( " [[%d %s|" .. bracket1 .. "%d" .. bracket2 .. " %s]]",
                                        nd, genitivusMonthes[nm], nd, genitivusMonthes[nm] )
    elseif (template == "1234") then
        datePart = datePart .. JulianComment(string.format( "%d", od )
							).. string.format( " [[%d %s|" .. bracket1 .. "%d" .. bracket2 .. " %s]] %s",
                                        nd, genitivusMonthes[nm], nd, genitivusMonthes[nm], nominativeYear( ny ) )
    elseif (template == "1245") then
        datePart = datePart .. JulianComment(string.format( "%d %s", od, genitivusMonthes[om] )
							).. string.format(" " .. bracket1 .. "[[%d %s]]" .. bracket2 .. "", nd, genitivusMonthes[nm] )										
    elseif (template == "12345") then
        datePart = datePart .. JulianComment(string.format( "%d %s", od, genitivusMonthes[om] )
							).. string.format(" " .. bracket1 .. "[[%d %s]]" .. bracket2 .. " %s", nd, genitivusMonthes[nm], nominativeYear( ny ) )
    elseif (template == "123456") then
        datePart = datePart .. JulianComment(string.format( "%d %s %d", od, genitivusMonthes[om], oy ))
							.. '</span> <span class="nowrap">'
							.. string.format(" " .. bracket1 .. "[[%d %s]] %s" .. bracket2 , nd, genitivusMonthes[nm], nominativeYear( ny ) )
    else
        datePart = datePart .. 'хибний формат'
    end
    datePart = datePart .. '</span>'
 
    local infocardTemplate =
        (nd ~= nil and "1" or "") .. (nm ~= nil and "2" or "") .. (ny ~= nil and "3" or "")
 
	if infocardClass then
	    if (infocardTemplate == "123") then
	        datePart = datePart .. string.format('<span style="display:none">(<span class="%s">%04d-%02d-%02d</span>)</span>', infocardClass , ny , nm , nd )
	    elseif (infocardTemplate == "23") then
	        datePart = datePart .. string.format('<span style="display:none">(<span class="%s">%04d-%02d</span>)</span>', infocardClass , ny , nm )
	    elseif (infocardTemplate == "3") then
	        datePart = datePart .. string.format('<span style="display:none;">(<span class="%s">%04d</span>)</span>', infocardClass , ny )
	    end
	end
 
    if categoryNamePrefix then
        if ( nd ~= nil and nm ~= nil) then
            datePart = datePart .. '[[Категорія:' .. categoryNamePrefix .. ' ' .. nd .. ' ' .. genitivusMonthes[nm] .. ']]'
        end
        if ( ny ~= nil) then
            datePart = datePart .. '[[Категорія:' .. categoryNamePrefix .. ' ' .. catbdYear( ny ) .. ']]'
        end
    end
 
    return datePart
end

return p