Модуль:Calendar: различия между версиями
Перейти к навигации
Перейти к поиску
(обновление) |
|||
Строка 1: | Строка 1: | ||
+ | local p = {} | ||
+ | -- Необходимые модули | ||
local getArgs = require('Module:Arguments').getArgs | local getArgs = require('Module:Arguments').getArgs | ||
− | local | + | local yesno = require('Module:Yesno') |
− | + | local err = "―" -- NthDay nil result | |
− | local err = "- | + | -- 00) Блок многократно используемых списков |
local bool_to_number={ [true]=1, [false]=0 } | local bool_to_number={ [true]=1, [false]=0 } | ||
local monthlang = {"января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря"} | local monthlang = {"января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря"} | ||
− | local | + | local params = { {"г", "g"}, {"ю", "j"}, {"нэ", "НЭ", "ac", "AC"}, {"днэ", "ДНЭ", "bc", "BC"}} |
− | + | local comment = { '<span style="border-bottom: 1px dotted; cursor: help" title="по юлианскому календарю">','</span>'} | |
− | local | + | local known_tzs = { |
− | local | + | ACDT='+10:30', ACST='+09:30', ACT ='+08:00', ADT ='-03:00', AEDT ='+11:00', |
+ | AEST='+10:00', AFT ='+04:30', AKDT='-08:00', AKST ='-09:00', AMST ='+05:00', | ||
+ | AMT ='+04:00', ART ='-03:00', AST ='+03:00', AST ='+04:00', AST ='+03:00', | ||
+ | AST ='-04:00', AWDT='+09:00', AWST='+08:00', AZOST='-01:00', AZT ='+04:00', | ||
+ | BDT ='+08:00', BIOT='+06:00', BIT ='-12:00', BOT ='-04:00', BRT ='-03:00', | ||
+ | BST ='+06:00', BST ='+01:00', BTT ='+06:00', CAT ='+02:00', CCT ='+06:30', | ||
+ | CDT ='-05:00', CEDT='+02:00', CEST='+02:00', CET ='+01:00', CHAST='+12:45', | ||
+ | CIST='-08:00', CKT ='-10:00', CLST='-03:00', CLT ='-04:00', COST ='-04:00', | ||
+ | COT ='-05:00', CST ='-06:00', CST ='+08:00', CVT ='-01:00', CXT ='+07:00', | ||
+ | CHST='+10:00', DFT ='+01:00', EAST='-06:00', EAT ='+03:00', ECT ='-04:00', | ||
+ | ECT ='-05:00', EDT ='-04:00', EEDT='+03:00', EEST ='+03:00', EET ='+02:00', | ||
+ | EST ='-05:00', FJT ='+12:00', FKST='-03:00', FKT ='-04:00', GALT ='-06:00', | ||
+ | GET ='+04:00', GFT ='-03:00', GILT='+12:00', GIT ='-09:00', GMT ='+00:00', | ||
+ | GST ='-02:00', GYT ='-04:00', HADT='-09:00', HAST ='-10:00', HKT ='+08:00', | ||
+ | HMT ='+05:00', HST ='-10:00', IRKT='+08:00', IRST ='+03:30', IST ='+05:30', | ||
+ | IST ='+01:00', IST ='+02:00', JST ='+09:00', KRAT ='+07:00', KST ='+09:00', | ||
+ | LHST='+10:30', LINT='+14:00', MAGT='+11:00', MDT ='-06:00', MIT ='-09:30', | ||
+ | MSD ='+04:00', MSK ='+03:00', MST ='+08:00', MST ='-07:00', MST ='+06:30', | ||
+ | MUT ='+04:00', NDT ='-02:30', NFT ='+11:30', NPT ='+05:45', NST ='-03:30', | ||
+ | NT ='-03:30', OMST='+06:00', PDT ='-07:00', PETT ='+12:00', PHOT ='+13:00', | ||
+ | PKT ='+05:00', PST ='-08:00', PST ='+08:00', RET ='+04:00', SAMT ='+04:00', | ||
+ | SAST='+02:00', SBT ='+11:00', SCT ='+04:00', SLT ='+05:30', SST ='-11:00', | ||
+ | SST ='+08:00', TAHT='-10:00', THA ='+07:00', UTC ='+00:00', UYST ='-02:00', | ||
+ | UYT ='-03:00', VET ='-04:30', VLAT='+10:00', WAT ='+01:00', WEDT ='+01:00', | ||
+ | WEST='+01:00', WET ='+00:00', YAKT='+09:00', YEKT ='+05:00', MSK ='+03:00', | ||
+ | -- US Millitary (for RFC-822) | ||
+ | Z='+00:00', A='-01:00', M='-12:00', N='+01:00', Y='+12:00', | ||
+ | } | ||
+ | |||
+ | 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"} | ||
+ | |||
+ | -- 10) Блок общих функций | ||
+ | local function trim(str) | ||
+ | if not str then return nil | ||
+ | else return str:match'^()%s*$' and '' or str:match'^%s*(.*%S)' | ||
+ | end | ||
+ | end | ||
local function purif(str) | local function purif(str) | ||
Строка 19: | Строка 67: | ||
end | end | ||
-- need .5 -- ,5 number format converter? | -- need .5 -- ,5 number format converter? | ||
+ | end | ||
+ | |||
+ | local function is(str) | ||
+ | if (not str) or (str == "") then return false | ||
+ | else return yesno(str,false) | ||
+ | end | ||
end | end | ||
Строка 29: | Строка 83: | ||
end | end | ||
− | function | + | function shallowcopy(orig) |
− | local | + | local orig_type = type(orig) |
− | local | + | local copy |
− | + | if orig_type == 'table' then | |
− | + | copy = {} | |
− | if | + | for orig_key, orig_value in pairs(orig) do |
− | + | copy[orig_key] = orig_value | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
+ | else -- number, string, boolean, etc | ||
+ | copy = orig | ||
end | end | ||
+ | return copy | ||
end | end | ||
+ | |||
+ | local inlist = function ( var, list ) | ||
+ | local n = #list | ||
+ | local inlist = false | ||
+ | for i=1,n do | ||
+ | if var == list[i] then inlist = true end | ||
+ | end | ||
+ | return inlist | ||
+ | end | ||
+ | |||
+ | -- 20) Блок общих проверочных функций, связанных с датами | ||
local function isdate ( chain ) | local function isdate ( chain ) | ||
− | if (not type(chain) == "table") | + | if not chain then return false |
+ | elseif (not type(chain) == "table") | ||
or (not inbord(chain.year,-9999,9999)) | or (not inbord(chain.year,-9999,9999)) | ||
or (not inbord(chain.month,1,12)) | or (not inbord(chain.month,1,12)) | ||
Строка 84: | Строка 122: | ||
local function ispartdate ( chain ) | local function ispartdate ( chain ) | ||
− | if not (type(chain) == "table") then return false | + | if not chain then return false |
+ | elseif not (type(chain) == "table") then return false | ||
elseif (inbord(chain.year,-9999,9999) | elseif (inbord(chain.year,-9999,9999) | ||
and (not inbord(chain.month,1,12)) | and (not inbord(chain.month,1,12)) | ||
Строка 98: | Строка 137: | ||
end | end | ||
− | + | -- 30) Блок функций для обработки ввода-вывода дат | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | local function | + | local numstr2date = function(numstr) |
local nums = {} | local nums = {} | ||
local dateout = {} | local dateout = {} | ||
Строка 129: | Строка 161: | ||
end | end | ||
− | local function | + | local function year2lang(numyear,yearmark,wiki) |
− | if not | + | if not numyear then return "" end |
− | local | + | if not yearmark then yearmark = "" end |
− | + | local output = "" | |
+ | local bcmark = " до н. э." | ||
+ | if numyear > 0 then bcmark = "" | ||
+ | else numyear = 1 - numyear end | ||
+ | if wiki then | ||
+ | output = table.concat({'[[', numyear,' год',bcmark,'|', numyear,']]', " ", yearmark, " ", bcmark}) | ||
+ | else | ||
+ | output = table.concat({numyear, " ", yearmark, bcmark}) | ||
+ | end | ||
+ | return trim(output) | ||
end | end | ||
− | + | ||
− | local function | + | local function day2lang(datein,wikidate,wiki,inner_brt) |
− | if not ispartdate(datein) then return | + | -- if not isdate(wikidate) then wiki = false end |
− | local dm_separ | + | if not ispartdate(datein) then return "" end |
− | + | local dm_separ, output = "" | |
− | |||
− | |||
if (not (not datein.day)) and (not (not datein.month)) then dm_separ = " " end | if (not (not datein.day)) and (not (not datein.month)) then dm_separ = " " end | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
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 | ||
− | + | local monlan = monthlang[datein.month] or "" | |
− | + | if wiki and not inner_brt then | |
− | + | output = table.concat({"[[", wikidate.day, " ", monthlang[wikidate.month] or "", | |
− | + | "|", (datein.day or ""), dm_separ, monlan, "]]"}) | |
− | return | + | elseif wiki then |
+ | output = table.concat({"[[", wikidate.day, " ", monthlang[wikidate.month] or "", | ||
+ | "|", (datein.day or ""), dm_separ, monlan}) | ||
+ | else | ||
+ | output = table.concat({datein.day, dm_separ, monlan}) | ||
+ | end | ||
+ | return trim(output) | ||
end | end | ||
− | function trim( | + | local function double_couple(jdate, gdate, wd, wm, wy, sq_brts, yearmark) |
− | + | local cd = {} | |
+ | local jd = shallowcopy(jdate) | ||
+ | local gd = shallowcopy(gdate) | ||
+ | local left = "(" | ||
+ | local right = ")" | ||
+ | if sq_brts then | ||
+ | left = "[" | ||
+ | right = "]" | ||
+ | end | ||
+ | if (not isdate(jdate)) or (not isdate(gdate)) then return error("Some wrong date") end | ||
+ | if jd.year == gd.year then | ||
+ | cd.year = gd.year | ||
+ | gd.year, jd.year = nil | ||
+ | end | ||
+ | if jd.month == gd.month then | ||
+ | cd.month = gd.month | ||
+ | gd.month, jd.month = nil | ||
+ | end | ||
+ | if (not not cd.month) and wm then | ||
+ | return table.concat({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, | ||
+ | day2lang(cd,gdate,false) .. "]]", trim(year2lang(cd.year,yearmark,wy))}, " ") | ||
+ | end | ||
+ | return table.concat({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(day2lang(cd,gdate,false)), trim(year2lang(cd.year,yearmark,wy))}, " ") | ||
end | end | ||
− | + | -- 40) Блок функций для перевода дат с использованием [[Юлианская дата]] | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
function gri2jd( datein ) | function gri2jd( datein ) | ||
Строка 254: | Строка 296: | ||
end | end | ||
− | function | + | function astroyear(num, bc) |
− | + | if not bc then return num | |
− | + | else return 1 - num | |
− | + | end | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
− | function | + | function recalc(datein,calend) |
− | + | if inlist(calend,params[1]) then | |
− | + | return jd2jul(gri2jd(datein)), datein | |
− | + | elseif inlist(calend,params[2]) then | |
− | + | return datein, jd2gri(jul2jd(datein)) | |
− | + | else error("Second argument must be 'g' or 'j'") | |
− | + | end | |
− | |||
− | |||
− | |||
end | end | ||
− | + | -- 50) Функции для обработки UTC | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
local function utc(str,margin) | local function utc(str,margin) | ||
Строка 476: | Строка 370: | ||
end | end | ||
− | -- | + | -- 60) Блок функций ввода-вывода |
− | function p. | + | function p.NthDay( frame ) |
− | + | local args = getArgs(frame, { frameOnly = true }) | |
− | local | + | local num, wday, mont, yea, format = |
− | local | + | purif(args[1]), purif(args[2]), purif(args[3]), purif(args[4]), args[5] |
− | + | if not format then format = "%d.%m.%y" end | |
− | return | + | 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 | ||
+ | |||
+ | 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 | end | ||
Строка 496: | Строка 460: | ||
local input = args[1] | local input = args[1] | ||
if not input then return "" end | if not input then return "" end | ||
− | if | + | if inlist(input:upper(),tzs_names) then |
utcin = known_tzs[input:upper()] | utcin = known_tzs[input:upper()] | ||
elseif (string.sub(input:upper(),1,3) == 'UTC') and (string.len(input) < 10) then | elseif (string.sub(input:upper(),1,3) == 'UTC') and (string.len(input) < 10) then | ||
Строка 520: | Строка 484: | ||
end | end | ||
− | -- =p.OldDate(mw.getCurrentFrame():newChild{title="smth",args={"20.02.2020","ю"," | + | -- =p.OldDate(mw.getCurrentFrame():newChild{title="smth",args={"20.02.2020","ю",["bc"]="0",["wd"]="1",["wy"]="0",["sq_brts"]="0"}}) |
+ | -- =p.OldDate(mw.getCurrentFrame():newChild{title="smth",args={"20.02.2020","ю",["bc"]="1",["wd"]="1",["wy"]="1",["sq_brts"]="1",["yearmark"]="г."}}) | ||
-- function p.formatWikiImpl( t1, t2, infocardClass, categoryNamePrefix, brts ) | -- function p.formatWikiImpl( t1, t2, infocardClass, categoryNamePrefix, brts ) | ||
function p.OldDate( frame ) | function p.OldDate( frame ) | ||
local args = getArgs(frame, { frameOnly = true }) | local args = getArgs(frame, { frameOnly = true }) | ||
local gdate, jdate = {} | local gdate, jdate = {} | ||
− | local | + | local strin = args[1] |
− | local | + | local cal = args[2]:lower() or "г" |
− | local | + | local bc = is(args["bc"]) |
− | + | local wd = is(args["wd"]) | |
− | local | + | local wm = is(args["wm"]) |
− | if not | + | local wy = is(args["wy"]) |
− | local | + | if not wd then wm = false end |
− | if | + | local sq_brts = is(args["sq_brts"]) |
− | + | local yearmark = "года" | |
− | + | if yesno(args["yearmark"]) then | |
− | -- local | + | elseif yesno(args["yearmark"]) == false then yearmark = "" |
− | -- local | + | else yearmark = trim(args["yearmark"]) or "года" end |
+ | -- local infocard = is(args["infocard"]) | ||
+ | -- local catName = args["catName"] or false | ||
local datein = numstr2date(strin) | local datein = numstr2date(strin) | ||
− | + | datein.year = astroyear(datein.year, bc) | |
− | + | jdate, gdate = recalc(datein,cal) | |
− | + | return double_couple(jdate, gdate, wd, wm, wy, sq_brts, yearmark) | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
return p | return p |
Версия от 18:08, 3 февраля 2020
Для документации этого модуля может быть создана страница Модуль:Calendar/doc
local p = {}
-- Необходимые модули
local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')
local err = "―" -- NthDay nil result
-- 00) Блок многократно используемых списков
local bool_to_number={ [true]=1, [false]=0 }
local monthlang = {"января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря"}
local params = { {"г", "g"}, {"ю", "j"}, {"нэ", "НЭ", "ac", "AC"}, {"днэ", "ДНЭ", "bc", "BC"}}
local comment = { '<span style="border-bottom: 1px dotted; cursor: help" title="по юлианскому календарю">','</span>'}
local known_tzs = {
ACDT='+10:30', ACST='+09:30', ACT ='+08:00', ADT ='-03:00', AEDT ='+11:00',
AEST='+10:00', AFT ='+04:30', AKDT='-08:00', AKST ='-09:00', AMST ='+05:00',
AMT ='+04:00', ART ='-03:00', AST ='+03:00', AST ='+04:00', AST ='+03:00',
AST ='-04:00', AWDT='+09:00', AWST='+08:00', AZOST='-01:00', AZT ='+04:00',
BDT ='+08:00', BIOT='+06:00', BIT ='-12:00', BOT ='-04:00', BRT ='-03:00',
BST ='+06:00', BST ='+01:00', BTT ='+06:00', CAT ='+02:00', CCT ='+06:30',
CDT ='-05:00', CEDT='+02:00', CEST='+02:00', CET ='+01:00', CHAST='+12:45',
CIST='-08:00', CKT ='-10:00', CLST='-03:00', CLT ='-04:00', COST ='-04:00',
COT ='-05:00', CST ='-06:00', CST ='+08:00', CVT ='-01:00', CXT ='+07:00',
CHST='+10:00', DFT ='+01:00', EAST='-06:00', EAT ='+03:00', ECT ='-04:00',
ECT ='-05:00', EDT ='-04:00', EEDT='+03:00', EEST ='+03:00', EET ='+02:00',
EST ='-05:00', FJT ='+12:00', FKST='-03:00', FKT ='-04:00', GALT ='-06:00',
GET ='+04:00', GFT ='-03:00', GILT='+12:00', GIT ='-09:00', GMT ='+00:00',
GST ='-02:00', GYT ='-04:00', HADT='-09:00', HAST ='-10:00', HKT ='+08:00',
HMT ='+05:00', HST ='-10:00', IRKT='+08:00', IRST ='+03:30', IST ='+05:30',
IST ='+01:00', IST ='+02:00', JST ='+09:00', KRAT ='+07:00', KST ='+09:00',
LHST='+10:30', LINT='+14:00', MAGT='+11:00', MDT ='-06:00', MIT ='-09:30',
MSD ='+04:00', MSK ='+03:00', MST ='+08:00', MST ='-07:00', MST ='+06:30',
MUT ='+04:00', NDT ='-02:30', NFT ='+11:30', NPT ='+05:45', NST ='-03:30',
NT ='-03:30', OMST='+06:00', PDT ='-07:00', PETT ='+12:00', PHOT ='+13:00',
PKT ='+05:00', PST ='-08:00', PST ='+08:00', RET ='+04:00', SAMT ='+04:00',
SAST='+02:00', SBT ='+11:00', SCT ='+04:00', SLT ='+05:30', SST ='-11:00',
SST ='+08:00', TAHT='-10:00', THA ='+07:00', UTC ='+00:00', UYST ='-02:00',
UYT ='-03:00', VET ='-04:30', VLAT='+10:00', WAT ='+01:00', WEDT ='+01:00',
WEST='+01:00', WET ='+00:00', YAKT='+09:00', YEKT ='+05:00', MSK ='+03:00',
-- US Millitary (for RFC-822)
Z='+00:00', A='-01:00', M='-12:00', N='+01:00', Y='+12:00',
}
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"}
-- 10) Блок общих функций
local function trim(str)
if not str then return nil
else return str:match'^()%s*$' and '' or str:match'^%s*(.*%S)'
end
end
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 is(str)
if (not str) or (str == "") then return false
else return yesno(str,false)
end
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 shallowcopy(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in pairs(orig) do
copy[orig_key] = orig_value
end
else -- number, string, boolean, etc
copy = orig
end
return copy
end
local inlist = function ( var, list )
local n = #list
local inlist = false
for i=1,n do
if var == list[i] then inlist = true end
end
return inlist
end
-- 20) Блок общих проверочных функций, связанных с датами
local function isdate ( chain )
if not chain then return false
elseif (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))
-- or chain.year == 0
then return false
else return true end
-- more detailed check for 31.02 needed
-- check for other calendars needed
end
local function ispartdate ( chain )
if not chain then return false
elseif not (type(chain) == "table") then return false
elseif (inbord(chain.year,-9999,9999)
and (not inbord(chain.month,1,12))
and inbord(chain.day,1,31)) then return false
elseif (inbord(chain.year,-9999,9999)
or inbord(chain.month,1,12)
or inbord(chain.day,1,31)) then return true
else return false
end
-- partial date
-- more detailed check for 31.02.0000 needed
-- check for other calendars needed
end
-- 30) Блок функций для обработки ввода-вывода дат
local numstr2date = function(numstr)
local nums = {}
local dateout = {}
for num in string.gmatch(numstr,"(%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]}
elseif inbord(nums[1],1,31) then
dateout = {["year"]=nums[3], ["month"]=nums[2], ["day"]=nums[1]}
else
-- local lang = mw.getContentLanguage()
-- implement lang:formatDate(format,datein,true) here
return error("Unable to recognize date")
end
return dateout
end
local function year2lang(numyear,yearmark,wiki)
if not numyear then return "" end
if not yearmark then yearmark = "" end
local output = ""
local bcmark = " до н. э."
if numyear > 0 then bcmark = ""
else numyear = 1 - numyear end
if wiki then
output = table.concat({'[[', numyear,' год',bcmark,'|', numyear,']]', " ", yearmark, " ", bcmark})
else
output = table.concat({numyear, " ", yearmark, bcmark})
end
return trim(output)
end
local function day2lang(datein,wikidate,wiki,inner_brt)
-- if not isdate(wikidate) then wiki = false end
if not ispartdate(datein) then return "" end
local dm_separ, output = ""
if (not (not datein.day)) and (not (not datein.month)) then dm_separ = " " end
if (not datein.month) then datein.month = "" end
if (not datein.day) then datein.day = "" end
local monlan = monthlang[datein.month] or ""
if wiki and not inner_brt then
output = table.concat({"[[", wikidate.day, " ", monthlang[wikidate.month] or "",
"|", (datein.day or ""), dm_separ, monlan, "]]"})
elseif wiki then
output = table.concat({"[[", wikidate.day, " ", monthlang[wikidate.month] or "",
"|", (datein.day or ""), dm_separ, monlan})
else
output = table.concat({datein.day, dm_separ, monlan})
end
return trim(output)
end
local function double_couple(jdate, gdate, wd, wm, wy, sq_brts, yearmark)
local cd = {}
local jd = shallowcopy(jdate)
local gd = shallowcopy(gdate)
local left = "("
local right = ")"
if sq_brts then
left = "["
right = "]"
end
if (not isdate(jdate)) or (not isdate(gdate)) then return error("Some wrong date") end
if jd.year == gd.year then
cd.year = gd.year
gd.year, jd.year = nil
end
if jd.month == gd.month then
cd.month = gd.month
gd.month, jd.month = nil
end
if (not not cd.month) and wm then
return table.concat({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,
day2lang(cd,gdate,false) .. "]]", trim(year2lang(cd.year,yearmark,wy))}, " ")
end
return table.concat({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(day2lang(cd,gdate,false)), trim(year2lang(cd.year,yearmark,wy))}, " ")
end
-- 40) Блок функций для перевода дат с использованием [[Юлианская дата]]
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 astroyear(num, bc)
if not bc then return num
else return 1 - num
end
end
function recalc(datein,calend)
if inlist(calend,params[1]) then
return jd2jul(gri2jd(datein)), datein
elseif inlist(calend,params[2]) then
return datein, jd2gri(jul2jd(datein))
else error("Second argument must be 'g' or 'j'")
end
end
-- 50) Функции для обработки UTC
local function utc(str,margin)
local d = 1
local dchar = "+"
local beginning = "[[UTC"
local ending = "]]"
local cat = ""
local nums = {}
local hmarg, timedec = 0
local mmarg = "00"
local output = ""
-- checking type of input
if not margin then margin = 0
elseif type(tonumber(margin)) ~= 'number' then
output = "Can't shift by " .. margin
error(output)
end
if type(str) ~= 'string' then
error("String missing")
elseif str:byte(1) == 43 then
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
else
error(string.char(str:byte(1)) .. " is not valid first char somehow")
end
-- parsing input
for num in string.gmatch(str,"(%d+)") do
table.insert(nums,purif(num))
end
if #nums > 2 then error("Max 2 numbers expected")
elseif #nums == 0 then error("If you mean 0 — type it in")
elseif #nums == 1 then
if inbord(nums[1],0,14) then timedec = d*nums[1] + margin
else error("From -14 to 14 only") end
elseif #nums == 2 then
if not inbord(nums[1],0,14) then error("Hours from -14 to 14 only")
elseif not inbord(nums[2],0,59) then error("Minutes from 0 to 59 only")
else
timedec = d*(nums[1] + nums[2]/60) + margin
end
end
if tonumber(timedec) == purif(timedec) then hmarg = timedec
else
local h, m = math.modf(math.abs(timedec))
hmarg = h
mmarg = math.floor(m*60)
end
if timedec == 0 then
dchar = "±"
elseif timedec > 0 then
elseif timedec < 0 then
dchar = "−"
end
-- output
output = beginning .. dchar .. math.abs(hmarg) .. ":" .. string.format("%02d",mmarg) .. ending .. cat
return output
end
-- 60) Блок функций ввода-вывода
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
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
-- =p.unitime(mw.getCurrentFrame():newChild{title="smth",args={"−1:30","1"}})
function p.unitime( frame )
local args = getArgs(frame, { frameOnly = true })
local DST = 0
if not args[2] then
else DST = 1 end
local utcin = ""
local input = args[1]
if not input then return "" end
if inlist(input:upper(),tzs_names) then
utcin = known_tzs[input:upper()]
elseif (string.sub(input:upper(),1,3) == 'UTC') and (string.len(input) < 10) then
utcin = string.sub(input,4)
else
if string.sub(input,1,1) == '['
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
-- elseif string.sub(input,1,3) ~= "−" then utcin = input
-- or not (not input:find("[А-я]")) при наличии в строке юникода не работает
local output = ""
if DST == 0 then output = utc(utcin)
else output = utc(utcin) .. ", [[летнее время|летом]] " .. utc(utcin,DST)
end
return output
end
-- =p.OldDate(mw.getCurrentFrame():newChild{title="smth",args={"20.02.2020","ю",["bc"]="0",["wd"]="1",["wy"]="0",["sq_brts"]="0"}})
-- =p.OldDate(mw.getCurrentFrame():newChild{title="smth",args={"20.02.2020","ю",["bc"]="1",["wd"]="1",["wy"]="1",["sq_brts"]="1",["yearmark"]="г."}})
-- function p.formatWikiImpl( t1, t2, infocardClass, categoryNamePrefix, brts )
function p.OldDate( frame )
local args = getArgs(frame, { frameOnly = true })
local gdate, jdate = {}
local strin = args[1]
local cal = args[2]:lower() or "г"
local bc = is(args["bc"])
local wd = is(args["wd"])
local wm = is(args["wm"])
local wy = is(args["wy"])
if not wd then wm = false end
local sq_brts = is(args["sq_brts"])
local yearmark = "года"
if yesno(args["yearmark"]) then
elseif yesno(args["yearmark"]) == false then yearmark = ""
else yearmark = trim(args["yearmark"]) or "года" end
-- local infocard = is(args["infocard"])
-- local catName = args["catName"] or false
local datein = numstr2date(strin)
datein.year = astroyear(datein.year, bc)
jdate, gdate = recalc(datein,cal)
return double_couple(jdate, gdate, wd, wm, wy, sq_brts, yearmark)
end
return p