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

Новая страница: «local p = {} -- Необходимые модули и переменные local getArgs = require('Module:Arguments').getArgs local yesno = require('Module:Yesno') local mwlang = mw.getContentLanguage() local err = "―" -- NthDay nil result local tCon = table.concat -- 00) Блок многократно используемых списков local bool_to_number={ [true]=1, [false]=0 } local monthlang = {"января","февраля","марта","а...»
 
Нет описания правки
 
(не показана 1 промежуточная версия этого же участника)
Строка 7: Строка 7:
local tCon = table.concat
local tCon = table.concat


-- 00) Блок многократно используемых списков
-- Блок многократно используемых списков
local bool_to_number={ [true]=1, [false]=0 }
local bool_to_number={ [true]=1, [false]=0 }
local monthlang = {"января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря"}
local monthlang = {"января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря"}
Строка 46: Строка 46:
   -- US Millitary (for RFC-822)
   -- US Millitary (for RFC-822)
   Z='+00:00', A='-01:00', M='-12:00', N='+01:00', Y='+12:00',
   Z='+00:00', A='-01:00', M='-12:00', N='+01:00', Y='+12:00',
  -- российское обозначение
  ["МСК"]='+03:00',
}
}


-- имена по конвенции [[:Категория:Тептар:Статьи по типам недостатков]]:
-- «ошибочная работа» — результат выдать не удалось; «неполные или некорректные
-- параметры» — результат выдан, но параметры пришлось восстанавливать эвристиками
local cat_erroneous  = "[[Категория:Тептар:Статьи с ошибочной работой Модуль:Calendar]]"
local cat_incomplete = "[[Категория:Тептар:Статьи с неполными или некорректными параметрами Модуль:Calendar]]"
local category = {
local category = {
["no_parameters"]=
["no_parameters"]         = cat_erroneous,
"<!--[[Категория:Модуль:Calendar:Страницы без параметров]]-->",
["incomplete_parameters"] = cat_incomplete,
["incomplete_parameters"]=
["without_verification"] = cat_incomplete,
"<!--[[Категория:Модуль:Calendar:Страницы с неполными или некорректными параметрами]]-->",
["erroneous_parameters"] = cat_erroneous,
["without_verification"]=
"<!--[[Категория:Модуль:Calendar:Страницы без проверки параметров]]-->",
["erroneous_parameters"]=
"<!--[[Категория:Модуль:Calendar:Страницы с ошибочными параметрами]]-->"
}
}


Строка 76: Строка 79:
-- [""]="",
-- [""]="",
}
}
local tzs_names = {"ACDT","ACST","ACT","ADT","AEDT","AEST","AFT","AKDT","AKST",
"AMST","AMT","ART","AST","AST","AST","AST","AWDT","AWST","AZOST","AZT","BDT",
"BIOT","BIT","BOT","BRT","BST","BST","BTT","CAT","CCT","CDT","CEDT","CEST",
"CET","CHAST","CIST","CKT","CLST","CLT","COST","COT","CST","CST","CVT","CXT",
"CHST","DFT","EAST","EAT","ECT","ECT","EDT","EEDT","EEST","EET","EST","FJT",
"FKST","FKT","GALT","GET","GFT","GILT","GIT","GMT","GST","GYT","HADT","HAST",
"HKT","HMT","HST","IRKT","IRST","IST","IST","IST","JST","KRAT","KST","LHST",
"LINT","MAGT","MDT","MIT","MSD","MSK","MST","MST","MST","MUT","NDT","NFT",
"NPT","NST","NT","OMST","PDT","PETT","PHOT","PKT","PST","PST","RET","SAMT",
"SAST","SBT","SCT","SLT","SST","SST","TAHT","THA","UTC","UYST","UYT","VET",
"VLAT","WAT","WEDT","WEST","WET","YAKT","YEKT","Z","A","M","N","Y","MSK"}


local pattern = { -- для распознавания дат, переданных одним строчным параметром
local pattern = { -- для распознавания дат, переданных одним строчным параметром
Строка 140: Строка 131:
end
end


-- 10) Блок общих функций
-- Блок общих функций
local function trim(str)
local function trim(str)
if not str then return nil
if not str then return nil
Строка 207: Строка 198:
end
end


-- 20) Блок общих проверочных функций, связанных с датами
-- Блок общих проверочных функций, связанных с датами
local function unwarp(tbl)
local function unwarp(tbl)
if not tbl then return ""
if not tbl then return ""
Строка 306: Строка 297:
end
end


