Модуль:Calendar
Материал из FetbukWiki
Функции
Находится в бета-версии (14 621 байт). Об ошибках просьба сообщать на страницу обсуждения шаблона или самого модуля, или 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
- первое (1) воскресенье (0) октября (10) (2020) года =
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}}
= 1 января 1г. (30 декабря -0г. д.н.э.) ошибка!{{#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 }}|г}}
= 12 г. (25 г.) ноября 2024г.{{#invoke:Calendar|OldDate|11.2.1602|j|wd=1|wm=0|wy=1}}
= 11 г. (21 г.) февраля 1602г.{{#invoke:Calendar|OldDate|11.2.1602|j|wd=1|wm=1|wy=1}}
= 11 г. (21 г.) февраля 1602г.{{#invoke:Calendar|OldDate|11.2.1602|g|bc=1|yearmark=г.}}
= 1 г. (11 г.) февраля 1602г.{{#invoke:Calendar|OldDate|11.2.1602|g|sq_brts=1|yearmark=0}}
= 1 г. (11 г.) февраля 1602г.
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 на строке 349: Wrong year. - 5 января 1002 =
{{#invoke:Calendar|ToIso|5 января 1002}}
= Ошибка Lua на строке 349: Wrong year.
- 1.2.1602 =
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» не существует.
- 06.1280 =
- 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}}
= 26 ноября 2024
- 1.2.1602 =
local getArgs = require('Module:Arguments').getArgs
local p = {}
local err = "-"
local bool_to_number={ [true]=1, [false]=0 }
local monthlang = {"января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря"}
local griglist = {"г", "g"}
local julilist = {"ю", "j"}
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 ispartdate ( chain )
if 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
local islist = 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
local function numstr2date(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 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
local function date2lang(datein)
if not ispartdate(datein) then return error("Wrong partial date") end
local dm_separ = ""
local my_separ = ""
local monlan = ""
local era = ""
if (not (not datein.day)) and (not (not datein.month)) then dm_separ = " " end
if (not (not datein.month)) and (not (not datein.year)) then my_separ = " " end
if not datein.year then datein.year = ""
elseif datein.year == "" then
elseif datein.year < 1 then
local negyear = datein.year
datein.year = - negyear
era = " д.н.э."
end
if (not datein.month) then datein.month = "" end
if (not datein.day) then datein.day = "" end
if type(my_separ) ~= "string" or type(dm_separ) ~= "string" then error("Separator fail to work") end
if (not datein.month) or (datein.month == "") then
else monlan = monthlang[datein.month] end
local dateout = datein.day .. dm_separ .. monlan .. my_separ .. datein.year .. "г." .. era
return dateout
end
function trim(str)
return str:match'^()%s*$' and '' or str:match'^%s*(.*%S)'
end
local function twodates2str(jdate,gdate)
if (not isdate(jdate)) or (not isdate(gdate)) then return error("Some wrong date")
else
local cdate = {}
if jdate.year == gdate.year then
cdate.year = jdate.year
jdate.year = ""
gdate.year = ""
end
if jdate.month == gdate.month then
cdate.month = jdate.month
jdate.month = ""
gdate.month = ""
end
local ending = ""
if ispartdate(cdate) then ending = " " .. date2lang(cdate) end
local output = '<span style="border-bottom: 1px dotted; cursor: help" title="по юлианскому календарю">' .. trim(date2lang(jdate)) .. "</span> (" .. trim(date2lang(gdate)) .. ")" .. ending
return output
end
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
-- =p.testing(mw.getCurrentFrame():newChild{title="smth",args={"20.02.2020"}})
function p.testing( frame )
local args = getArgs(frame, { frameOnly = true })
local datein = args[1]
local gdate = numstr2date(datein)
local jdate = jd2jul(gri2jd(gdate))
local output = twodates2str(jdate, gdate)
return output
end
-- =p.OldDate(mw.getCurrentFrame():newChild{title="smth",args={"20.02.2020","ю","днэ"}})
function p.OldDate( frame )
local args = getArgs(frame, { frameOnly = true })
local gdate, jdate = {}
local strin = args[1]
local calinp = ""
local era = ""
if not args[2] then calinp = "г" else calinp = args[2]:lower() end
if not args[3] then era = "нэ" else era = args[3]:lower() end
local datein = numstr2date(strin)
if era == "нэ" then
if islist(calinp,griglist) then
gdate = datein
jdate = jd2jul(gri2jd(gdate))
elseif islist(calinp,julilist) then
jdate = datein
gdate = jd2gri(jul2jd(jdate))
else error("Second argument must be 'g' or 'j'")
end
elseif era == "днэ" then
local negyear = datein.year
datein.year = - negyear
if islist(calinp,griglist) then
gdate = datein
jdate = jd2jul(gri2jd(gdate))
elseif islist(calinp,julilist) then
jdate = datein
gdate = jd2gri(jul2jd(jdate))
else error("Second argument must be 'g' or 'j'")
end
end
local output = twodates2str(jdate, gdate)
return output
end
return p