Модуль:Dates: различия между версиями
Перейти к навигации
Перейти к поиску
Mansur700 (обсуждение | вклад) (Керла агӀо: «--ХIокху жимакепачохь гулбина барамаш, техьашца хIотта делла ду local monthg = {'Нажи-бутт', 'Мархи...») |
Mansur700 (обсуждение | вклад) Нет описания правки |
||
Строка 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+"=ЧМГ, | ||
-- потом в скобках м.б. переопределено для старого стиля начиная с числа | -- потом в скобках м.б. переопределено для старого стиля начиная с числа | ||
local nd=d:match("^[%d.-]*"); | local nd=d:match("^[%d.-]*"); | ||
Строка 34: | Строка 34: | ||
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)-- | 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)..' '..t or tostring(y), ']]' | '[[', tostring(y), ' год|', t and tostring(y)..' '..t or tostring(y), ']]' | ||
} else return table.concat{ | } else return table.concat{ | ||
'[[', tostring(-y), ' | '[[', tostring(-y), ' год до н. э.|', | ||
t and tostring(-y)..' '..t or tostring(-y), | t and tostring(-y)..' '..t or tostring(-y), | ||
' | ' до н. э.]]' | ||
} | } | ||
end | end | ||
end | end | ||
local function FormDate(j,m,y,oj,om,oy,mo)-- ~ | local function FormDate(j,m,y,oj,om,oy,mo)-- ~ Персона/Дата/Logic 4 | ||
if j then | if j then | ||
if not m then return "'' | if not m then return "''формат неверен''" end | ||
if y then return | if y then return | ||
string.format( | string.format( | ||
Строка 58: | Строка 58: | ||
oj and ( | oj and ( | ||
om and ( | om and ( | ||
oy and {-- ДД | oy and {-- ДД ММММ ГГГГ ([[ДД ММММ]] [[ГГГГ]]) | ||
oj,' ',monthg[om],' ',oy, | oj,' ',monthg[om],' ',oy, | ||
'</span> <span class="nowrap">([[', | '</span> <span class="nowrap">([[', | ||
j, ' ', monthg[m],']] ',Year0(y),')' | j, ' ', monthg[m],']] ',Year0(y),')' | ||
} or {-- ДД | } or {-- ДД ММММ ([[ДД ММММ]]) [[ГГГГ]] | ||
oj,' ',monthg[om],' ([[',j,' ',monthg[m],']]) ',Year0(y) | oj,' ',monthg[om],' ([[',j,' ',monthg[m],']]) ',Year0(y) | ||
} | } | ||
) or {-- ДД [[ДД | ) or {-- ДД [[ДД ММММ|(ДД) ММММ]] [[ГГГГ]] | ||
oj,' [[',j,' ',monthg[m],'|','(',j,') ',monthg[m],']] ',Year0(y) | oj,' [[',j,' ',monthg[m],'|','(',j,') ',monthg[m],']] ',Year0(y) | ||
} | } | ||
) or {'[[',j,' ',monthg[m],']] ',Year0(y)} | ) or {'[[',j,' ',monthg[m],']] ',Year0(y)} | ||
),--/table.concat | ),--/table.concat | ||
({[' | ({['Рождения']='bday',['Смерти']='dday'})[mo] or '', | ||
y,m,j | y,m,j | ||
)--/string.format | )--/string.format | ||
Строка 76: | Строка 76: | ||
'<span class="nowrap">' .. table.concat( | '<span class="nowrap">' .. table.concat( | ||
oj and ( | oj and ( | ||
om and {-- ДД | om and {-- ДД ММММ ([[ДД ММММ]]) | ||
oj,' ',monthg[om],' ([[',j,' ',monthg[m],']])</span>' | oj,' ',monthg[om],' ([[',j,' ',monthg[m],']])</span>' | ||
} or {-- ДД [[ДД | } or {-- ДД [[ДД ММММ|(ДД) ММММ]] | ||
oj,' [[',j,' ',monthg[m],'|','(',j,') ',monthg[m],']]</span>' | oj,' [[',j,' ',monthg[m],'|','(',j,') ',monthg[m],']]</span>' | ||
} | } | ||
Строка 87: | Строка 87: | ||
return y and string.format( | return y and string.format( | ||
'<span class="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,' | Year0(y,'год'),y) or "''формат неверен''" | ||
end | end | ||
end | end | ||
local function GetDate(D)--dd.mm.-?yyyy | 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+)') | ||
if not d then y,m,d = D:match('^%s*(%-?%d+)[-\\]0*(1?%d)[-\\]0*(%d+)') end | if not d then y,m,d = D:match('^%s*(%-?%d+)[-\\]0*(1?%d)[-\\]0*(%d+)') end | ||
Строка 97: | Строка 97: | ||
end | end | ||
local function Cmp(a,b)-- | local function Cmp(a,b)--Сравнивает две даты, результат соответственно -1, 0 или 1 | ||
local d1,m1,y1 = GetDate(a) | local d1,m1,y1 = GetDate(a) | ||
local d2,m2,y2 = GetDate(b) | local d2,m2,y2 = GetDate(b) | ||
return d1 and d2 and (--nil, | return d1 and d2 and (--nil, если формат не опознан | ||
y1==y2 and ( | y1==y2 and ( | ||
m1==m2 and ( | m1==m2 and ( | ||
Строка 109: | Строка 109: | ||
end | end | ||
local function Yyyymmdd(r)-- | 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 | for i = 1, 12 do | ||
if m == monthg[i] then | if m == monthg[i] then | ||
Строка 132: | Строка 132: | ||
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; | ||
Строка 144: | Строка 144: | ||
Yyyymmdd = Yyyymmdd; | Yyyymmdd = Yyyymmdd; | ||
diffy = function(f)-- | 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]) | ||
Строка 152: | Строка 152: | ||
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)-- | persdate=function(f)-- Для шаблона Персона/Дата;{{#invoke:dates|persdate|nocat={{NAMESPACE}}}} | ||
local frame=f:getParent(); | local frame=f:getParent(); | ||
local catpref,mo,d,d2={[' | 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 = '' | local cat, j,m,y,oj,om,oy,tail, j2,m2,y2, age = '' | ||
if d then | if d then | ||
j,m,y,oj,om,oy,tail=DecodeDate(d:gsub('−','-')); | j,m,y,oj,om,oy,tail=DecodeDate(d:gsub('−','-')); | ||
if not (j or y) then | if not (j or y) then | ||
return (frame.args.nocat and d or d..'[[Category: | return (frame.args.nocat and d or d..'[[Category:Википедия:Статьи с ручной викификацией дат в карточке]]') | ||
end | end | ||
end; | end; | ||
Строка 168: | Строка 168: | ||
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{ | ||
'[[Category: | '[[Category:Персоналии по алфавиту]]', | ||
j and string.format('[[Category:%s %i %s]]',catpref[mo],j,monthg[m]) or '', | j and string.format('[[Category:%s %i %s]]',catpref[mo],j,monthg[m]) or '', | ||
y and string.format('[[Category:%s в %s]]',catpref[mo],y,Year0(y,' | y and string.format('[[Category:%s в %s]]',catpref[mo],y,Year0(y,'году')) or '' | ||
},--/table.concat | },--/table.concat внутр. | ||
(function(F)-- | (function(F)--возраст | ||
if not F then return '' end; | if not F then return '' end; | ||
local n=F(); | local n=F(); | ||
return n and string.format(" (%i %s)%s", | return n and string.format(" (%i %s)%s", | ||
n, | n, | ||
mw.getLanguage(' | mw.getLanguage('ru'):plural(n,'год','года','лет'), | ||
n>150 and '[[Category: | n>150 and '[[Category:Википедия:Статьи о персоналиях с большим текущим возрастом]]' or '' | ||
) or '' | ) or '' | ||
end)( ({ | end)( ({ | ||
[' | ['Рождения']=function() | ||
local now=os.date('*t'); | local now=os.date('*t'); | ||
if (not d2 or d2=='') and j and m and y then | if (not d2 or d2=='') and j and m and y then | ||
Строка 190: | Строка 190: | ||
return j and m and y and j2 and m2 and y2 and Diffy(j,m,y,j2,m2,y2); | return j and m and y and j2 and m2 and y2 and Diffy(j,m,y,j2,m2,y2); | ||
end, | end, | ||
})[mo] ),-- | })[mo] ),--конец вызова функции возраста | ||
tail or '', | tail or '', | ||
cat | cat | ||
}--/table.concat | }--/table.concat внеш. | ||
end; | end; | ||
formdate=function(f) -- | formdate=function(f) -- Формирует дату по 3--6 параметрам #invoke или шаблона | ||
-- | --не использовать с пустыми аргументами | ||
if (f.args[1] or '')~='' and (f.args[2] or '')~='' or (f.args[3] or '')~='' then | 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']) | return FormDate(f.args[1],f.args[2],f.args[3],f.args[4],f.args[5],f.args[6],f.args['m']) | ||
Строка 206: | Строка 206: | ||
end; | end; | ||
cmp=function(f)-- | 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)-- | G2J=function(f)--перевод григорианских дат в юлианские, возврат DD.MM.YYYY | ||
-- | --Не знает про 15 октября 1582 года, не работает до нашей эры и после ???99 года | ||
-- | --Если есть второй аргумент, преобразует только ДО этой даты включительно | ||
-- | --Если есть третий аргумент, результат форматирует под Персона/Дата | ||
local d,m,y=GetDate(f.args[1]) | local d,m,y=GetDate(f.args[1]) | ||
if f.args[2] and Cmp(f.args[1],f.args[2])==1 then | if f.args[2] and Cmp(f.args[1],f.args[2])==1 then | ||
Строка 243: | Строка 243: | ||
end; | end; | ||
-- | -- Переводит русскую дату в YYYY-MM-DD. Возвращает входное значение, если дата уже в этом формате | ||
yyyymmdd = function(f) | yyyymmdd = function(f) | ||
local date, hourmin = f.args[1] | local date, hourmin = f.args[1] | ||
Строка 252: | Строка 252: | ||
local y, m, d = Yyyymmdd(date) | local y, m, d = Yyyymmdd(date) | ||
if not y then | if not y then | ||
return '<span class="error"> | return '<span class="error">Ошибка: некорректный формат даты.</span>' | ||
end | end | ||
return string.format('%4i-%02i-%02i', y, m, d) .. (hourmin or '') | return string.format('%4i-%02i-%02i', y, m, d) .. (hourmin or '') | ||
Строка 294: | Строка 294: | ||
end | end | ||
function parseISO8601Date(str) | local function parseISO8601Date(str) | ||
local pattern = "(%-?%d+)%-(%d+)%-(%d+)T" | local pattern = "(%-?%d+)%-(%d+)%-(%d+)T" | ||
local Y, M, D = mw.ustring.match( str, pattern ) | local Y, M, D = mw.ustring.match( str, pattern ) | ||
Строка 300: | Строка 300: | ||
end | end | ||
function parseISO8601Time(str) | local function parseISO8601Time(str) | ||
local pattern = "T(%d+):(%d+):(%d+)%Z" | local pattern = "T(%d+):(%d+):(%d+)%Z" | ||
local H, M, S = mw.ustring.match( str, pattern) | local H, M, S = mw.ustring.match( str, pattern) | ||
Строка 306: | Строка 306: | ||
end | end | ||
function parseISO8601Offset(str) | local 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 | ||
Строка 335: | Строка 335: | ||
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 ) | ||
if 'table'==type( time ) then | if 'table'==type( time ) then | ||
Строка 348: | Строка 348: | ||
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) | ||
Строка 376: | Строка 376: | ||
end | end | ||
-- | --только Григорианский календарь | ||
return p.formatWikiImpl( t, t, infocardClass, categoryNamePrefix ) | return p.formatWikiImpl( t, t, infocardClass, categoryNamePrefix ) | ||
end | end | ||
function ternary ( cond , T , F ) | local 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 ) | local 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 ) | local function inYear( year ) | ||
if ( year >= 0 ) then | if ( year >= 0 ) then | ||
return '' .. year .. ' | return '' .. year .. ' году' | ||
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; | ||
Строка 413: | Строка 413: | ||
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 = "[" | |||
bracket2 = "]" | |||
end | |||
local JulianComment = function(s) | local JulianComment = function(s) | ||
return tostring(mw.html.create("abbr") | return tostring(mw.html.create("abbr") | ||
:attr("title"," | :attr("title","по юлианскому календарю") | ||
:wikitext(s) | :wikitext(s) | ||
:done()) | :done()) | ||
Строка 440: | Строка 447: | ||
elseif (template == "124") then | elseif (template == "124") then | ||
datePart = datePart .. JulianComment(string.format( "%d", od ) | datePart = datePart .. JulianComment(string.format( "%d", od ) | ||
).. string.format( " [[%d %s| | ).. string.format( " [[%d %s|" .. bracket1 .. "%d" .. bracket2 .. " %s]]", | ||
nd, genitivusMonthes[nm], nd, genitivusMonthes[nm] ) | nd, genitivusMonthes[nm], nd, genitivusMonthes[nm] ) | ||
elseif (template == "1234") then | elseif (template == "1234") then | ||
datePart = datePart .. JulianComment(string.format( "%d", od ) | datePart = datePart .. JulianComment(string.format( "%d", od ) | ||
).. string.format( " [[%d %s| | ).. string.format( " [[%d %s|" .. bracket1 .. "%d" .. bracket2 .. " %s]] %s", | ||
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 .. JulianComment(string.format( "%d %s", od, genitivusMonthes[om] ) | datePart = datePart .. JulianComment(string.format( "%d %s", od, genitivusMonthes[om] ) | ||
).. string.format(" | ).. string.format(" " .. bracket1 .. "[[%d %s]]" .. bracket2 .. "", nd, genitivusMonthes[nm] ) | ||
elseif (template == "12345") then | elseif (template == "12345") then | ||
datePart = datePart .. JulianComment(string.format( "%d %s", od, genitivusMonthes[om] ) | datePart = datePart .. JulianComment(string.format( "%d %s", od, genitivusMonthes[om] ) | ||
).. string.format(" | ).. string.format(" " .. bracket1 .. "[[%d %s]]" .. bracket2 .. " %s", nd, genitivusMonthes[nm], nominativeYear( ny ) ) | ||
elseif (template == "123456") then | elseif (template == "123456") then | ||
datePart = datePart .. JulianComment(string.format( "%d %s %d", od, genitivusMonthes[om], oy )) | datePart = datePart .. JulianComment(string.format( "%d %s %d", od, genitivusMonthes[om], oy )) | ||
.. '</span> <span class="nowrap">' | .. '</span> <span class="nowrap">' | ||
.. string.format( | .. string.format(" " .. bracket1 .. "[[%d %s]] %s" .. bracket2 , nd, genitivusMonthes[nm], nominativeYear( ny ) ) | ||
else | else | ||
datePart = datePart .. ' | datePart = datePart .. 'формат неверен' | ||
end | end | ||
datePart = datePart .. '</span>' | datePart = datePart .. '</span>' |
Версия от 09:52, 18 июня 2020
Этот модуль содержит функции для работы с датами.
Тестирование конвертаций
- {{#invoke:Dates|parseISO8601|1380-09-08T00:00:00Z}} → -18596909850
- {{#invoke:Dates|parseISO8601|1700-03-11T00:00:00Z}} → -8514375450
- {{#invoke:Dates|parseISO8601|1799-06-06T00:00:00Z}} → -5382721050
- {{#invoke:Dates|parseISO8601|1800-03-12T00:00:00Z}} → -5358615450
- {{#invoke:Dates|parseISO8601|1825-12-26T00:00:00Z}} → -4544727450
- {{#invoke:Dates|parseISO8601|1837-02-10T00:00:00Z}} → -4193597850
- {{#invoke:Dates|parseISO8601|1900-03-13T00:00:00Z}} → -2202854400
- {{#invoke:Dates|parseISO8601|2900-03-13T00:00:00Z}} → 29354137200
- {{#invoke:Dates|formatWiki|-18596908800}} → 8 сентября 1380
- {{#invoke:Dates|formatWiki|-8514374400}} → 29 февраля (11 марта) 1700
- {{#invoke:Dates|formatWiki|-5382720000}} → 26 мая (6 июня) 1799
- {{#invoke:Dates|formatWiki|-5358614400}} → 29 февраля (12 марта) 1800
- {{#invoke:Dates|formatWiki|-5358614400}} → 14 (26) декабря 1825
- {{#invoke:Dates|formatWiki|-4193596800}} → 29 января (10 февраля) 1837
- {{#invoke:Dates|formatWiki|-2202854400}} → 29 февраля (13 марта) 1900
См. также
- {{Date Converter}}
--[[
В это модуле собраны функции, связанные с работой с датами.
]]
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)..' '..t or tostring(y), ']]'
} else return table.concat{
'[[', tostring(-y), ' год до н. э.|',
t and tostring(-y)..' '..t or tostring(-y),
' до н. э.]]'
}
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,' ',monthg[om],' ',oy,
'</span> <span class="nowrap">([[',
j, ' ', monthg[m],']] ',Year0(y),')'
} or {-- ДД ММММ ([[ДД ММММ]]) [[ГГГГ]]
oj,' ',monthg[om],' ([[',j,' ',monthg[m],']]) ',Year0(y)
}
) or {-- ДД [[ДД ММММ|(ДД) ММММ]] [[ГГГГ]]
oj,' [[',j,' ',monthg[m],'|','(',j,') ',monthg[m],']] ',Year0(y)
}
) or {'[[',j,' ',monthg[m],']] ',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,' ',monthg[om],' ([[',j,' ',monthg[m],']])</span>'
} or {-- ДД [[ДД ММММ|(ДД) ММММ]]
oj,' [[',j,' ',monthg[m],'|','(',j,') ',monthg[m],']]</span>'
}
) or {'[[',j,' ',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..'[[Category:Википедия:Статьи с ручной викификацией дат в карточке]]')
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{
'[[Category:Персоналии по алфавиту]]',
j and string.format('[[Category:%s %i %s]]',catpref[mo],j,monthg[m]) or '',
y and string.format('[[Category:%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('ru'):plural(n,'год','года','лет'),
n>150 and '[[Category:Википедия:Статьи о персоналиях с большим текущим возрастом]]' 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
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
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
local function ternary ( cond , T , F )
if cond then return T else return F end
end
local nominativeMonthes = {'январь', 'февраль', 'март', 'апрель', 'май', 'июнь',
'июль', 'август', 'сентябрь', 'октябрь', 'ноябрь', 'декабрь'}
local genitivusMonthes = {'января', 'февраля', 'марта', 'апреля', 'мая', 'июня',
'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'}
local function nominativeYear( year )
if ( year >= 0 ) then
return '[[' .. year .. ' год|' .. year .. ']]'
else
return '[[' .. ( 0 - year ) .. ' год до н. э.|' .. ( 0 - year ) .. ' до н. э.]]'
end
end
local function inYear( 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 = "["
bracket2 = "]"
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 .. '[[Category:' .. categoryNamePrefix .. ' ' .. nd .. ' ' .. genitivusMonthes[nm] .. ']]'
end
if ( ny ~= nil) then
datePart = datePart .. '[[Category:' .. categoryNamePrefix .. ' в ' .. inYear( ny ) .. ']]'
end
end
return datePart
end
return p