Zum Inhalt springen

„Modul:Wikidata/Time“ – Versionsunterschied

aus Wikipedia, der freien Enzyklopädie
[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


p.test = function(frame)
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