-- 30) Блок функций для обработки ввода-вывода дат
-- Блок функций для обработки ввода-вывода дат


local function undate(tbl)
local function undate(tbl)
Строка 352: Строка 343:
return date --, error_data
return date --, error_data
end
end
----[[ УСТАРЕЛО ]]----
-- DEPRECATED
local numstr2date = function(numstr)
local numstr2date = function(numstr)
local format = "Y-m-d"
local format = "Y-m-d"
Строка 398: Строка 389:
end
end
local function day2lang(datein,wikidate,wiki,inner_brt)
-- prefix — текст перед днём внутри подписи ссылки (открывающая скобка при inner_brt)
local function day2lang(datein,wikidate,wiki,inner_brt,prefix)
-- if not isdate(wikidate) then wiki = false end
-- if not isdate(wikidate) then wiki = false end
if not ispartdate(datein) then return "" end
if not ispartdate(datein) then return "" end
Строка 405: Строка 397:
if (not datein.month) then datein.month = "" end
if (not datein.month) then datein.month = "" end
if (not datein.day) then datein.day = "" end
if (not datein.day) then datein.day = "" end
if not prefix then prefix = "" end
local monlan = monthlang[datein.month] or ""
local monlan = monthlang[datein.month] or ""
if wiki and not inner_brt then
if wiki and not inner_brt then
output = tCon({"[[", wikidate.day, " ", monthlang[wikidate.month] or "",
output = tCon({"[[", wikidate.day, " ", monthlang[wikidate.month] or "",
"|", (datein.day or ""), dm_separ, monlan, "]]"})
"|", prefix, (datein.day or ""), dm_separ, monlan, "]]"})
elseif wiki then
elseif wiki then
output = tCon({"[[", wikidate.day, " ", monthlang[wikidate.month] or "",
output = tCon({"[[", wikidate.day, " ", monthlang[wikidate.month] or "",
"|", (datein.day or ""), dm_separ, monlan})
"|", prefix, (datein.day or ""), dm_separ, monlan})
else
else
output = tCon({datein.day, dm_separ, monlan})
output = tCon({prefix, datein.day, dm_separ, monlan})
end
end
     return trim(output)
     return trim(output)
