Jump to content

Module:Dates

Википедиа — Чөлөөт нэвтэрхий толь
--[[
 В это модуле собраны функции, связанные с работой с датами.
]]
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 {-- [[ОООО]] [[СССС ДД|СССС ӨӨ (ӨӨ)]] 
                        '[[',j,' ',monthg[m],'|',oj,'&nbsp;(',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 {-- [[СССС ӨӨ|СССС ӨӨ (ӨӨ)]]
                        '[[',j,' ',monthg[m],'|',oj,'&nbsp;(',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;
Yyymmdd=Yyymmdd;

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('ru'):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",y,m,d)
    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)",y,m,d,d-shift)
        or string.format("%i.%i.%i",y,m,d-shift)
    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)", y,m,d, monthd[m-1]+d-shift,m-1
            )
            or string.format("%i.%i.%i",monthd[m-1]+d-shift,m-1,y)
        end
    end
end;

yyyymmdd = function(f)--Переводит русскую дату в YYYY-MM-DD
    local y,m,d=Yyyymmdd(f.args[1])
    return string.format('%4i-%02i-%02i',y,m,d)
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 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]]",
        								genitivusMonthes[nm], nd)
    elseif (template == "23") then
        datePart = datePart .. string.format( "[[%s]] %s",
        								nominativeYear( ny ), nominativeMonthes[nm] )
    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 .. string.format( "[[%d %s|%d (%d) %s]]",
                                        nd, genitivusMonthes[nm], od, nd, genitivusMonthes[nm] )
    elseif (template == "1234") then
        datePart = datePart .. string.format( "[[%d %s|%d (%d) %s]] %s",
                                        nd, genitivusMonthes[nm], od, nd, genitivusMonthes[nm], nominativeYear( ny ) )
    elseif (template == "1245") then
        datePart = datePart .. string.format( "%d %s ([[%d %s]])",
                                        od, genitivusMonthes[om], nd, genitivusMonthes[nm] )
    elseif (template == "12345") then
        datePart = datePart .. string.format( "%d %s ([[%d %s]]) %s",
                                        od, genitivusMonthes[om], nd, genitivusMonthes[nm], nominativeYear( ny ) )
    elseif (template == "123456") then
        datePart = datePart .. string.format( '%d %s %d</span> <span style="white-space:nowrap;">([[%d %s]] %s)',
                                        od, genitivusMonthes[om], oy, 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 .. '<span style="display:none">(<span class="' .. infocardClass .. '">{{padleft:' .. ny .. '|4|0}}-{{padleft:' .. nm .. '|2|0}}-{{padleft:' .. nd .. '|2|0}}</span>)</span>'
	    elseif (infocardTemplate == "23") then
	        datePart = datePart .. '<span style="display:none">(<span class="' .. infocardClass .. '">{{padleft:' .. ny .. '|4|0}}-{{padleft:' .. nm .. '|2|0}}</span>)</span>'
	    elseif (infocardTemplate == "3") then
	        datePart = datePart .. '<span style="display:none;">(<span class="' .. infocardClass .. '">{{padleft:' .. ny .. '|4|0}}</span>)</span>'
	    end
	end
 
    if categoryNamePrefix then
        if ( nd ~= nil and nm ~= nil) then
            datePart = datePart .. '[[Ангилал:' .. genitivusMonthes[nm] .. ' ' .. nd .. ' ' .. categoryNamePrefix .. ']]'
        end
        if ( ny ~= nil) then
            datePart = datePart .. '[[Ангилал:' .. inYear( ny ) ..'-нд' .. categoryNamePrefix .. ']]'
        end
    end
 
    return datePart
end

return p
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy