Модуль:Calendar: различия между версиями

Материал из FetbukWiki
https://ru.wikipedia.org/wiki/>Carn
Нет описания правки
https://ru.wikipedia.org/wiki/>Carn
(подготовка к внедрению человеческих функций в код)
Строка 1: Строка 1:
local getArgs = require('Module:Arguments').getArgs
local getArgs = require('Module:Arguments').getArgs
local p = {}
local p = {}
local bool_to_number={ [true]=1, [false]=0 }
local err = "-"
local function purif(str)
    if str == "" or str == nil then
        return nil
    elseif type(tonumber(str)) == "number" then
        return math.floor(tonumber(str))
    else
        return nil
    end
    -- need .5 -- ,5 number format converter?
end
local function inbord(val, down, up)
if type(up) ~= "number" or type(down) ~= "number" or type(val) ~= "number" or up < down or val < down or val > up then
return false
    else
        return true
    end
end


function p.NthDay( frame )
function p.NthDay( frame )
    -- копирование аргументов в локальную переменную
     local args = getArgs(frame, { frameOnly = true })
     local args = getArgs(frame, { frameOnly = true })
    -- таблица для перевода логической переменной в число
     local num, wday, mont, yea, format =  
     local bool_to_number={ [true]=1, [false]=0 }
    purif(args[1]), purif(args[2]), purif(args[3]), purif(args[4]), args[5]
    -- записывание переменных для использования в программе
if not format then format = "%d.%m.%y" end
    -- день недели в месяце по порядку, к примеру - ''первая/вторая/третья'' суббота месяца
     if not inbord(num,-5,5) then  
    local num = math.floor(tonumber(args[1]))
    return error("The number must be between -5 and 5")
    -- день недели, который нужно получить в формате 0 это воскресенье, 6 это суббота
     elseif num == 0 then  
    local wday = math.floor(tonumber(args[2]))
    return error("The number must not be zero") end
    -- месяц, для которого делается расчёт
     if not inbord(wday,0,6) then  
    local mont = math.floor(tonumber(args[3]))
    return error("The day of the week must be between 0 and 6") end
    -- год, для которого делается расчёт
     if not inbord(mont,1,12) then  
    local yea = math.floor(tonumber(args[4]))
    return error("The month must be between 1 and 12") end
    -- проверка переменных на допустимость использования
     if not inbord(yea,0,9999) then  
    local format = args[5]
    return error("Wrong year number") end
    if not format then format = "%d.%m.%y" end
     if inbord(num,1,5) then
    local err = "---"
     if num < -5 or num > 5 then  
        error("The number must be between -5 and 5")
     elseif num == 0 then
        error("The number must not be zero")
    end
     if wday < 0 or wday > 6 then  
        error("The day of the week must be between 0 and 6") end
     if mont < 0 or mont > 12 then  
        error("The month must be between 1 and 12") end
     if yea < 0 or yea > 9999 then  
        error("Wrong year number") end
    -- ветка расчётов с начала
     if num > 0 and num < 6 then
        -- получение значения в секундах для первого числа месяца, от которого идёт отсчёт
         local m_start = os.time{year=yea, month=mont, day=1, hour=0}
         local m_start = os.time{year=yea, month=mont, day=1, hour=0}
        -- получение дня недели
         local m_wds = tonumber(os.date("%w", m_start))  
         local m_wds = tonumber(os.date("%w", m_start))
        -- расчёт сдвига в днях и перевод в секунды 
         local start_shift = (
         local start_shift = (
             (num - bool_to_number[wday >= m_wds]) * 7  
             (num - bool_to_number[wday >= m_wds]) * 7  
Строка 43: Строка 46:
             ) * 24 * 60 * 60
             ) * 24 * 60 * 60
         local tim = m_start + start_shift
         local tim = m_start + start_shift
        -- вывод результата в необходимом формате даты
         if tonumber(os.date("%m", tim)) == mont then
         if tonumber(os.date("%m", tim)) == mont then
             return (os.date(format, tim))
             return (os.date(format, tim))
Строка 49: Строка 51:
             return (err)
             return (err)
         end
         end
    -- ветка расчётов с конца
     elseif inbord(num,-5,-1) then
     elseif num < 0 and num > -6 then
         local m_end = os.time{year = yea, month = mont + 1, day = 1, hour = 0} - 24 * 60 * 60
        -- получение значения в секундах для последнего числа месяца, от которого идёт отсчёт
         local m_end = os.time{year = yea,  
            month = mont + 1, day = 1, hour = 0}  
            - 24 * 60 * 60
        -- получение дня недели конца месяца
         local m_wde = tonumber(os.date("%w", m_end))
         local m_wde = tonumber(os.date("%w", m_end))
        -- расчёт сдвига в днях и перевод в секунды
         local end_shift = ((math.abs(num + 1) + bool_to_number[wday > m_wde]) * 7  
         local end_shift = ((math.abs(num + 1) + bool_to_number[wday > m_wde]) * 7  
             + (m_wde - wday)) * 24 * 60 * 60
             + (m_wde - wday)) * 24 * 60 * 60
Строка 67: Строка 63:
         end
         end
     end
     end
end
local function isdate ( chain )
if (not type(chain) == "table")
or (not inbord(chain.year,-9999,9999))
or (not inbord(chain.month,1,12))
or (not inbord(chain.day,1,31))
then return false
else return true end
--  more detailed check for 31.02.0000 needed
--  check for other calendars needed
end
local function numstr2date(datein)
local nums = {}
    local dateout = {}
    for num in string.gmatch(datein,"(%d+)") do
        table.insert(nums,purif(num))
    end
    if #nums ~= 3 then error("Wrong format: 3 numbers expected")
    elseif not inbord(nums[2],1,12) then error("Wrong month")
    elseif not inbord(nums[3],1,31) then
        dateout = {["year"]=nums[3], ["month"]=nums[2], ["day"]=nums[1]}
    elseif not inbord(nums[1],1,31) then
        dateout = {["year"]=nums[1], ["month"]=nums[2], ["day"]=nums[3]}
    else
-- local lang = mw.getContentLanguage()
-- implement lang:formatDate(format,datein,true) here
        return error("Unable to recognize date")
    end
    return dateout
end
local function date2str(datein)
if not isdate(datein) then return error("Wrong date") end
local dateout = os.date("%Y-%m-%d", os.time(datein))
    return dateout
end
function gri2jd( datein )
if not isdate(datein) then return error("Wrong date") end
    local year = datein.year
    local month = datein.month
    local day = datein.day
    -- jd calculation
    local a = math.floor((14 - month)/12)
    local y = year + 4800 - a
    local m = month + 12*a - 3
    local offset = math.floor(y/4) - math.floor(y/100) + math.floor(y/400) - 32045
    local jd = day + math.floor((153*m + 2)/5) + 365*y + offset
    -- jd validation
    local low, high = -1931076.5, 5373557.49999
    if not (low <= jd and jd <= high) then
        return error("Wrong date")
    end
return jd
end
function jd2jul( jd )
if type(jd) ~= "number" then return error("Wrong jd") end
    -- calendar date calculation
    local c = jd + 32082
    local d = math.floor((4*c + 3)/1461)
    local e = c - math.floor(1461*d/4)
    local m = math.floor((5*e + 2)/153)
    local year_out = d - 4800 + math.floor(m/10)
    local month_out = m + 3 - 12*math.floor(m/10)
    local day_out = e - math.floor((153*m + 2)/5) + 1
    -- output
    local dateout = {["year"]=year_out, ["month"]=month_out, ["day"]=day_out}
    return dateout
end
function jul2jd( datein )
if not isdate(datein) then return error("Wrong date") end
    local year = datein.year
    local month = datein.month
    local day = datein.day
    -- jd calculation
    local a = math.floor((14 - month)/12)
    local y = year + 4800 - a
    local m = month + 12*a - 3
    local offset = math.floor(y/4) - 32083
    local jd = day + math.floor((153*m + 2)/5) + 365*y + offset
    -- jd validation
    local low, high = -1930999.5, 5373484.49999
    if not (low <= jd and jd <= high) then
        return error("Wrong date")
    end
return jd
end
function jd2gri( jd )
    -- calendar date calculation
    local a = jd + 32044
    local b = math.floor((4*a + 3) / 146097)
    local c = a - math.floor(146097*b/4)
    local d = math.floor((4*c+3)/1461)
    local e = c - math.floor(1461*d/4)
    local m = math.floor((5*e+2)/153)
    local day_out =  e - math.floor((153*m+2)/5)+1
    local month_out = m + 3 - 12*math.floor(m/10)
    local year_out = 100*b + d - 4800 + math.floor(m/10)
    -- output
    local dateout = {["year"]=year_out, ["month"]=month_out, ["day"]=day_out}
    return dateout
end
end



Версия от 17:54, 10 января 2020

Функции

Находится в бета-версии (10 471 байт). Об ошибках просьба сообщать на страницу обсуждения шаблона или самого модуля, или Carn. Если вы хотите поэкспериментировать, лучше делать это в альфа-версии (30 288 байт).

NthDay

{{ДатыСтрокой}}, {{Даты}}

  • Получает 4 числовых аргумента, считает дату и выдаёт её в формате пятого, необязательного аргумента. Примеры использования (значения аргументов в скобках):
    • первое (1) воскресенье (0) октября (10) (2020) года ={{#invoke:Calendar|NthDay|1|0|10|2020}}= 04.10.20
    • вторая (2) среда (3) мая (5) (2019) года ={{#invoke:Calendar|NthDay|2|3|5|2019}}= 08.05.19
    • последний (-1) понедельник (1) января (1) (2010) года ={{#invoke:Calendar|NthDay|-1|1|1|2010}}= 25.01.10
    • предпоследняя (-2) суббота (6) декабря (12) (2001) года ={{#invoke:Calendar|NthDay|-2|6|12|2001}}= 22.12.01
    • третье (3) воскресенье (0) марта (3) (2024) года в формате ISO 8601={{#invoke:Calendar|NthDay|3|0|3|2024|%Y-%m-%d}}= 2024-03-17

unitime

{{НП/Формат времени}}

  • Оформляет ссылку на UTC, если есть любой второй параметр — ставит летнее время
    • {{#invoke:Calendar|unitime|-0}} = Ошибка скрипта: Функции «unitime» не существует.
    • {{#invoke:Calendar|unitime|+0}} = Ошибка скрипта: Функции «unitime» не существует.
    • {{#invoke:Calendar|unitime|+2:00}} = Ошибка скрипта: Функции «unitime» не существует.
    • {{#invoke:Calendar|unitime|−3:30|}} = Ошибка скрипта: Функции «unitime» не существует.
    • {{#invoke:Calendar|unitime|+12:45|1}} = Ошибка скрипта: Функции «unitime» не существует.
    • {{#invoke:Calendar|unitime|-3:30|да}} = Ошибка скрипта: Функции «unitime» не существует.
    • {{#invoke:Calendar|unitime|CET}} = Ошибка скрипта: Функции «unitime» не существует.
    • {{#invoke:Calendar|unitime|EST|no}} = Ошибка скрипта: Функции «unitime» не существует.

OldDate

устарело

  • Два обязательных аргумента, первый из которых — дата в формате ДД.ММ.ГГГГ или Д. М.ГГГГ, второй — григорианский/юлианский календарь, «г» или «ю»
  • Необязательные аргументы bc (до нашей эры), а также параметры викификации wd, wm и wy, связанные, соответственно с вифификацией дня, месяца и года
  • Можно использовать параметр sq_brts для использования квадратных скобок и параметр yearmark для нестандартного обозначения года
    • {{#invoke:Calendar|OldDate|1.1.1|ю|wd=1}} = Ошибка скрипта: Функции «OldDate» не существует. ошибка!
    • {{#invoke:Calendar|OldDate|31.12.1|г|bc=1}} = Ошибка Lua: bad argument #2 to 'formatDate' (not a valid timestamp).
    • {{#invoke:Calendar|OldDate|{{#time: d.m.Y }}|г}} = Ошибка скрипта: Функции «OldDate» не существует.
    • {{#invoke:Calendar|OldDate|11.2.1602|j|wd=1|wm=0|wy=1}} = Ошибка скрипта: Функции «OldDate» не существует.
    • {{#invoke:Calendar|OldDate|11.2.1602|j|wd=1|wm=1|wy=1}} = Ошибка скрипта: Функции «OldDate» не существует.
    • {{#invoke:Calendar|OldDate|11.2.1602|g|bc=1|yearmark=г.}} = Ошибка скрипта: Функции «OldDate» не существует.
    • {{#invoke:Calendar|OldDate|11.2.1602|g|sq_brts=1|yearmark=0}} = Ошибка скрипта: Функции «OldDate» не существует.

NewDate

{{DateStyle}}

  • Аналогично функции выше, но может обрабатывать отрицательные даты и принимает жёстко только 2 формата d.m.y и y-m-d
    • {{#invoke:Calendar|NewDate|1.1.1|ю|wd=1}} = Ошибка скрипта: Функции «NewDate» не существует.
    • {{#invoke:Calendar|NewDate|31.12.1|г|bc=1}} = Ошибка скрипта: Функции «NewDate» не существует.
    • {{#invoke:Calendar|NewDate|{{#time: d.m.Y }}}} = Ошибка скрипта: Функции «NewDate» не существует. (по умолчанию григорианский)
    • {{#invoke:Calendar|NewDate|11.2.1602|j|wd=1|wm=0|wy=1}} = Ошибка скрипта: Функции «NewDate» не существует.
    • {{#invoke:Calendar|NewDate|11.2.1602|j|wd=1|wm=1|wy=1}} = Ошибка скрипта: Функции «NewDate» не существует.
    • {{#invoke:Calendar|NewDate|11.2.1602|g|bc=1|yearmark=г.}} = Ошибка скрипта: Функции «NewDate» не существует.
    • {{#invoke:Calendar|NewDate|11.2.1602|g|sq_brts=1|yearmark=0}} = Ошибка скрипта: Функции «NewDate» не существует.

ToIso

  • Получает полную дату дату в форматах с четырёхзначным годом и выдаёт дату в формате ГГГГ-ММ-ДД
    • 1.2.1602 ={{#invoke:Calendar|ToIso|1.2.1602}}= 1602-02-01
    • -2020-12-12 ={{#invoke:Calendar|ToIso|-2020-12-12}}= Ошибка Lua на строке 271: Wrong year.
    • 5 января 1002 ={{#invoke:Calendar|ToIso|5 января 1002}}= Ошибка Lua на строке 271: Wrong year.

BoxDate

  • Получает дату с четырёхзначным годом, месяцем и опционально днём месяца, выдаёт читаемую
    • 06.1280 ={{#invoke:Calendar|BoxDate|06.1280}}= Ошибка скрипта: Функции «BoxDate» не существует.
    • 1820-07 ={{#invoke:Calendar|BoxDate|1820-07}}= Ошибка скрипта: Функции «BoxDate» не существует.
    • 2020-12, xg Y = {{#invoke:Calendar|BoxDate|2020-12|xg Y}}= Ошибка скрипта: Функции «BoxDate» не существует.
    • 08.08.1828 ={{#invoke:Calendar|BoxDate|08.08.1828}}= Ошибка скрипта: Функции «BoxDate» не существует.
    • July 12, 2020 ={{#invoke:Calendar|BoxDate|Jule 12, 2020}}= Ошибка скрипта: Функции «BoxDate» не существует.
    • 12 July 2020 ={{#invoke:Calendar|BoxDate|12 Jule 2020}}= Ошибка скрипта: Функции «BoxDate» не существует.
    • July 2020 ={{#invoke:Calendar|BoxDate|Jule 2020}}= Ошибка скрипта: Функции «BoxDate» не существует.
    • 13 août 1281, l W недели Y года ={{#invoke:Calendar|BoxDate|13 août 1281|l W недели Y года}}= Ошибка скрипта: Функции «BoxDate» не существует.
    • 13 января ={{#invoke:Calendar|BoxDate|13 января}}= Ошибка скрипта: Функции «BoxDate» не существует.
bxDate

Реализует указанные выше функции для вызова из других модулей (см. пример использования в Message box), todo:

  • поддержка отрицательных лет (запоминание знака, обработка в положительном виде, приделывание "до н.э." в конце; 0000-01-01 невалидно)
  • преобразование даты в ISO формат, получение строки форматирования и преобразование по ней (необходимы доп.проверки для неточных дат)
  • отдавать параметры errorText и errorCat

ToDate

  • Получает дату в формате Википедия:Функции парсера##time и возвращает в формате <число> <месяц в родительном падеже> <год>
  • Если в строке нету символов препинания, то возвращает её неизменённой
    • 1.2.1602 ={{#invoke:Calendar|ToDate|1.2.1602}}= 1 февраля 1602
    • 1/2/1602 ={{#invoke:Calendar|ToDate|1/2/1602}}= 2 января 1602
    • 1602-02-01 ={{#invoke:Calendar|ToDate|1602-02-01}}= 1 февраля 1602
    • 1 февраля 1602 ={{#invoke:Calendar|ToDate|1 февраля 1602}}= 1 февраля 1602
    • Завтра (+ 1 day) ={{#invoke:Calendar|ToDate|+ 1 day}}= 23 ноября 2024

local getArgs = require('Module:Arguments').getArgs
local p = {}
local bool_to_number={ [true]=1, [false]=0 }
local err = "-"

local function purif(str)
    if str == "" or str == nil then
        return nil
    elseif type(tonumber(str)) == "number" then
        return math.floor(tonumber(str))
    else
        return nil
    end
    -- need .5 -- ,5 number format converter?
end

local function inbord(val, down, up)
	if type(up) ~= "number" or type(down) ~= "number" or type(val) ~= "number" or up < down or val < down or val > up then
		return false
    else
        return true
    end
end

function p.NthDay( frame )
    local args = getArgs(frame, { frameOnly = true })
    local num, wday, mont, yea, format = 
    	purif(args[1]), purif(args[2]), purif(args[3]), purif(args[4]), args[5]
	if not format then format = "%d.%m.%y" end
    if not inbord(num,-5,5) then 
    	return error("The number must be between -5 and 5")
    elseif num == 0 then 
    	return error("The number must not be zero") end
    if not inbord(wday,0,6) then 
    	return error("The day of the week must be between 0 and 6") end
    if not inbord(mont,1,12) then 
    	return error("The month must be between 1 and 12") end
    if not inbord(yea,0,9999) then 
    	return error("Wrong year number") end
    if inbord(num,1,5) then
        local m_start = os.time{year=yea, month=mont, day=1, hour=0}
        local m_wds = tonumber(os.date("%w", m_start)) 
        local start_shift = (
            (num - bool_to_number[wday >= m_wds]) * 7 
            - (m_wds - wday)
            ) * 24 * 60 * 60
        local tim = m_start + start_shift
        if tonumber(os.date("%m", tim)) == mont then
            return (os.date(format, tim))
        else
            return (err)
        end
    elseif inbord(num,-5,-1) then
        local m_end = os.time{year = yea, month = mont + 1, day = 1, hour = 0} - 24 * 60 * 60
        local m_wde = tonumber(os.date("%w", m_end))
        local end_shift = ((math.abs(num + 1) + bool_to_number[wday > m_wde]) * 7 
            + (m_wde - wday)) * 24 * 60 * 60
        local tim = m_end - end_shift
        if tonumber(os.date("%m", tim)) == mont then
            return (os.date(format, tim))
        else
            return (err)
        end
    end
end

local function isdate ( chain )
	if (not type(chain) == "table")
	or (not inbord(chain.year,-9999,9999))
	or (not inbord(chain.month,1,12))
	or (not inbord(chain.day,1,31))
	then return false
	else return true end
--  more detailed check for 31.02.0000 needed
--  check for other calendars needed
end

local function numstr2date(datein)
	local nums = {}
    local dateout = {}
    for num in string.gmatch(datein,"(%d+)") do
        table.insert(nums,purif(num))
    end
    if #nums ~= 3 then error("Wrong format: 3 numbers expected")
    elseif not inbord(nums[2],1,12) then error("Wrong month")
    elseif not inbord(nums[3],1,31) then
        dateout = {["year"]=nums[3], ["month"]=nums[2], ["day"]=nums[1]}
    elseif not inbord(nums[1],1,31) then
        dateout = {["year"]=nums[1], ["month"]=nums[2], ["day"]=nums[3]}
    else
--		local lang = mw.getContentLanguage()
--		implement lang:formatDate(format,datein,true) here
        return error("Unable to recognize date")
    end
    return dateout
end

local function date2str(datein)
	if not isdate(datein) then return error("Wrong date") end
	local dateout = os.date("%Y-%m-%d", os.time(datein))
    return dateout
end

function gri2jd( datein )
	if not isdate(datein) then return error("Wrong date") end
    local year = datein.year
    local month = datein.month
    local day = datein.day
    -- jd calculation
    local a = math.floor((14 - month)/12)
    local y = year + 4800 - a
    local m = month + 12*a - 3
    local offset = math.floor(y/4) - math.floor(y/100) + math.floor(y/400) - 32045
    local jd = day + math.floor((153*m + 2)/5) + 365*y + offset
    -- jd validation
    local low, high = -1931076.5, 5373557.49999
    if not (low <= jd and jd <= high) then
        return error("Wrong date")
    end
	return jd
end

function jd2jul( jd )
	if type(jd) ~= "number" then return error("Wrong jd") end
    -- calendar date calculation
    local c = jd + 32082
    local d = math.floor((4*c + 3)/1461)
    local e = c - math.floor(1461*d/4)
    local m = math.floor((5*e + 2)/153)
    local year_out = d - 4800 + math.floor(m/10)
    local month_out = m + 3 - 12*math.floor(m/10)
    local day_out = e - math.floor((153*m + 2)/5) + 1
    -- output
    local dateout = {["year"]=year_out, ["month"]=month_out, ["day"]=day_out}
    return dateout
end

function jul2jd( datein )
	if not isdate(datein) then return error("Wrong date") end
    local year = datein.year
    local month = datein.month
    local day = datein.day
    -- jd calculation
    local a = math.floor((14 - month)/12)
    local y = year + 4800 - a
    local m = month + 12*a - 3
    local offset = math.floor(y/4) - 32083
    local jd = day + math.floor((153*m + 2)/5) + 365*y + offset
    -- jd validation
    local low, high = -1930999.5, 5373484.49999
    if not (low <= jd and jd <= high) then
        return error("Wrong date")
    end
	return jd
end

function jd2gri( jd )
    -- calendar date calculation
    local a = jd + 32044
    local b = math.floor((4*a + 3) / 146097)
    local c = a - math.floor(146097*b/4)
    local d = math.floor((4*c+3)/1461)
    local e = c - math.floor(1461*d/4)
    local m = math.floor((5*e+2)/153)
    local day_out =  e - math.floor((153*m+2)/5)+1
    local month_out = m + 3 - 12*math.floor(m/10)
    local year_out = 100*b + d - 4800 + math.floor(m/10)
    -- output
    local dateout = {["year"]=year_out, ["month"]=month_out, ["day"]=day_out}
    return dateout
end

function p.gri2jul( frame )
    local args = getArgs(frame, { frameOnly = true })
    local datein = args[1]
    -- парсинг входящей даты по шаблону
    local pattern = "(%d+)%.(%d+)%.(%d+)"
    local dayin, monthin, yearin = datein:match(pattern)
    local year = tonumber(yearin)
    local month = tonumber(monthin)
    local day = tonumber(dayin)
    -- проверка параметров
    if not (type(year) == 'number') then 
        return error("Wrong year")
    end
    if not (1 <= month and month <= 12) then 
        return error("Wrong month")
    end
    if not (1 <= day and day <= 31) then 
        return error("Wrong day")
    end
    -- расчёт юлианской даты
    local a = math.floor((14 - month)/12) 
    local y = year + 4800 - a
    local m = month + 12*a - 3
    local offset = math.floor(y/4) - math.floor(y/100) + math.floor(y/400) - 32045 
    local jd = day + math.floor((153*m + 2)/5) + 365*y + offset
    -- проверка попадания юлианской даты в границы между -9999 и 9999 годами Ю.К.
    local low, high = -1931076.5, 5373557.49999
    if not (low <= jd and jd <= high) then
        return error("Wrong date")
    end
    -- расчёт даты по юлианскому календарю
    local c = jd + 32082
    local d = math.floor((4*c + 3)/1461)
    local e = c - math.floor(1461*d/4)
    local m = math.floor((5*e + 2)/153)
    local year_out = d - 4800 + math.floor(m/10)
    local month_out = m + 3 - 12*math.floor(m/10)
    local day_out = e - math.floor((153*m + 2)/5) + 1
    -- вывод даты в формате ГГГГ-ММ-ДД
    local date = os.date("%Y-%m-%d", os.time{year=year_out, month=month_out, day=day_out})
    return date
end

function p.jul2gri( frame )
    local args = getArgs(frame, { frameOnly = true })
    local datein = args[1]
    -- парсинг входящей даты по шаблону
    local pattern = "(%d+)%.(%d+)%.(%d+)"
    local dayin, monthin, yearin = datein:match(pattern)
    local year = tonumber(yearin)
    local month = tonumber(monthin)
    local day = tonumber(dayin)
    -- проверка параметров
    if not (type(year) == 'number') then 
        return error("Wrong year")
    end
    if not (1 <= month and month <= 12) then 
        return error("Wrong month")
    end
    if not (1 <= day and day <= 31) then 
        return error("Wrong day")
    end
    -- расчёт юлианской даты
    local a = math.floor((14 - month)/12) 
    local y = year + 4800 - a
    local m = month + 12*a - 3
    local offset = math.floor(y/4) - 32083
    local jd = day + math.floor((153*m + 2)/5) + 365*y + offset
    -- проверка попадания юлианской даты в границы -9999 до 9999 года Г.К.
    local low, high = -1930999.5, 5373484.49999
    if not (low <= jd and jd <= high) then
        return error("Wrong date")
    end
    -- расчёт даты по григорианскому календарю
    local a = jd + 32044
    local b = math.floor((4*a + 3) / 146097)
    local c = a - math.floor(146097*b/4)
    local d = math.floor((4*c+3)/1461)
    local e = c - math.floor(1461*d/4)
    local m = math.floor((5*e+2)/153)
    local day_out =  e - math.floor((153*m+2)/5)+1
    local month_out = m + 3 - 12*math.floor(m/10)
    local year_out = 100*b + d - 4800 + math.floor(m/10)
    local date = os.date("%Y-%m-%d", os.time{year=year_out, month=month_out, day=day_out})
    return date
end

function p.ToIso( frame )
    local args = getArgs(frame, { frameOnly = true })
    local datein = args[1]
    -- парсинг входящей даты по шаблону
    local pattern = "(%d+)%.(%d+)%.(%d+)"
    local dayin, monthin, yearin = datein:match(pattern)
    local year = tonumber(yearin)
    local month = tonumber(monthin)
    local day = tonumber(dayin)
    -- проверка параметров
    if not (type(year) == 'number') then 
        return error("Wrong year")
    end
    if not (1 <= month and month <= 12) then 
        return error("Wrong month")
    end
    if not (1 <= day and day <= 31) then 
        return error("Wrong day")
    end
    local timedate = os.time{year=year, month=month, day=day}
    local date = os.date("%Y-%m-%d", timedate)
    return date
end

function p.ToDate( frame )
    local args = getArgs(frame, { frameOnly = true })
    local lang = mw.getContentLanguage()
    local datein = args[1]
    local format = "j xg Y"
    if not string.match(datein, "%p") then return datein
    elseif not args[2] then
    else format = args[2]
    end
    return lang:formatDate(format,datein,true)
end

return p