Строка 482: Строка 475:
gd.month, jd.month = nil, nil
gd.month, jd.month = nil, nil
end
end
if (not not cd.month) and wm then  
if (not not cd.month) and wm then
return tCon({comment[1] .. trim(day2lang(jd,jdate,false) .. " " .. year2lang(jd.year,yearmark,false)) .. comment[2],  
-- ссылка тут сквозная (закрывается после общего месяца), поэтому открывающая
trim(left .. day2lang(gd,gdate,wd,wm) .. " " .. year2lang(gd.year,yearmark,wy)) .. right,  
-- скобка уходит внутрь подписи: [[21 февраля|(21) февраля]], а не ([[21 февраля|21) февраля]]
local gday = day2lang(gd,gdate,wd,wm,left)
if gday == "" then gday = left end
return tCon({comment[1] .. trim(day2lang(jd,jdate,false) .. " " .. year2lang(jd.year,yearmark,false)) .. comment[2],
trim(gday .. " " .. year2lang(gd.year,yearmark,wy)) .. right,
day2lang(cd,gdate,false) .. "]]", trim(year2lang(cd.year,yearmark,wy)..msg)}, " ")
day2lang(cd,gdate,false) .. "]]", trim(year2lang(cd.year,yearmark,wy)..msg)}, " ")
end  
end
return tCon({comment[1] .. trim(day2lang(jd,jdate,false) .. " " .. year2lang(jd.year,yearmark,false)) .. comment[2],  
return tCon({comment[1] .. trim(day2lang(jd,jdate,false) .. " " .. year2lang(jd.year,yearmark,false)) .. comment[2],  
trim(left .. day2lang(gd,gdate,wd) .. " " .. year2lang(gd.year,yearmark,wy)) .. right,  
trim(left .. day2lang(gd,gdate,wd) .. " " .. year2lang(gd.year,yearmark,wy)) .. right,  
Строка 492: Строка 489:
end
end


-- 40) Блок функций для перевода дат с использованием [[Юлианская дата]]
-- Блок функций для перевода дат с использованием [[Юлианская дата]]


local function gri2jd( datein )
local function gri2jd( datein )
Строка 583: Строка 580:
end
end


-- 50) Функции для обработки UTC
-- Функции для обработки UTC


local function utc(str,margin)
local function utc(str,margin)
Строка 604: Строка 601:
error("Нет входящей строки")
error("Нет входящей строки")
elseif str:byte(1) == 43 then
elseif str:byte(1) == 43 then
elseif inbord(str:byte(1),48,57) then cat = "[[Категория:Википедия:Ошибка в часовом поясе НП]]"
elseif inbord(str:byte(1),48,57) then cat = "[[Категория:Тептар:Ошибка в часовом поясе НП]]"
elseif str:byte(1) == 45 or string.sub(str,1,3) == "−" or string.sub(str,1,1)=="-" then d = -1
elseif str:byte(1) == 45 or string.sub(str,1,3) == "−" or string.sub(str,1,1)=="-" then d = -1
else
else
Строка 629: Строка 626:
local h, m = math.modf(math.abs(timedec))
local h, m = math.modf(math.abs(timedec))
hmarg = h
hmarg = h
mmarg = math.floor(m*60)
mmarg = math.floor(m*60 + 0.5)   -- без +0.5 «+4:35» давало 4:34: m*60 = 34.999…
end
end
if timedec == 0 then
if timedec == 0 then
Строка 642: Строка 639:
end
end


-- 60) Блок функций ввода-вывода
-- Блок функций ввода-вывода


function p.NthDay( frame )
function p.NthDay( frame )
Строка 650: Строка 647:
if not format then format = "%d.%m.%y" end
if not format then format = "%d.%m.%y" end
     if not inbord(num,-5,5) then  
     if not inbord(num,-5,5) then  
     return error("The number must be between -5 and 5")
     return e.start .. "The number must be between -5 and 5" .. e.ending .. category.erroneous_parameters
     elseif num == 0 then  
     elseif num == 0 then  
     return error("The number must not be zero") end
     return e.start .. "The number must not be zero" .. e.ending .. category.erroneous_parameters end
     if not inbord(wday,0,6) then  
     if not inbord(wday,0,6) then  
     return error("The day of the week must be between 0 and 6") end
     return e.start .. "The day of the week must be between 0 and 6" .. e.ending .. category.erroneous_parameters end
     if not inbord(mont,1,12) then  
     if not inbord(mont,1,12) then  
     return error("The month must be between 1 and 12") end
     return e.start .. "The month must be between 1 and 12" .. e.ending .. category.erroneous_parameters end
     if not inbord(yea,0,9999) then  
     if not inbord(yea,0,9999) then  
     return error("Wrong year number") end
     return e.start .. "Wrong year number" .. e.ending .. category.erroneous_parameters end
     if inbord(num,1,5) then
     if inbord(num,1,5) 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}
Строка 724: Строка 721:
     local txtDateOut, date, status = p.bxDate(txtDateIn, strFormat, params)
     local txtDateOut, date, status = p.bxDate(txtDateIn, strFormat, params)
if status.brk then
if status.brk then
return error(status.errorText)
return e.start .. status.errorText .. e.ending .. (status.errorCat or "")
else
else
return txtDateOut
return txtDateOut
Строка 730: Строка 727:
end
end


function p.bxDate( txtDateIn , strFormat, params ) -- к отладке
function p.bxDate( txtDateIn , strFormat, params )
local txtDateOut, date, status = "", {}, {brk = false, errorCat = "", errorText = ""}
local txtDateOut, date, status = "", {}, {brk = false, errorCat = "", errorText = ""}
strFormat = strFormat or "j xg Y"
strFormat = strFormat or "j xg Y"
Строка 772: Строка 769:
end
end


function p.ToDate( frame ) -- возможно неиспользуемая
function p.ToDate( frame )
     local args = getArgs(frame, { frameOnly = true })
     local args = getArgs(frame, { frameOnly = true })
     local mwlang = mw.getContentLanguage()
     local mwlang = mw.getContentLanguage()
Строка 785: Строка 782:


