Zum Inhalt springen

„Modul:Time“ – Versionsunterschied

aus Wikipedia, der freien Enzyklopädie
[gesichtete Version][gesichtete Version]
Inhalt gelöscht Inhalt hinzugefügt
Keine Bearbeitungszusammenfassung
Keine Bearbeitungszusammenfassung
 
(44 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 44: Zeile 44:
},
},
URI = {
URI = {
GREGORIAN = "http://www.wikidata.org/entity/Q1985786",
GREGORIAN = "http://www.wikidata.org/entity/Q1985727",
JULIAN = "http://www.wikidata.org/entity/Q1985786"
JULIAN = "http://www.wikidata.org/entity/Q1985786"
},
},
Zeile 89: Zeile 89:
-- Point of time
-- Point of time
----------------------
----------------------

local autoprecision = function(o, default)
if o.precision then return o.precision end
if o.sec then return 14 end
if o.min then return 13 end
if o.hour then return 12 end
if o.day then return 11 end
if o.month then return 10 end
return default
end


--[[
--[[
constructor
constructor
parameter:
parameter:
source: string that can be processed by
source: either string that can be processed by
mw.language.getContentLanguage():formatDate
mw.language.getContentLanguage():formatDate
or table containing time information:
In this case negative julianian dates are accepted with an
offset of -1: 0 is translated to 1 BC, -1 = 2 BC, etc.
ATTENTION: This is usual but not in wikidata
]]
]]
function p.point:new(source)
function p.point:new(source)
Zeile 101: Zeile 115:
if type(source) == 'table' then
if type(source) == 'table' then
o = source
o = source
if o.year then
if o.year <= 0 then
o.era = '-'
o.year = 1 - o.year
o.calendarmodel = p.constant.URI.JULIAN
o.BC = true
else
if not o.era then o.era = '+' end
if o.BC then o.BC = false end
end
o.precision = autoprecision(o, 9)
else
o.era = 'n'
if o.BC then o.BC = false end
o.precision = autoprecision(o, 0)
end
else
o = {}
local fsIn = "+Y-m-d\\TH:i:s\\Z"
local fsOut = "(.)(%d+)%-(%d%d)%-(%d%d)T(%d%d):(%d%d):(%d%d)Z"
local lang = mw.language.getContentLanguage()
local success, t = pcall(lang.formatDate, lang, fsIn, source)
o.valid = success
if success then
o.era, o.year, o.month, o.day, o.hour, o.min, o.sec = t:match(fsOut)
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)
else
o.year = 0
o.month = 0
o.day = 0
end
if t:match('00:00:00Z') then o.precision = 11
elseif t:match('00:00Z') then o.precision = 12
elseif t:match('00Z') then o.precision = 13
else o.precision = 14
end
end
end
o = {}
setmetatable(o, self)
setmetatable(o, self)
self.__index = self
self.__index = self
if not o.calendarmodel then
local fsIn = "+Y-m-d\\TH:i:s\\Z"
if o < p.constant.STARTOFGREGORIAN then
local fsOut = "(.)(%d+)%-(%d%d)%-(%d%d)T(%d%d):(%d%d):(%d%d)Z"
o.calendarmodel = p.constant.URI.JULIAN
local t = mw.language.getContentLanguage():formatDate(fsIn, source)
o.BC = true
o.era, o.year, o.month, o.day, o.hour, o.min, o.sec = t:match(fsOut)
else
o.year = tonumber(o.year)
o.calendarmodel = p.constant.URI.GREGORIAN
o.month = tonumber(o.month)
end
o.day = tonumber(o.day)
o.hour = tonumber(o.hour)
o.min = tonumber(o.min)
o.sec = tonumber(o.sec)
if t:match('00:00:00Z') then o.precision = 11
elseif t:match('00:00Z') then o.precision = 12
elseif t:match('00Z') then o.precision = 13
else o.precision = 14
end
if o:isLessthan(p.constant.STARTOFGREGORIAN) then
o.calendarmodel = p.constant.URI.JULIAN
o.BC = true
else
o.calendarmodel = p.constant.URI.GREGORIAN
end
end
return o
return o
Zeile 155: Zeile 196:
list = {0, 31, 59, 90, 120, 151, 181, 212, 242, 273, 303, 334}
list = {0, 31, 59, 90, 120, 151, 181, 212, 242, 273, 303, 334}
local s = math.floor(y / 4)
local s = math.floor(y / 4)
mw.log('days by ')
if calendarmodel == p.constant.URI.GREGORIAN then
mw.log(point.calendarmodel)
if point.calendarmodel == p.constant.URI.GREGORIAN then
s = s - math.floor(y / 100)
s = s - math.floor(y / 100)
s = s + math.floor(y / 400)
s = s + math.floor(y / 400)
else
else
s = s + 10
s = s -2
end
end
return yb * 365 + s + list[point.month] + point.day
return yb * 365 + s + list[point.month] + point.day
Zeile 171: Zeile 214:
p.point.dayOfTheWeek = function(this)
p.point.dayOfTheWeek = function(this)
local d = days(this)
local d = days(this)
if d then return days(this) % 7 + 1
if d then return (days(this)+1) % 7 + 1
else return nil end
else return nil end
end

