ФЭНДОМ


--[[
 В это модуле собраны функции, связанные с работой с датами.
]]
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 style="white-space: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 style="white-space: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 style="white-space: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 style="white-space: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)
    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 p.formatWikiImpl( t1, t2, infocardClass, categoryNamePrefix )
    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 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 style="white-space: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|(%d) %s]]",
                                        nd, genitivusMonthes[nm], nd, genitivusMonthes[nm] )
    elseif (template == "1234") then
        datePart = datePart .. JulianComment(string.format( "%d", od )
							).. string.format( " [[%d %s|(%d) %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(" ([[%d %s]])", nd, genitivusMonthes[nm] )										
    elseif (template == "12345") then
        datePart = datePart .. JulianComment(string.format( "%d %s", od, genitivusMonthes[om] )
							).. string.format(" ([[%d %s]]) %s", nd, genitivusMonthes[nm], nominativeYear( ny ) )
    elseif (template == "123456") then
        datePart = datePart .. JulianComment(string.format( "%d %s %d", od, genitivusMonthes[om], oy ))
							.. '</span> <span style="white-space:nowrap;">'
							.. string.format(' ([[%d %s]] %s)', 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

Обнаружено использование расширения AdBlock.


Викия — это свободный ресурс, который существует и развивается за счёт рекламы. Для блокирующих рекламу пользователей мы предоставляем модифицированную версию сайта.

Викия не будет доступна для последующих модификаций. Если вы желаете продолжать работать со страницей, то, пожалуйста, отключите расширение для блокировки рекламы.

Также на ФЭНДОМЕ

Случайная вики