„Modul:Wikidata/Time“ – Versionsunterschied
Erscheinungsbild
[gesichtete Version] | [gesichtete Version] |
Inhalt gelöscht Inhalt hinzugefügt
Keine Bearbeitungszusammenfassung |
Vererbung |
||
Zeile 28: | Zeile 28: | ||
--Module globals |
--Module globals |
||
local _, GeneralTime = pcall(require, "Modul:Time") |
|||
local constant = GeneralTime.constant |
|||
local pointOfTime = GeneralTime.point |
|||
local p = { service={ |
local p = { service={ |
||
-- more selective variant to '(.)(%d+)%-(%d+)%-(%d+)T(%d+):(%d+):(%d+)Z': |
-- more selective variant to '(.)(%d+)%-(%d+)%-(%d+)T(%d+):(%d+):(%d+)Z': |
||
MATCHING = '(.)(%d+)%-([0-1]%d)%-([0-3]%d)T([0-2]%d):([0-6]%d):([0-6]%d)Z', |
MATCHING = '(.)(%d+)%-([0-1]%d)%-([0-3]%d)T([0-2]%d):([0-6]%d):([0-6]%d)Z', |
||
PRECISIONLEVEL = |
PRECISIONLEVEL = constant.PRECISIONLEVEL, |
||
DEFAULTFORMAT = constant.DEFAULTFORMAT, |
|||
-- unused: |
|||
'E8', 'E7', 'E6', 'E5', 'E4', |
|||
-- use with caution (only 'year' is in time object) : |
|||
[6]='millennium', [7]='century', [8]='decade', [9]='year', |
|||
-- use at will (fields in time object): |
|||
[10]='month', [11]='day', [12]='hour', [13]='min', [14]='sec' |
|||
}, |
|||
DEFAULTFORMAT = { |
|||
[6]='yyyye=( v.Chr.)', [7]='yyyye=( v.Chr.)', [9]='yyyye=( v.Chr.)', |
|||
[9]='yyyye=( v.Chr.)', [10]='mm/yyyy', [11]='dd.mm.yyyy', [12]='HH Uhr', |
|||
[13]='HH:MM Uhr', [14]='E=(+)e=(-)yyyy-mm-ddTHH:MM:SSZ' |
|||
}, |
|||
PoT='point of time' |
PoT='point of time' |
||
} } |
} } |
||
Zeile 65: | Zeile 59: | ||
-- time object is UTC system time if no source specified |
-- time object is UTC system time if no source specified |
||
if not source or source == '' then |
if not source or source == '' then |
||
return pointOfTime:new() |
|||
d = os.date("!*t") |
|||
for k, v in pairs(p.service) do d[k] = v end |
|||
d.era = '+' |
|||
d.precision = 14 |
|||
d.timezone = 0 |
|||
d.calendarmodel = "http://www.wikidata.org/entity/Q1985727" |
|||
d.__tostring=function() |
|||
return d:format('+yyyy-mm-ddTHH:MM:SSZ') |
|||
end |
|||
return d |
|||
end |
end |
||
o = {} |
|||
setmetatable(o, self) |
|||
self.__index = self |
|||
if type(source) == "table" then |
if type(source) == "table" then |
||
local ts = source["time"] |
local ts = source["time"] |
||
if not ts then |
if not ts then return pointOfTime:new(source) end |
||
o = {} |
|||
o.__tostring=function() |
|||
setmetatable(o, {__index = pointOfTime}) |
|||
return 'Time not initialized!' |
|||
self.__index = self |
|||
end |
|||
return o |
|||
end |
|||
o.era, o.year, o.month, o.day, o.hour, o.min, o.sec |
o.era, o.year, o.month, o.day, o.hour, o.min, o.sec |
||
= ts:match(o.MATCHING) |
= ts:match(o.MATCHING) |
||
Zeile 103: | Zeile 83: | ||
end |
end |
||
return o |
return o |
||
end |
|||
--[[ |
|||
Time.isLessthan(a, b) |
|||
datetime compare |
|||
parameters: |
|||
a, b 2 service.time objects |
|||
returns: true if on lowest precision level a is before b |
|||
false if necessary properties inavailable or |
|||
if a is same time or later than b on given |
|||
precision level |
|||
]] |
|||
p.service.isLessthan = function(a, b) |
|||
if not a then return false end |
|||
if not b then return false end |
|||
local precision = 11 |
|||
if a.precision then precision = a.precision end |
|||
if b.precision and b.precision < precision then |
|||
precision = b.precision |
|||
end |
|||
if a.era and b.era then |
|||
if a.era ~= b.era then return b.era == '+' end |
|||
if a.year and b.year then |
|||
local na = tonumber(a.year) |
|||
local nb = tonumber(b.year) |
|||
if na ~= nb then return (a.era == '+') == (na < nb) end |
|||
else return false end |
|||
end |
|||
for i = 10, 14 do |
|||
if precision < i then return false end |
|||
local aa = a[p.service.PRECISIONLEVEL[i]] |
|||
local ab = b[p.service.PRECISIONLEVEL[i]] |
|||
if aa and ab then |
|||
local na = tonumber(aa) |
|||
local nb = tonumber(ab) |
|||
if na ~= nb then return na < nb end |
|||
else return false end |
|||
i = i + 1 |
|||
end |
|||
return false |
|||
end |
|||
--[[ |
|||
Time.LT(a, b) |
|||
comparator function for sort e.g. |
|||
]] |
|||
p.service.LT = function(a, b) |
|||
if a.time then a = a.time end |
|||
if b.time then b = b.time end |
|||
if not a.isLessthan then return false end |
|||
return a.isLessthan(b) |
|||
end |
|||
--[[ |
|||
Time.equals(a, b) |
|||
compares any objects in terms of time properties |
|||
parameters: two of any kind |
|||
returns: true * if both objects represent the same time at lowest |
|||
common precision level |
|||
* if both objects lack the same time properties |
|||
* if both are no objects but of simple data type |
|||
false * if the objects represent different times at lowest |
|||
common precision level |
|||
* if only one lacks a relevant time property |
|||
* if only one is of simple data type even if the other |
|||
doesn't contain time properties at all |
|||
]] |
|||
p.service.equals = function(a, b) |
|||
if not a == not b then return true end |
|||
if not a then return false end |
|||
if not b then return false end |
|||
if type(a) ~= 'table' then return type (b) == 'table' end |
|||
if type (b) ~= 'table' then return false end |
|||
local precision = 11 |
|||
if a.precision then precision = a.precision end |
|||
if b.precision and b.precision < precision then |
|||
precision = b.precision |
|||
end |
|||
if a.era then |
|||
if a.era == '+' then |
|||
if b.era and b.era ~= '+' then return false end |
|||
else |
|||
if b.era then |
|||
if b.era == '+' then return false end |
|||
else return false end |
|||
end |
|||
else |
|||
if b.era and b.era ~= '+' then return false end |
|||
end |
|||
if precision < 9 then precision = 9 end |
|||
for i = 9, precision do |
|||
local aa = a[p.service.PRECISIONLEVEL[i]] |
|||
local ab = b[p.service.PRECISIONLEVEL[i]] |
|||
if not aa ~= not ab then return false end |
|||
if aa and aa ~= ab then return false end |
|||
i = i + 1 |
|||
end |
|||
return true |
|||
end |
|||
--[[ |
|||
Time:format(fmtStr) |
|||
return formated date time value based on given format string |
|||
parameters: |
|||
fmtStr: limited format string evaluating each appearance of keys: |
|||
either |
|||
%y or %Y for year |
|||
%m for month |
|||
%d for day of month |
|||
%H for 24-hour hour value |
|||
%M for minute |
|||
%S for second |
|||
or |
|||
yy or yyyy for year |
|||
m or mm for month |
|||
d or dd for day of month |
|||
H or HH for 24-hour hour value |
|||
M or MM for minute |
|||
S or SS for second |
|||
e=(<content>) for content string appearing |
|||
if era is '-' (BC) |
|||
E=(<content>) for content string appearing |
|||
if era is '+' (CE) |
|||
returns date time value string |
|||
]] |
|||
p.service.format = function(this, fmtStr) |
|||
function d2(value) |
|||
if value > 9 then return value end |
|||
return '0' .. value |
|||
end |
|||
if not fmtStr then |
|||
if this.precision then |
|||
if this.precision < 6 then return '' end |
|||
fmtStr = this.DEFAULTFORMAT[this.precision] |
|||
else return '' end |
|||
end |
|||
if fmtStr:match('%%') then |
|||
if this.year then |
|||
fmtStr = fmtStr:gsub('%%Y', this.year) |
|||
if this.year < 100 then fmtStr = fmtStr:gsub('%%y', this.year) |
|||
else fmtStr = fmtStr:gsub('%%y', d2(this.year % 100)) end |
|||
end |
|||
if this.month then fmtStr = fmtStr:gsub('%%m', d2(this.month)) end |
|||
if this.month then fmtStr = fmtStr:gsub('%%d', d2(this.day)) end |
|||
if this.month then fmtStr = fmtStr:gsub('%%H', d2(this.hour)) end |
|||
if this.month then fmtStr = fmtStr:gsub('%%M', d2(this.min)) end |
|||
if this.month then fmtStr = fmtStr:gsub('%%S', d2(this.sec)) end |
|||
else |
|||
if this.year then |
|||
fmtStr = fmtStr:gsub('yyyy', this.year) |
|||
fmtStr = fmtStr:gsub('jjjj', this.year) |
|||
if this.year < 100 then |
|||
fmtStr = fmtStr:gsub('yy', this.year) |
|||
fmtStr = fmtStr:gsub('jj', this.year) |
|||
else |
|||
fmtStr = fmtStr:gsub('yy', d2(this.year % 100)) |
|||
fmtStr = fmtStr:gsub('jj', d2(this.year % 100)) |
|||
end |
|||
end |
|||
if this.month then |
|||
fmtStr = fmtStr:gsub('mm', d2(this.month)) |
|||
fmtStr = fmtStr:gsub('m', this.month) |
|||
end |
|||
if this.day then |
|||
fmtStr = fmtStr:gsub('dd', d2(this.day)) |
|||
fmtStr = fmtStr:gsub('tt', d2(this.day)) |
|||
fmtStr = fmtStr:gsub('d', this.day) |
|||
fmtStr = fmtStr:gsub('t', this.day) |
|||
end |
|||
if this.hour then |
|||
fmtStr = fmtStr:gsub('HH', d2(this.hour)) |
|||
fmtStr = fmtStr:gsub('H', this.hour) |
|||
end |
|||
if this.min then |
|||
fmtStr = fmtStr:gsub('MM', d2(this.min)) |
|||
fmtStr = fmtStr:gsub('M', this.min) |
|||
end |
|||
if this.sec then |
|||
fmtStr = fmtStr:gsub('SS', d2(this.sec)) |
|||
fmtStr = fmtStr:gsub('S', this.sec) |
|||
end |
|||
if this.era then |
|||
if this.era == '+' then |
|||
fmtStr = fmtStr:gsub('e=%(.*%)', '') |
|||
fmtStr = fmtStr:gsub('E=%((.*)%)', '%1') |
|||
else |
|||
fmtStr = fmtStr:gsub('E=%(.*%)', '') |
|||
fmtStr = fmtStr:gsub('e=%((.*)%)', '%1') |
|||
end |
|||
end |
|||
end |
|||
return fmtStr |
|||
end |
end |
||
Zeile 425: | Zeile 214: | ||
end |
end |
||
local testLine = function(a, b, c) |
|||
local result = '<tr style="background-color:' |
|||
-- test constructions |
|||
if type(b) == 'boolean' then if b then b = 'true' else b = 'false' end |
|||
local t1 = p.service:new() |
|||
elseif b == nil then b = 'nil' |
|||
mw.logObject(t1, 'p.service:new()') |
|||
elseif type(b) == 'table' then |
|||
mw.logObject(DateTime, 'DateTime') |
|||
local t = b.format |
|||
mw.logObject(DateTime.Prototypes, 'DateTime.Prototypes') |
|||
if t then b = t(b) end |
|||
end |
|||
if type(c) == 'boolean' then if c then c = 'true' else c = 'false' end |
|||
elseif c == nil then c = 'nil' |
|||
elseif type(c) == 'table' then |
|||
local t = c.format |
|||
if t then c = t(c) end |
|||
end |
|||
if b == c then result = result .. '#4f4">' |
|||
else result = result .. '#f44">' end |
|||
return result .. '<td>' .. a .. '</td><td>' .. b .. '</td><td>' .. c |
|||
.. '</td></tr>' |
|||
end |
|||
p.test = function() |
|||
local result = '<table class="wikitable">' |
|||
local a = p.service:new('1.3.2000') |
|||
mw.logObject(a) |
|||
result = result .. testLine("a:format('mm-dd')", a:format('mm-dd'), '03-01') |
|||
local b = constant.STARTOFGREGORIAN |
|||
result = result .. testLine("a, b", a, b) |
|||
result = result .. testLine("a < b", a < b, false) |
|||
result = result .. testLine("a > b", a > b, true) |
|||
result = result .. testLine("a == b", a == b, false) |
|||
result = result .. testLine("a ~= b", a ~= b, true) |
|||
a = p.service:new('1582-08-15') |
|||
result = result .. testLine("a, b", a, b) |
|||
result = result .. testLine("a < b", a < b, false) |
|||
result = result .. testLine("a == b", a == b, true) |
|||
result = result .. testLine("a ~= b", a ~= b, false) |
|||
a = p.service:new() |
|||
result = result .. testLine("today", a:format('d.m.yyyy'), '2.11.2022') |
|||
result = result .. testLine("day of the week", a:dayOfTheWeek(), 4) |
|||
result = result .. testLine("days of gregor", days(b), 577675) |
|||
result = result .. testLine("day of the week", b:dayOfTheWeek(), 2) |
|||
a = p.service:new('1582-08-04') |
|||
result = result .. testLine("days before", days(a), 577674) |
|||
result = result .. testLine("day of the week", a:dayOfTheWeek(), 1) |
|||
return result .. '</table>' |
|||
end |
end |
||
Version vom 2. November 2022, 03:07 Uhr
Vorlagenprogrammierung | Diskussionen | Lua | Unterseiten | |
Modul | Deutsch
|
Modul: | Dokumentation |
Diese Seite enthält Code in der Programmiersprache Lua. Einbindungszahl Cirrus
--[=[ Wikidata/Time 2022-10-28
Module for processing wikidata time information
Author: Vollbracht
== for use in other modules ==
* service object representing a wikidata time property
fields: year, month, day, hour, min, sec,
precision, timezone, calendarmodel
constructor:
Time:new(value) processes snack.datavalue.value e.g.
method:
Time:format(fmtStr) string representation for time object
Time:qualified(snak) snak and qualification state
Time:isLessthan(time) comparator method
Time:equals(time) comparator method
* service.LT(a, b) comparator function for table.sort e.g.
* service.equals(a, b) comparator function
* service.timify(values) table of time objects by table of values
== for use in templates ==
{{#invoke:Wikidata/Time|now|<format string>}} current system time
(mainly for testing purposes;
format string optional: defaults to wikidata time string format)
]=]
--Module globals
local _, GeneralTime = pcall(require, "Modul:Time")
local constant = GeneralTime.constant
local pointOfTime = GeneralTime.point
local p = { service={
-- more selective variant to '(.)(%d+)%-(%d+)%-(%d+)T(%d+):(%d+):(%d+)Z':
MATCHING = '(.)(%d+)%-([0-1]%d)%-([0-3]%d)T([0-2]%d):([0-6]%d):([0-6]%d)Z',
PRECISIONLEVEL = constant.PRECISIONLEVEL,
DEFAULTFORMAT = constant.DEFAULTFORMAT,
PoT='point of time'
} }
local _, DateTime = pcall(require, "Modul:DateTime")
--------------------------- local functions -----------------------------
--------------------------- service functions -----------------------------
--[[
constructor
generates a Time object
parameters:
source: (optional) table of possible time informations as of
mw.wikibase.getBestStatements(a, b)[1].mainsnak.datavalue.value
current system time if nil
NO MANDANTORY INFOS IN TABLE! OBJECT MAY CONTAIN NO TIME DATA!
]]
function p.service:new(source)
-- time object is UTC system time if no source specified
if not source or source == '' then
return pointOfTime:new()
end
if type(source) == "table" then
local ts = source["time"]
if not ts then return pointOfTime:new(source) end
o = {}
setmetatable(o, {__index = pointOfTime})
self.__index = self
o.era, o.year, o.month, o.day, o.hour, o.min, o.sec
= ts:match(o.MATCHING)
o.year = tonumber(o.year)
o.month = tonumber(o.month)
o.day = tonumber(o.day)
o.hour = tonumber(o.hour)
o.min = tonumber(o.min)
o.sec = tonumber(o.sec)
o.precision = source.precision
o.timezone = source.timezone
o.calendarmodel = source.calendarmodel
o.__tostring=function()
return o:format()
end
end
return o
end
--[[
Time:qualified(Statement)
Statement and its qualification state
parameters:
Statement a Statement that is to be qualified
returns: Statement, true if this time qualifies the snack
Statement, false if Statement is independent from this time
nil, false if this time disqualifies the snack
nil, true if Statement is nil (Ex falso quodlibet)
]]
p.service.qualified = function(this, Statement)
if not snack then return nil, true end
if type(Statement) ~= 'table' then return Statement, false end
if not Statement.qualifiers then return Statement, false end
local hasCriteria = false
-- point of time
for _, pot in ipairs(Statement.qualifiers.P585) do
local comp = p.service:new(pot.datavalue.value)
if not this:equals(comp) then return nil, false end
hasCriteria = true;
end
-- start time
for _, pot in ipairs(Statement.qualifiers.P580) do
local comp = p.service:new(pot.datavalue.value)
if this:isLessthan(comp) then return nil, false end
hasCriteria = true;
end
-- end time
for _, pot in ipairs(Statement.qualifiers.P582) do
local comp = p.service:new(pot.datavalue.value)
if comp:isLessthan(this) then return nil, false end
hasCriteria = true;
end
return Statement, hasCriteria
end
--[[
Time:getFiltered(statemens)
new claim list without time disqualified claims
parameters:
statemens data source as of mw.wikidata.getBestStatements
returns: refined claimlist
]]
p.service.getFiltered = function(this, statements)
local result = {}
for _, v in ipairs(claimlist) do
local tested, tv = this:qualified(v)
if tested then table.insert(result, tested) end
end
return result
end
--[[
Time.timify(values)
table of time objects by table of values
can process statements as of mw.wikidata.getBestStatements('Q79822', 'P569')
or qualifiers for a statement
parameters:
values: table: {<source>, <source>, ...}
<source>: (requirements as of time:new() source parameter)
returns: table: {<time object>, <time object>, ...}
Time objects of <source>-elements that could be
converted are in this result table. The others are
just ignored. Hence contains initialized time
objects only.
nil if result table empty
]]
p.service.timify = function(values)
local result = {}
for _, v in ipairs(values) do
local value = v
if value.mainsnak then value = value.mainsnak end
if value.datavalue then value = value.datavalue end
if value.value then value = value.value end
local t = service.time:new(v)
if t.year then table.insert(result, t) end
end
if #result == 0 then return nil end
return result
end
--[[
Time.filtered(claimlist, timeStr)
new claim list without time disqualified claims
parameters:
claimlist data source as of mw.wikidata.getBestStatements
timeStr time given by user
returns: refined claimlist
]]
p.service.filtered = function(statements, timeStr)
local myTime = nil
if not timeStr then myTime = p.service:new() end
if timeStr:match('^%d+$') then
myTime = p.service:new({})
myTime.era = '+'
myTime.year = tonumber(timeStr)
myTime.precision=9
myTime.__tostring=function() -- just in case s.o. edits filtered(..)
return timeStr
end
else
local t = mw.language.getContentLanguage():formatDate(
"+Y-m-d\\TH:i:s\\Z", timeStr)
local p = 14
if t:match('00:00:00Z') then p = 11
elseif t:match('00:00Z') then p = 12
elseif t:match('00Z') then p = 13
end
local source={
time=t,
precision=p,
calendarmodel='http://www.wikidata.org/entity/Q1985727',
timezone=0
}
myTime = p.service:new(source)
end
return myTime:getFiltered(statements)
end
--------------------------- template functions -----------------------------
--[[
{{#invoke:Wikidata/Time|now|<format string>}}
current system time
]]
p.now = function(frame)
return p.service:new():format(frame.args[1])
end
local testLine = function(a, b, c)
local result = '<tr style="background-color:'
if type(b) == 'boolean' then if b then b = 'true' else b = 'false' end
elseif b == nil then b = 'nil'
elseif type(b) == 'table' then
local t = b.format
if t then b = t(b) end
end
if type(c) == 'boolean' then if c then c = 'true' else c = 'false' end
elseif c == nil then c = 'nil'
elseif type(c) == 'table' then
local t = c.format
if t then c = t(c) end
end
if b == c then result = result .. '#4f4">'
else result = result .. '#f44">' end
return result .. '<td>' .. a .. '</td><td>' .. b .. '</td><td>' .. c
.. '</td></tr>'
end
p.test = function()
local result = '<table class="wikitable">'
local a = p.service:new('1.3.2000')
mw.logObject(a)
result = result .. testLine("a:format('mm-dd')", a:format('mm-dd'), '03-01')
local b = constant.STARTOFGREGORIAN
result = result .. testLine("a, b", a, b)
result = result .. testLine("a < b", a < b, false)
result = result .. testLine("a > b", a > b, true)
result = result .. testLine("a == b", a == b, false)
result = result .. testLine("a ~= b", a ~= b, true)
a = p.service:new('1582-08-15')
result = result .. testLine("a, b", a, b)
result = result .. testLine("a < b", a < b, false)
result = result .. testLine("a == b", a == b, true)
result = result .. testLine("a ~= b", a ~= b, false)
a = p.service:new()
result = result .. testLine("today", a:format('d.m.yyyy'), '2.11.2022')
result = result .. testLine("day of the week", a:dayOfTheWeek(), 4)
result = result .. testLine("days of gregor", days(b), 577675)
result = result .. testLine("day of the week", b:dayOfTheWeek(), 2)
a = p.service:new('1582-08-04')
result = result .. testLine("days before", days(a), 577674)
result = result .. testLine("day of the week", a:dayOfTheWeek(), 1)
return result .. '</table>'
end
return p