--[[
pointOfTime:setPrecision(level)
pointOfTime.precision initialization by date string merely is a guess
]]
p.point.setPrecision = function(this, level)
this.precision = level
end
end


Zeile 178: Zeile 229:
if not days then return nil end
if not days then return nil end
local o = {}
local o = {}
if calendar then o.calendarmdel = calendar
if calendar then o.calendarmodel = calendar
elseif days >= 577687 then o.calendarmdel = p.constant.URI.GREGORIAN
elseif days >= 577675 then o.calendarmodel = p.constant.URI.GREGORIAN
else o.calendarmdel = p.constant.URI.JULIAN end
else o.calendarmodel = p.constant.URI.JULIAN end
o.era = '+'
local febl = 28
if o.calendarmodel == p.constant.URI.GREGORIAN then
if o.calendarmodel == p.constant.URI.GREGORIAN then
local yb = math.floor(days / 365.2425)
local yb = math.floor(days / 365.2425)
Zeile 186: Zeile 239:
o.year = yb + 1
o.year = yb + 1
if (o.year % 400 == 0 or o.year % 100 > 0 and o.year % 4 == 0)
if (o.year % 400 == 0 or o.year % 100 > 0 and o.year % 4 == 0)
and days > 60 then days = days - 1 end
and days > 60 then
days = days - 1
febl = 29
end
else
else
o.BC = true
o.BC = true
local yb = math.floor(days / 365.25)
local yb = math.floor(days / 365.25)
days = days - math.floor(yb * 365.25)
days = days - math.floor(yb * 365.25) + 2
o.year = yb + 1
o.year = yb + 1
if o.year % 4 == 0 and days > 60 then days = days - 1 end
if o.year % 4 == 0 and days > 60 then
days = days - 1
febl = 29
end
end
end
list = {334, 303, 273, 242, 212, 181, 151, 120, 90, 59, 31, 0}
list = {334, 303, 273, 242, 212, 181, 151, 120, 90, 59, 31, 0}
Zeile 198: Zeile 257:
while not o.day do
while not o.day do
if days > list[i] then
if days > list[i] then
month = 13 - i
o.month = 13 - i
o.day = days - list[i]
o.day = days - list[i]
end
end
i = i + 1
i = i + 1
end
end
list = {31, febl, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
setmetatable(o, p.point)
if o.day > list[o.month] then
o.__index = function(table, key)
o.day = o.day - list[o.month]
return p.point[key]
o.month = o.month + 1
end
if o.month > 12 then
o.month = 1
o.year = o.year + 1
end
end
o.era = '+'
o.precision = 11
o.precision = 11
return p.point:new(o)
o.timezone = 0
return o
end

--[[
pointOfTime:setPrecision(level)
pointOfTime.precision initialization by date string merely is a guess
]]
p.point.setPrecision = function(this, level)
this.precision = level
end

p.point.timify = function(this, object)
if not ( object.year
or object.month and object.day
or object.hour and object.min) then return nil end
setmetatable(object, self)
self.__index = self
if not object.era then object.era = '+' end
if not object.precision then object.precision = 14 end
if not object.timezone then object.timezone = 0 end
if not object.calendarmodel then
if o:isLessthan(p.constant.STARTOFGREGORIAN) then
o.calendarmodel = "http://www.wikidata.org/entity/Q1985786"
o.BC = true
else
o.calendarmodel = "http://www.wikidata.org/entity/Q1985786"
end
end
end
end


Zeile 360: Zeile 394:
precision = b.precision
precision = b.precision
end
end
if a.era and b.era then
if a.era and b.era and a.era ~= 'n' and b.era ~= 'n' then
if a.era ~= b.era then return b.era == '+' end
if a.era ~= b.era then return b.era == '+' end
if a.year and b.year then
if a.year and b.year then
Zeile 436: Zeile 470:
doesn't contain time properties at all
doesn't contain time properties at all
]]
]]
p.point.equals = function(a, b)
p.point.equals = function(a, b) --####
if not a == not b then return true end
if not a and not b then return true end
if not a then return false end
if not a then return false end
if not b then return false end
if not b then return false end
mw.logObject(a, '===== a')
mw.logObject(b, '===== b')
if type(a) ~= 'table' then return type (b) == 'table' end
if type(a) ~= 'table' then return type (b) == 'table' end
if type (b) ~= 'table' then return false end
if type (b) ~= 'table' then return false end
Zeile 469: Zeile 505:
end
end
p.point.__eq = p.point.equals
p.point.__eq = p.point.equals
p.point.__ne = function(this)
return not p.point.equals(this)
end


--[[
--[[
Zeile 508: Zeile 547:
local result = '<tr style="background-color:'
local result = '<tr style="background-color:'
if type(b) == 'boolean' then if b then b = 'true' else b = 'false' end
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
elseif type(b) == 'table' then
local t = b.format
local t = b.format
Zeile 513: Zeile 553:
end
end
if type(c) == 'boolean' then if c then c = 'true' else c = 'false' 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
elseif type(c) == 'table' then
local t = c.format
local t = c.format
Zeile 532: Zeile 573:
result = result .. testLine("a < b", a < b, false)
result = result .. testLine("a < b", a < b, false)
result = result .. testLine("a > b", a > b, true)
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.point:new('1582-08-15')
a = p.point:new('1582-08-15')
result = result .. testLine("a, b", a, b)
result = result .. testLine("a, b", a, b)
result = result .. testLine("a < b", a < b, false)
result = result .. testLine("a < b", a < b, false)
result = result .. testLine("a == b", a == b, true)
result = result .. testLine("a == b", a == b, true)
result = result .. testLine("a ~= b", a ~= b, false)
a = p.point:new()
a = p.point:new()
result = result .. testLine("today", a:format('d.m.yyyy'), '1.11.2022')
result = result .. testLine("today", a:format('d.m.yyyy'), '2.11.2022')
result = result .. testLine("day of the week", a:dayOfTheWeek(), 3)
result = result .. testLine("day of the week", a:dayOfTheWeek(), 4)
result = result .. testLine("days of gregor", days(b), 577687)
result = result .. testLine("days of gregor", days(b), 577675)
result = result .. testLine("day of the week", b:dayOfTheWeek(), 2)
a = p.point:new('1582-08-04')
a = p.point:new('1582-08-04')
result = result .. testLine("days before", days(a), 577686)
result = result .. testLine("days before", days(a), 577674)
result = result .. testLine("day of the week", a:dayOfTheWeek(), 1)
for i = 50000, 50300 do
a = byDays(i)
b = byDays(days(a))
result = result .. testLine("a, b: " .. i, a, b)
end
return result .. '</table>'
return result .. '</table>'
end
end

Aktuelle Version vom 2. Dezember 2022, 08:43 Uhr

Vorlagenprogrammierung Diskussionen Lua Unterseiten
Modul Deutsch English

Modul: Dokumentation

Diese Seite enthält Code in der Programmiersprache Lua. Einbindungszahl Cirrus


--[=[ Time 2022-10-31
Modul for processing time information; point and span objects

Author: Vollbracht

== for use in other modules ==
* constant.PRECISIONLEVEL	table of valid precision values
			constants:
				MIN		lowest valid precision level (value for t.precision)
				MINUSE	lowest index of PRECISIONLEVEL table
				MAX		highest valid precision level
				[MINUSE] .. [MAX]	precision level name (unit)
			function
				unit(level)	unit name of smallest significant time element
* point	object representing a point of time
			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:isLessthan(time)	comparator method
				Time:equals(time)		comparator method

]=]

local p = {
	constant = {
		PRECISIONLEVEL = {
			MIN = 0,		-- lowest valid precision
			MINUSE = 9,		-- lowest available index
			MAXUSE = 14,	-- highest valid precision
			MAX=15,			-- highest available index
			-- unused: 'E8', 'E7', 'E6', 'E5', 'E4',
			-- [6]='millennium', [7]='century', [8]='decade',
			[9]='year', [10]='month', [11]='day',
			[12]='hour', [13]='min', [14]='sec', [15]='msec',
		},
		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'
		},
		URI = {
			GREGORIAN = "http://www.wikidata.org/entity/Q1985727",
			JULIAN = "http://www.wikidata.org/entity/Q1985786"
		},
		MONTHLENGTH = {31,28,31,30,31,30,31,31,30,31,30,31}
	},
	point = {},
	duration = {}
}

p.constant.STARTOFGREGORIAN = {
	era = '+',
	year = 1582,
	month = 8,
	day = 15,
	precision = 11,
	timezone = 0,
	calendarmodel = p.constant.URI.GREGORIAN,
	__index = function(table, key)
		return p.point[key]
	end
}
setmetatable(p.constant.STARTOFGREGORIAN, p.point)

--[[
	p.constant.PRECISIONLEVEL
	constant constructor:
]]
local precisionlevel = function()
	o = {}
	o.__index = function(table, key)
		return p.constant.PRECISIONLEVEL[key]
	end
	o.unit = function(this, level)
		if level < o.MIN then return '' end
		if level < o.MINUSE then return o[o.MINUSE] end
		if level > o.MAXUSE then return o[o.MAXUSE] end
		local result = o[i]
		if result then return result end
	end
	return o
end

---------------------- point ----------------------
-- Point of time
----------------------

local autoprecision = function(o, default)
	if o.precision then return o.precision end
	if o.sec then return 14 end
	if o.min then return 13 end
	if o.hour then return 12 end
	if o.day then return 11 end
	if o.month then return 10 end
	return default
end	

--[[
	constructor
	parameter:
		source:	either string that can be processed by
					mw.language.getContentLanguage():formatDate
				or table containing time information:
					In this case negative julianian dates are accepted with an
					offset of -1: 0 is translated to 1 BC, -1 = 2 BC, etc.
					ATTENTION: This is usual but not in wikidata
]]
function p.point:new(source)
	local o = nil
	if source then
		if type(source) == 'table' then
			o = source
			if o.year then
				if o.year <= 0 then
					o.era = '-'
					o.year = 1 - o.year
					o.calendarmodel = p.constant.URI.JULIAN
					o.BC = true
				else
					if not o.era then o.era = '+' end
					if o.BC then o.BC = false end
				end
				o.precision = autoprecision(o, 9)
			else
				o.era = 'n'
				if o.BC then o.BC = false end
				o.precision = autoprecision(o, 0)
			end
		else
			o = {}
			local fsIn = "+Y-m-d\\TH:i:s\\Z"
			local fsOut = "(.)(%d+)%-(%d%d)%-(%d%d)T(%d%d):(%d%d):(%d%d)Z"
			local lang = mw.language.getContentLanguage()
			local success, t = pcall(lang.formatDate, lang, fsIn, source)
			o.valid = success
			if success then
			o.era, o.year, o.month, o.day, o.hour, o.min, o.sec = t:match(fsOut)
				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)
			else
				o.year = 0
				o.month = 0
				o.day = 0
			end
			if t:match('00:00:00Z') then o.precision = 11
			elseif t:match('00:00Z') then o.precision = 12
			elseif t:match('00Z') then o.precision = 13
			else o.precision = 14
			end
		end
		setmetatable(o, self)
		self.__index = self
		if not o.calendarmodel then
			if o < p.constant.STARTOFGREGORIAN then
				o.calendarmodel = p.constant.URI.JULIAN
				o.BC = true
			else
				o.calendarmodel = p.constant.URI.GREGORIAN
			end
		end
		return o
	else
		local d = os.date("!*t")
		for k, v in pairs(p.point) do d[k] = v end
		d.era = '+'
		d.precision = 14
		d.timezone = 0
		d.calendarmodel = p.constant.URI.GREGORIAN
		return d
	end
end

--[[
	days(pointOfTime)
	theoretical number of days since 1.1.0000
	returns:	positive integer or nil (year before christian counting)
]]
local days = function(point)
	if not point.year then return nil end
	if point.year < 1 then return nil end
	if not point.month then return nil end
	if not point.day then return nil end
	local yb = point.year - 1
	local list = {	yb, yb,
					point.year, point.year, point.year, point.year, point.year,
					point.year, point.year, point.year, point.year, point.year}
	local y = list[point.month]
	list = {0, 31, 59, 90, 120, 151, 181, 212, 242, 273, 303, 334}
	local s = math.floor(y / 4)
	mw.log('days by ')
	mw.log(point.calendarmodel)
	if point.calendarmodel == p.constant.URI.GREGORIAN then
		s = s - math.floor(y / 100)
		s = s + math.floor(y / 400)
	else
		s = s -2
	end
	return yb * 365 + s + list[point.month] + point.day
end

--[[
	pointOfTime:dayOfTheWeek
	returns:	number from 1 (sunday) to 7 (saturday) or
				nil (year before christian counting)
]]
p.point.dayOfTheWeek = function(this)
	local d = days(this)
	if d then return (days(this)+1) % 7 + 1
	else return nil end
end

--[[
	pointOfTime:setPrecision(level)
	pointOfTime.precision initialization by date string merely is a guess
]]
p.point.setPrecision = function(this, level)
	this.precision = level
end

local byDays = function(days, calendar)
	if not days then return nil end
	local o = {}
	if calendar then o.calendarmodel = calendar
	elseif days >= 577675 then o.calendarmodel = p.constant.URI.GREGORIAN
	else o.calendarmodel = p.constant.URI.JULIAN end
	o.era = '+'
	local febl = 28
	if o.calendarmodel == p.constant.URI.GREGORIAN then
		local yb = math.floor(days / 365.2425)
		days = days - math.floor(yb * 365.2425)
		o.year = yb + 1
		if (o.year % 400 == 0 or o.year % 100 > 0 and o.year % 4 == 0)
		and days > 60 then
			days = days - 1
			febl = 29
		end
	else 
		o.BC = true
		local yb = math.floor(days / 365.25)
		days = days - math.floor(yb * 365.25) + 2
		o.year = yb + 1
		if o.year % 4 == 0 and days > 60 then
			days = days - 1
			febl = 29
		end
	end
	list = {334, 303, 273, 242, 212, 181, 151, 120, 90, 59, 31, 0}
	local i = 1
	while not o.day do
		if days > list[i] then
			o.month = 13 - i
			o.day = days - list[i]
		end
		i = i + 1
	end
	list = {31, febl, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
	if o.day > list[o.month] then
		o.day = o.day - list[o.month]
		o.month = o.month + 1
	end
	if o.month > 12 then
		o.month = 1
		o.year = o.year + 1
	end
	o.precision = 11
	return p.point:new(o)
end

--[[
	pointOfTime: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 with all requested information or ''
]]
p.point.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
			fmtStr = p.constant.DEFAULTFORMAT[this.precision]
			if not fmtStr then return '' end
		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
		else
			if fmtStr:match('%%[yY]') then return '' end
		end
		if this.month then fmtStr = fmtStr:gsub('%%m', d2(this.month))
		else if fmtStr:match('%%m') then return '' end end
		if this.month then fmtStr = fmtStr:gsub('%%d', d2(this.day))
		else if fmtStr:match('%%d') then return '' end end
		if this.month then fmtStr = fmtStr:gsub('%%H', d2(this.hour))
		else if fmtStr:match('%%H') then return '' end end
		if this.month then fmtStr = fmtStr:gsub('%%M', d2(this.min))
		else if fmtStr:match('%%M') then return '' end end
		if this.month then fmtStr = fmtStr:gsub('%%S', d2(this.sec))
		else if fmtStr:match('%%S') then return '' end 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
		else if fmtStr:match('[jy][jy]') then return '' end end
		if this.month then
			fmtStr = fmtStr:gsub('mm', d2(this.month))
			fmtStr = fmtStr:gsub('m', this.month)
		else if fmtStr:match('m') then return '' end 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)
		else if fmtStr:match('[dt]') then return '' end end
		if this.hour then
			fmtStr = fmtStr:gsub('HH', d2(this.hour))
			fmtStr = fmtStr:gsub('H', this.hour)
		else if fmtStr:match('H') then return '' end end
		if this.min then
			fmtStr = fmtStr:gsub('MM', d2(this.min))
			fmtStr = fmtStr:gsub('M', this.min)
		else if fmtStr:match('M') then return '' end end
		if this.sec then
			fmtStr = fmtStr:gsub('SS', d2(this.sec))
			fmtStr = fmtStr:gsub('S', this.sec)
		else if fmtStr:match('S') then return '' end 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

--[[
	pointOfTime.isLessthan(a, b)
	datetime compare
	parameters:
		a, b	2 pointOfTime 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.point.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 and a.era ~= 'n' and b.era ~= 'n' 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.constant.PRECISIONLEVEL[i]]
		local ab = b[p.constant.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
--[[
	pointOfTime.LT(a, b)
	comparator function for sort e.g.
]]
p.point.__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
--[[
	pointOfTime.LE(a, b)
	comparator function
]]
p.point.__le = function(a, b)
	if a.time then a = a.time end
	if b.time then b = b.time end
	if not b.isLessthan then return false end
	return not b:isLessthan(a)
end
--[[
	pointOfTime.GT(a, b)
	comparator function
]]
p.point.__gt = function(a, b)
	if a.time then a = a.time end
	if b.time then b = b.time end
	if not b.isLessthan then return false end
	return b:isLessthan(a)
end
--[[
	pointOfTime.LE(a, b)
	comparator function
]]
p.point.__ge = 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 not 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.point.equals = function(a, b) --####
	if not a and not b then return true end
	if not a then return false end
	if not b then return false end
	mw.logObject(a, '===== a')
	mw.logObject(b, '===== b')
	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.constant.PRECISIONLEVEL[i]]
		local ab = b[p.constant.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
p.point.__eq = p.point.equals
p.point.__ne = function(this)
	return not p.point.equals(this)
end

--[[
	pointOfTime:gregorian()
	gregorian variant of a julian date
]]
p.point.gregorian = function(this)
	if this.calendarmodel == p.constant.URI.GREGORIAN then return this end
	local result = {}
	for k, v in pairs(this) do result[k] = v end
	setmetatable(result, self)
	self.__index = self
	local yDif = this.year - 1600
	local sdty = 0
	local sdtc = 0
	local cDif = 0
	local dDif = 0
	if this.year % 100 == 0 then
		if this.month > 2 then sdty = 1 end
		cDif = yDif / 100
		if yDif > 0 then
			
			if this.month > 2 then sdtc = 1 end
		else
			if this.month <= 2 then sdtc = -1 end
		end
	else
		if this.year % 4 == 0 and this.month > 2 then sdty = 1 end
		cDif = math.floor(yDif / 100)
	end
	local cDif = 10 + cDif - math.floor(yDif / 400)
end

---------------------- template service ----------------------
-- test, etc.
----------------------

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.point:new('1.3.2000')
	mw.logObject(a)
	result = result .. testLine("a:format('mm-dd')", a:format('mm-dd'), '03-01')
	local b = p.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.point: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.point: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.point: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