-- =p.unitime(mw.getCurrentFrame():newChild{title="smth",args={"−1:30","1"}})
-- =p.unitime(mw.getCurrentFrame():newChild{title="smth",args={"−1:30","1"}})
-- ── Разбор пользовательской записи часового пояса ────────────────────────────
-- Признак того, что в строке зашито второе значение (зимнее/летнее) или
-- диапазон: такую строку разбирать нельзя — потеряется половина смысла.
local function has_second_value(tail)
if tail == '' then return false end
local t = mw.ustring.lower(tail)
return mw.ustring.find(t, '[+±−%-]%s*%d') ~= nil
or mw.ustring.find(t, 'лет[а-яё]') ~= nil
or mw.ustring.find(t, 'зим[а-яё]') ~= nil
or mw.ustring.find(t, 'dst') ~= nil
or mw.ustring.find(t, 'summer') ~= nil
or mw.ustring.find(t, 'winter') ~= nil
end
-- Минуты из записи «часы<разделитель>дробь».
-- «:30» — канон; «.30» и «,30» — те же 30 минут; «.5» и «,5» — половина часа.
-- Второе возвращаемое значение — признак того, что применена эвристика.
local function minutes_from(sep, frac)
if frac == '' then return 0, false end
local n = tonumber(frac)
if sep == ':' then return n, false end
if mw.ustring.len(frac) == 2 and n <= 59 then return n, true end
return math.floor(tonumber('0.' .. frac) * 60 + 0.5), true
end
-- Приводит вход к каноническому «±H:MM» для utc(), отдельно возвращая
-- неразобранный хвост строки и признак применённой эвристики.
-- Первое значение nil — разбор не удался.
local function split_tz(input)
local abbr = known_tzs[mw.ustring.upper(input)]
if abbr then return abbr, '', false end
local letters, sign, hh, sep, mm, tail = mw.ustring.match(
input, '^(%a*)%s*([+±−%-]?)%s*(%d+)([:%.,]?)(%d*)(.-)%s*$')
if not hh then return nil end
if letters ~= '' and mw.ustring.upper(letters) ~= 'UTC' then return nil end
if sep ~= '' and mm == '' then return nil end          -- «+3:» — обрубок
if has_second_value(tail) then return nil end
local minutes, guessed = minutes_from(sep, mm)
if minutes > 59 then return nil end
if sign == '' or sign == '±' then sign = '+' end
return sign .. hh .. ':' .. string.format('%02d', minutes), tail,
guessed or tail ~= ''
end


function p.unitime( frame )
function p.unitime( frame )
     local args = getArgs(frame, { frameOnly = true })
     local args = getArgs(frame, { frameOnly = true })
     local DST = 0
     local DST = 0
     if not args[2] then  
     if args[2] then DST = 1 end
    else DST = 1 end
     local input = trim(args[1] or "")
    local utcin = ""
     if input == "" then return "" end
     local input = args[1]
     -- уже оформленное (Тептар-ссылка или шаблон) возвращается как есть
     if not input then return "" end
     if string.sub(input,1,1) == '[' or string.sub(input,1,1) == '{' then
     if inlist(input:upper(),tzs_names) then
         return input
    utcin = known_tzs[input:upper()]
    end
     elseif (string.sub(input:upper(),1,3) == 'UTC') and (string.len(input) < 10) then
    local utcin, tail, heuristic = split_tz(input)
    utcin = string.sub(input,4)
    if not utcin then
    else
        -- не распознано: вернуть как есть, пометить категорией
    if string.sub(input,1,1) == '['  
        return input .. category.erroneous_parameters
        or string.sub(input,1,1) == '{'  
         or string.sub(input,1,1):upper() == 'U'
        or string.sub(input,1,1):upper() == 'M' then
        return input
--     elseif not string.find(string.upper(string.sub(input,1,1)),"[\65-\90]") or
--      not string.find(string.upper(string.sub(input,1,1)),"[\192-\223]") then
--    return input
    else utcin = input end
     end
     end
--  elseif string.sub(input,1,3) ~= "−" then utcin = input
     local ok, output
--  or not (not input:find("[А-я]")) при наличии в строке юникода не работает
     if DST == 0 then
     local output = ""
    ok, output = pcall(function() return utc(utcin) .. tail end)
     if DST == 0 then output = utc(utcin)
     else
     else output = utc(utcin) .. ", [[летнее время|летом]] " .. utc(utcin,DST)
    ok, output = pcall(function()
    return utc(utcin) .. tail .. ", [[летнее время|летом]] " .. utc(utcin,DST)
    end)
     end
     end
    if not ok then return input .. category.erroneous_parameters end
    if heuristic then return output .. category.incomplete_parameters end
     return output
     return output
end
end




-- УСТАРЕЛО
-- DEPRECATED
-- =p.OldDate(mw.getCurrentFrame():newChild{title="smth",args={"20.02.2020","ю",["bc"]="1",["wd"]="1",["wy"]="1",["sq_brts"]="1",["yearmark"]="г."}})
-- =p.OldDate(mw.getCurrentFrame():newChild{title="smth",args={"20.02.2020","ю",["bc"]="1",["wd"]="1",["wy"]="1",["sq_brts"]="1",["yearmark"]="г."}})
function p.OldDate( frame )
function p.OldDate( frame )
Строка 826: Строка 864:
     local gdate, jdate = {}, {}
     local gdate, jdate = {}, {}
     local strin = args[1]  
     local strin = args[1]  
     local cal = args[2]:lower() or "г"
     local cal = (args[2] or "г"):lower()
     local bc = is(args["bc"])
     local bc = is(args["bc"])
     local wd = is(args["wd"])
     local wd = is(args["wd"])
Строка 999: Строка 1037:
return err .. category.incomplete_parameters
return err .. category.incomplete_parameters
end
end
end
-- Блок реестра календарей и вывода дат по разным календарям
-- "ГГГГ-ММ-ДД" → таблица {year, month, day}
local function iso2date(iso)
local y, m, d = string.match(iso or "", "^(-?%d+)-(%d%d?)-(%d%d?)$")
return {["year"]=purif(y), ["month"]=purif(m), ["day"]=purif(d)}
end
-- Коптский календарь: арифметика через JD. Эпоха 1.1.1 = JD 1825030
-- (29 августа 284 года по юлианскому). Високосный год: y mod 4 == 3.
local function coptic2jd(y, m, d)
return 1825029 + 365*(y-1) + math.floor(y/4) + 30*(m-1) + d
end
local function jd2coptic(jd)
local year = math.floor((4*(jd - 1825030) + 1463)/1461)
local month = math.floor((jd - coptic2jd(year, 1, 1))/30) + 1
local day = jd - coptic2jd(year, month, 1) + 1
return {["year"]=year, ["month"]=month, ["day"]=day}
end
-- Реестр календарей. Два вида записей:
--  fmt  = календарь умеет сам движок MediaWiki (коды x* в formatDate);
--  conv = своя математика: функция JD → таблица {year, month, day}.
-- Новый календарь = одна строка (fmt) либо строка + пара функций x2jd/jd2x.
local calreg = {
{["id"]="григорианский", ["name"]="[[Григорианский календарь|Григорианский]]", ["fmt"]="j xg Y"},
{["id"]="юлианский", ["name"]="[[Юлианский календарь|Юлианский]]", ["conv"]=jd2jul},
{["id"]="исламский", ["name"]="[[Исламский календарь|Исламский (хиджра)]]", ["fmt"]="xmj xmF xmY"},
{["id"]="иранский", ["name"]="[[Иранский календарь|Иранский (солнечная хиджра)]]", ["fmt"]="xij xiF xiY"},
{["id"]="еврейский", ["name"]="[[Еврейский календарь|Еврейский]]", ["fmt"]="xjj xjF xjY"},
{["id"]="тайский", ["name"]="[[Тайский солнечный календарь|Тайский солнечный]]", ["fmt"]="j xg xkY"},
{["id"]="миньго", ["name"]="[[Миньго|Миньго]]", ["fmt"]="j xg xoY"},
{["id"]="нэнго", ["name"]="[[Японское летосчисление|Японский (нэнго)]]", ["fmt"]="j xg (xtY)"},
{["id"]="коптский", ["name"]="[[Коптский календарь|Коптский]]", ["conv"]=jd2coptic},
}
local function cal_render(entry, iso, jd)
if entry.fmt then
return mwlang:formatDate(entry.fmt, iso)
end
local d = entry.conv(jd)
return tCon({d.day, ".", string.format("%02d", d.month), ".", d.year})
end
-- {{#invoke:Песочница/Carn/Calendar|CalDate|2026-07-27|еврейский}} → 13 Ав 5786
-- Первый аргумент пустой = сегодня (по UTC).
function p.CalDate(frame)
local args = getArgs(frame, { frameOnly = true })
local iso = trim(args[1] or "")
if iso == "" then iso = mwlang:formatDate("Y-m-d") end
local date = iso2date(iso)
if not isdate(date) then
return e.start .. string.format(e.box_date, iso) .. e.ending .. category.erroneous_parameters
end
local id = trim(args[2] or "")
for i = 1, #calreg do
if calreg[i].id == id then
return cal_render(calreg[i], iso, gri2jd(date))
end
end
return e.start .. string.format(e.unknown_param, id) .. e.ending .. category.erroneous_parameters
end
-- Дашборд: {{#invoke:Песочница/Carn/Calendar|Today}} → таблица «сегодня по всем
-- календарям реестра». Необязательный аргумент — фиксированная дата для тестов.
function p.Today(frame)
local args = getArgs(frame, { frameOnly = true })
local iso = trim(args[1] or "")
if iso == "" then iso = mwlang:formatDate("Y-m-d") end
local date = iso2date(iso)
if not isdate(date) then
return e.start .. string.format(e.box_date, iso) .. e.ending .. category.erroneous_parameters
end
local jd = gri2jd(date)
local rows = {'{| class="wikitable sortable"', '! Календарь !! Дата'}
for i = 1, #calreg do
table.insert(rows, '|-')
table.insert(rows, '| ' .. calreg[i].name .. ' || ' .. cal_render(calreg[i], iso, jd))
end
table.insert(rows, '|}')
return tCon(rows, "\n")
end
-- Блок семейства {{OldStyleDate}} ({{СС}}, {{СС2}}, {{СС3}}, {{СС4}}) — T276471.
local cat_mismatch = "[[Категория:Тептар:Статьи с несовпадающими датами старого и нового стиля]]"
local jul_title = "по юлианскому календарю"
local gri_title = "по григорианскому календарю"
local function ifset(v) return v ~= nil and trim(v) ~= "" end
-- {{Comment|text|title}} без вызова шаблона: те же стили и тот же span
local function comment_span(frame, text, title)
local styles = frame:extensionTag("templatestyles", "", { src = "Шаблон:Comment/styles.css" })
title = title:gsub('"', "&quot;"):gsub("<", "&lt;"):gsub(">", "&gt;")
return tCon({styles, '<span class="ts-comment-commentedText" title="', title, '">', text, "</span>"})
end
-- {{До символа|s| }} — текст до первого пробела
local function before_space(s) return (s:match("^([^ ]*)")) end
-- юлианская дата → JD без проверки (переполнение нормализуется, как в PHP strtotime)
local function jul2jd_lenient(y, m, d)
local a = math.floor((14 - m)/12)
local yy = y + 4800 - a
local mm = m + 12*a - 3
return d + math.floor((153*mm + 2)/5) + 365*yy + math.floor(yy/4) - 32083
end
-- Проверка пары дат {{СС}}: старый стиль (od, om, oy) должен давать новый (nd, nm, ny).
-- Возвращает категорию или "". Год неизвестен → перебор эпох с разрывом 10…13 дней,
-- по високосному и невисокосному году на каждую (февраль).
local function osd_check(d1, m1, y1, d2, m2, y2)
local nd = tonumber(d1:match("^%s*(%d+)%s*$"))
local nm = month_to_num[trim(m1)]
local ny = tonumber((y1:match("%d+")))
local od = tonumber(d2:match("^%s*(%d+)%s*$"))
local om, oy = nm, ny
if ifset(m2) then om = month_to_num[trim(m2)]
elseif not od then -- «24 августа» одним параметром
od = tonumber(d2:match("^%s*(%d+)"))
om = month_to_num[mw.ustring.match(d2, "(%a+)") or ""]
end
if ifset(y2) then oy = tonumber((y2:match("%d+"))) end
if not (nd and nm and od and om) then return "" end -- диапазон, прочерк — не проверяем
if not isdate({year = oy or 1900, month = om, day = od}, true) then return category.incomplete_parameters end
local years = oy and {oy} or {1600, 1650, 1704, 1750, 1804, 1850, 1904, 1950}
for _, y in ipairs(years) do
local g = jd2gri(jul2jd_lenient(y, om, od))
if g.day == nd and g.month == nm then
if not oy or not ny or g.year == ny then return "" end
if not ifset(y2) then return category.incomplete_parameters end -- год НС другой, а {{{6}}} не задан
end
end
return cat_mismatch
end
-- {{OldStyleDate|день НС|месяц НС|год НС|день СС|месяц СС|год СС|[}} ; 7-й параметр = квадратные скобки
function p.OldStyleDate(frame)
local a = frame.args
local d1, m1, y1, d2, m2, y2 = a[1] or "", a[2] or "", a[3] or "", a[4] or "", a[5] or "", a[6] or ""
local lb, rb = "(", ")"
if ifset(a[7]) then lb, rb = "&#91;", "&#93;" end
local function jul(text) return comment_span(frame, text, jul_title) end
local year_link = ""
if ifset(y1) then year_link = tCon({"&nbsp;[[", before_space(y1), " год|", y1, "]]"}) end
local m1_tail = ifset(m1) and ("&nbsp;" .. m1) or ""
local out
if ifset(y2) then
out = tCon({jul(d2 .. "&nbsp;" .. m2 .. " " .. y2), " ", lb, "[[", d1, "&nbsp;", m1, "]] [[", before_space(y1), " год|", y1, "]]", rb})
elseif ifset(m2) then
out = tCon({jul(d2 .. "&nbsp;" .. m2), " ", lb, "[[", d1, m1_tail, "]]", rb, year_link})
else
out = tCon({jul(d2), "&nbsp;[[", d1, " ", m1, "|", lb, d1, rb, m1_tail, "]]", year_link})
end
return out .. osd_check(d1, m1, y1, d2, m2, y2)
end
-- {{OldStyleDate3|д.м.гггг|года|bracket=|bracket end=}} — дата по старому стилю, новый стиль считается
function p.OldStyleDate3(frame)
local a = frame.args
local strin, ym = a[1] or "", trim(a[2] or "")
local lb = ifset(a["bracket"]) and trim(a["bracket"]) or "("
local rb = ifset(a["bracket end"]) and trim(a["bracket end"]) or ")"
local d, m, y = strin:match("^%s*(%d%d?)%s*[%.%-/]%s*(%d%d?)%s*[%.%-/%s]%s*(%d%d%d%d?)%s*$")
if not d then -- запасной разбор движком, как #time
local ok, iso = pcall(function() return mwlang:formatDate("Y-m-d", strin) end)
if ok then y, m, d = iso:match("^(%d+)-(%d+)-(%d+)$") end
end
if not d then
return e.start .. string.format(e.no_valid_date, strin) .. e.ending .. category.erroneous_parameters
end
d, m, y = tonumber(d), tonumber(m), tonumber(y)
local msg = ""
if not (m >= 1 and m <= 12 and isdate({year = y, month = m, day = d}, true)) then
msg = category.incomplete_parameters -- 30.02 и т. п.: нормализуем, как PHP, и помечаем
end
local jd = jul2jd_lenient(y, m, d)
local jdate, gdate = jd2jul(jd), jd2gri(jd)
local jD, jM, jY = tostring(jdate.day), monthlang[jdate.month], tostring(jdate.year)
local gD, gM, gY = tostring(gdate.day), monthlang[gdate.month], tostring(gdate.year)
local ymk = (ym ~= "") and ("&nbsp;" .. ym) or ""
local function jul(text) return comment_span(frame, text, jul_title) end
if jdate.year*10000 + jdate.month*100 + jdate.day <= 15821004 then -- до введения григорианского
return jul(jD .. "&nbsp;" .. jM .. "&nbsp;" .. jY .. ymk) .. msg
end
if jdate.month == gdate.month then
return tCon({comment_span(frame, jD, jD .. " " .. jM .. " " .. jul_title), "&nbsp;", lb,
"[[", gD, " ", gM, '|<span title="', gD, " ", gM, " ", gri_title, '">', gD, "</span>]]", rb,
"&nbsp;", gM, "&nbsp;[[", gY, " год|", gY, ymk, "]]", msg})
elseif jdate.year == gdate.year then
return tCon({jul(jD .. "&nbsp;" .. jM), "&nbsp;", lb,
"[[", gD, " ", gM, '|<span title="', gri_title, '">', gD, "&nbsp;", gM, "</span>]]", rb,
"&nbsp;[[", gY, " год|", gY, ymk, "]]", msg})
end
return tCon({jul(jD .. "&nbsp;" .. jM .. "&nbsp;" .. jY .. ymk), "&nbsp;", lb,
"[[", gD, " ", gM, '|<span title="', gri_title, '">', gD, "&nbsp;", gM, "</span>]]",
"&nbsp;[[", gY, " год|<span title=\"", gri_title, '">', gY, "</span>]]", rb, msg})
end
end


return p
return p