Modul:DateTime: Unterschied zwischen den Versionen
2015-07-15
(2015-03-16) |
(2015-07-15) |
||
Zeile 1: | Zeile 1: | ||
-- | local DateTime -- Date and time utilities | ||
Date and time utilities | local Serial = "2015-07-15" | ||
local Calc = { } | |||
-- | |||
local | |||
local Parser = { } | local Parser = { } | ||
local Private = { } | local Private = { } | ||
local Prototypes = { } | local Prototypes = { } | ||
local Templates = { } | |||
local World = { slang = "en", | local World = { slang = "en", | ||
monthsLong = { }, | monthsLong = { }, | ||
Zeile 17: | Zeile 13: | ||
local Nbsp = mw.ustring.char( 160 ) | local Nbsp = mw.ustring.char( 160 ) | ||
local Tab = mw.ustring.char( 9 ) | local Tab = mw.ustring.char( 9 ) | ||
local Frame | |||
World.era = { en = { "BC", "AD" } } | World.era = { en = { "BC", "AD" } } | ||
World.monthsAbbr = { en = { n = 3 } } | World.monthsAbbr = { en = { n = 3 } } | ||
Zeile 116: | Zeile 113: | ||
return mw.ustring.upper( mw.ustring.sub( a, 1, 1 ) ) | return mw.ustring.upper( mw.ustring.sub( a, 1, 1 ) ) | ||
.. mw.ustring.lower( mw.ustring.sub( a, 2 ) ) | .. mw.ustring.lower( mw.ustring.sub( a, 2 ) ) | ||
end -- | end -- capitalize() | ||
Zeile 131: | Zeile 128: | ||
DateTime = function ( assign, alien ) | local function frame() | ||
-- Create | if not Frame then | ||
Frame = mw.getCurrentFrame() | |||
end | |||
return Frame | |||
end -- frame() | |||
local Signature = "__datetime" | |||
local Metatable = { | |||
__index = function ( self, access ) | |||
local r = self[ Signature ][ access ] | |||
if r == nil then | |||
if access == "serial" then | |||
r = Serial | |||
elseif access == "suite" then | |||
r = "DateTime" | |||
else | |||
for k, v in pairs( Prototypes ) do | |||
if k == access then | |||
r = Prototypes[ k ] | |||
end | |||
end -- for k, v | |||
end | |||
end | |||
return r | |||
end, | |||
__newindex = function ( self, access, assign ) | |||
if type( access ) == "string" then | |||
local data = self[ Signature ] | |||
if assign == nil then | |||
local val = data[ access ] | |||
data[ access ] = nil | |||
if not Prototypes.fair( data ) then | |||
data[ access ] = val | |||
end | |||
elseif Prototypes.fair( data, | |||
access, | |||
assign ) then | |||
data[ access ] = assign | |||
end | |||
end | |||
return | |||
end, | |||
__add = function ( op1, op2 ) | |||
return Prototypes.future( op1, op2 ) | |||
end, | |||
__eq = function ( op1, op2 ) | |||
return Prototypes.flow( op1, op2, "eq" ) | |||
end, | |||
__lt = function ( op1, op2 ) | |||
return Prototypes.flow( op1, op2, "lt" ) | |||
end, | |||
__le = function ( op1, op2 ) | |||
return Prototypes.flow( op1, op2, "le" ) | |||
end | |||
} | |||
DateTime = function ( assign, alien, add ) | |||
-- Create object (constructor) | |||
-- Parameter: | -- Parameter: | ||
-- assign -- string, with initial timestamp, or nil | -- assign -- string, with initial timestamp, or nil | ||
Zeile 138: | Zeile 196: | ||
-- false -- empty object | -- false -- empty object | ||
-- alien -- string, with language code, or nil | -- alien -- string, with language code, or nil | ||
-- add -- string, with interval (PHP strtotime), or nil | |||
-- Returns: | -- Returns: | ||
-- table, as DateTime object | -- table, as DateTime object | ||
Zeile 143: | Zeile 202: | ||
local r | local r | ||
Private.foreign() | Private.foreign() | ||
r = Private.factory( assign, alien ) | r = Private.factory( assign, alien, add ) | ||
if type( r ) == "table" then | if type( r ) == "table" then | ||
r = { [ Signature ] = r } | |||
setmetatable( r, Metatable ) | |||
r | |||
setmetatable( r, | |||
end | end | ||
return r | return r | ||
Zeile 190: | Zeile 212: | ||
Calc.months = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } | |||
-- Calc.fast = function ( at ) | |||
-- -- Quick scan of full ISO stamp | |||
-- -- Parameter: | |||
-- -- apply -- string, ISO | |||
-- -- Returns: | |||
-- -- table, with numeric components | |||
-- local r = { } | |||
-- r.year = tonumber( at:sub( 1, 4 ) ) | |||
-- r.month = tonumber( at:sub( 6, 2 ) ) | |||
-- r.dom = tonumber( at:sub( 9, 2 ) ) | |||
-- r.hour = tonumber( at:sub( 12, 2 ) ) | |||
-- r.min = tonumber( at:sub( 14, 2 ) ) | |||
-- r.sec = tonumber( at:sub( 17, 2 ) ) | |||
-- if at:sub( 19, 1 ) == "." then | |||
-- r.msec = tonumber( at:sub( 20, 3 ) ) | |||
-- if #at > 22 then | |||
-- r.mysec = tonumber( at:sub( 23, 3 ) ) | |||
-- end | |||
-- end | |||
-- return r | |||
-- end -- Calc.fast() | |||
Calc.fair = function ( adjust ) | |||
-- Normalize numeric components | |||
-- Parameter: | -- Parameter: | ||
-- | -- adjust -- table, with raw numbers | ||
-- | local order = { "mysec", "msec", "sec", "min", "hour", | ||
-- | "dom", "month", "year" } | ||
-- | local ranges = { year = { min = -999, | ||
-- add | max = 9999 }, | ||
month = { min = 1, | |||
max = 12, | |||
mod = 12 }, | |||
dom = { min = 1, | |||
max = 28 }, | |||
hour = { mod = 24 }, | |||
min = { mod = 60 }, | |||
sec = { mod = 60 }, | |||
msec = { mod = 1000 }, | |||
mysec = { mod = 1000 } } | |||
local m, max, min, move, n, range | |||
for k, v in pairs( order ) do | |||
n = adjust[ v ] | |||
if n or move then | |||
range = ranges[ v ] | |||
min = range.min or 0 | |||
max = range.max or ( range.mod - 1 ) | |||
if move then | |||
n = ( n or 0 ) + move | |||
move = false | |||
end | |||
if n < min or n > max then | |||
if range.mod then | |||
m = n % range.mod | |||
move = ( n - m ) / range.mod | |||
n = min + m | |||
else -- dom | |||
if adjust.month and adjust.year and n > 1 and | |||
adjust.month >= 1 and | |||
adjust.month <= 12 and | |||
adjust.year > 1900 then | |||
max = Calc.months[ adjust.month ] | |||
if adjust.month == 2 and | |||
( adjust.year % 4 ~= 0 or | |||
adjust.year % 400 == 0 ) then | |||
max = 28 | |||
end | |||
if n <= max then | |||
max = false | |||
end | |||
end | |||
if max then | |||
m = n % 30 | |||
move = ( n - m ) / 30 | |||
n = 1 + m | |||
end | |||
end | |||
end | |||
adjust[ v ] = n | |||
end | |||
end -- for k, v | |||
end -- Calc.fair() | |||
Calc.future = function ( add ) | |||
-- Parse move interval | |||
-- Parameter: | |||
-- add -- string, with GNU relative items | |||
-- Returns: | -- Returns: | ||
-- table, | -- table, with numeric components, or false | ||
local r, token | |||
local | local units = { year = true, | ||
month = true, | |||
fortnight = { slot = "dom", mult = 14 }, | |||
week = { slot = "dom", mult = 7 }, | |||
dom = true, | |||
hour = true, | |||
min = true, | |||
sec = true } | |||
local story = string.format( " %s ", add:lower() ) | |||
:gsub( "%s+", " " ) | |||
:gsub( " yesterday ", " -1 dom " ) | |||
:gsub( " tomorrow ", " 1 dom " ) | |||
:gsub( "(%l)s ", "%1 " ) | |||
:gsub( " day ", " dom " ) | |||
:gsub( " minute ", " min " ) | |||
:gsub( " second ", " sec " ) | |||
local feed = function () | |||
local slice | |||
token, slice = story:match( "^( (%S+)) " ) | |||
return slice | |||
end | |||
local fed = function () | |||
story = story:sub( #token + 1 ) | |||
end | |||
local m, n, s, u | |||
while true do | |||
s = feed() | |||
if s then | |||
n = 1 | |||
if s:match( "^[+-]?%d+$" ) then | |||
n = tonumber( s ) | |||
fed() | |||
s = feed() | |||
end | |||
if s then | |||
u = units[ s ] | |||
end | |||
if s and u then | |||
fed() | |||
if u ~= true then | |||
s = u.slot | |||
n = n * u.mult | |||
end | |||
if feed() == "ago" then | |||
if n > 0 then | |||
n = - n | |||
end | |||
fed() | |||
end | |||
r = r or { } | |||
r[ s ] = ( r[ s ] or 0 ) + n | |||
else | |||
r = false | |||
break -- while true | |||
end | |||
else | else | ||
break -- while true | |||
end | end | ||
end -- while true | |||
return r | |||
end -- Calc.future() | |||
Parser.digitsHeading = function ( analyse, alone, amount, add ) | |||
-- String analysis, if digits only or at least 4 digits heading | |||
-- Parameter: | |||
-- analyse -- string to be scanned, starting with digit | |||
-- digits only, else starting with exactly 4 digits | |||
-- alone -- true, if only digits | |||
-- amount -- number of heading digits | |||
-- add -- table, to be extended | |||
-- Returns: | |||
-- table, extended if parsed | |||
-- false, if invalid text format | |||
local r = add | |||
if alone then | |||
-- digits only | |||
if amount <= 4 then | |||
r.year = tonumber( analyse ) | |||
elseif n == 14 then | |||
-- timestamp | |||
r.year = tonumber( analyse:sub( 1, 4 ) ) | |||
r.month = tonumber( analyse:sub( 5, 2 ) ) | |||
r.dom = tonumber( analyse:sub( 7, 2 ) ) | |||
r.hour = tonumber( analyse:sub( 9, 2 ) ) | |||
r.min = tonumber( analyse:sub( 11, 2 ) ) | |||
r.sec = tonumber( analyse:sub( 13, 2 ) ) | |||
else | else | ||
r = false | r = false | ||
end | end | ||
elseif amount == | elseif amount == 4 then | ||
local s, sep, sx = analyse:match( "^(%d+)([%-%.:Ww]?)(.*)$" ) | |||
local s, | r.year = tonumber( s ) | ||
if sep == "-" then | |||
-- ISO | |||
s, sep, sx = sx:match( "^(%d%d)(-?)(.*)$" ) | |||
if s then | |||
r.month = tonumber( s ) | |||
r.month2 = true | |||
if sep == "-" then | |||
s, sep, sx = sx:match( "^(%d%d?)([ T]?)(.*)$" ) | |||
if s then | |||
r.dom = tonumber( s ) | |||
if sep == "T" then | |||
r.month2 = nil | |||
if | |||
s, | |||
if s = | |||
if | |||
r. | |||
else | else | ||
s = | r.dom2 = ( #s == 2 ) | ||
end | |||
if sep then | |||
r = Parser.time( sx, r, sep == "T" ) | |||
end | end | ||
else | else | ||
r = false | |||
end | end | ||
elseif sx and sx ~= "" then | |||
r = false | |||
end | end | ||
else | else | ||
r = false | |||
end | end | ||
elseif sep:lower() == "w" then | |||
if sx then | |||
s = sx:match( "^(%d%d?)$" ) | |||
if s then | |||
r.week = tonumber( s ) | |||
if r.week < 1 or r.week > 53 then | |||
r = false | |||
end | |||
else | |||
r = false | |||
end | |||
else | |||
r = false | |||
end | |||
else | |||
r = false | |||
end | |||
if r then | |||
r.iso = true | |||
end | end | ||
elseif amount == 8 then | |||
-- ISO compact | |||
local s, sz = analyse:match( "^%d+T(%d+)([.+-]?%d*%a*)$" ) | |||
if s then | if s then | ||
local n = #s | |||
if n == 2 or n == 4 or n == 6 then | |||
r.year = tonumber( analyse:sub( 1, 4 ) ) | |||
r.month = tonumber( analyse:sub( 5, 6 ) ) | |||
r.dom = tonumber( analyse:sub( 7, 8 ) ) | |||
r.hour = tonumber( analyse:sub( 10, 11 ) ) | |||
if n > 2 then | |||
r.min = tonumber( s:sub( 3, 4 ) ) | |||
if n == 6 then | |||
r.sec = tonumber( s:sub( 5, 6 ) ) | |||
end | |||
n, s = sz:match( "^(%.%d+)([+-]?[%a%d]*)$" ) | |||
if n then | |||
n = n .. "00" | |||
r.msec = tonumber( n:sub( 1, 3 ) ) | |||
if #n >= 6 then | |||
r.mysec = tonumber( n:sub( 4, 6 ) ) | |||
end | |||
sz = s | |||
end | |||
end | |||
if sz ~= "" then | |||
s, sz = sz:match( "^([+-]?)(%a*)$" ) | |||
if s == "" then | |||
if sz:match( "^(%u)$" ) then | |||
r.zone = sz | |||
else | |||
s = false | |||
end | |||
elseif #s == 1 then | |||
r.zone = s .. sz | |||
end | else | ||
return | s = false | ||
end -- Parser. | end | ||
end | |||
else | |||
s = false | |||
end | |||
end | |||
if s then | |||
r = false | |||
end | |||
end | |||
return r | |||
end -- Parser.digitsHeading() | |||
Parser. | Parser.eraGermanEnglish = function ( analyse ) | ||
-- String analysis, | -- String analysis, for German and English era | ||
-- v. Chr. v. u. Z. n. Chr. AD BC A.D. B.C. B.C.E. | |||
-- Parameter: | -- Parameter: | ||
-- analyse -- string | |||
-- analyse -- string | |||
-- Returns: | -- Returns: | ||
-- table, | -- 1 -- table, with boolean era, if any | ||
local | -- 2 -- string, with era stripped off, if any | ||
local s, | local rO = { } | ||
if | local rS = analyse | ||
local s, switch = analyse:match( "^(.+) ([vn])%. ?Chr%.$" ) | |||
if switch then | |||
rS = s | |||
rO.bc = ( switch == "v" ) | |||
elseif analyse:find( " v%. ?u%. ?Z%.$" ) then | |||
rS = analyse:match( "^(.+) v%. ?u%. ?Z%.$" ) | |||
rO.bc = true | |||
elseif analyse:find( " B%.? ?C%.? ?E?%.?$" ) then | |||
rS = analyse:match( "^(.+) B%.? ?C%.? ?E?%.?$" ) | |||
rO.bc = true | |||
elseif analyse:find( "^A%.? ?D%.? " ) then | |||
rS = analyse:match( "^A%.? ?D%.? (.*)$" ) | |||
rO.bc = false | |||
end | |||
return rO, rS | |||
end -- Parser.eraGermanEnglish() | |||
Parser.european = function ( ahead, adhere, analyse, assign ) | |||
-- String analysis, retrieve date style: DOM MONTH YEAR | |||
-- Parameter: | |||
-- ahead -- string, with first digits, not more than 2 | |||
-- adhere -- string, with first separator; not ":" | |||
-- 23 | -- analyse -- string, remainder following adhere | ||
s, sx = | -- assign -- table | ||
-- Returns: | |||
-- table, extended if parsed | |||
local r = assign | |||
local s, s2, sx | |||
if adhere == "." or adhere == ". " then | |||
-- 23.12.2013 | |||
-- 23. Dezember 2013 | |||
s, sx = analyse:match( "^(%d%d?)%.(.*)$" ) | |||
if s then | if s then | ||
r = Parser.putDate( false, s, ahead, assign ) | |||
r = Parser.yearTime( sx, r ) | |||
else | else | ||
r = false | s, sx = mw.ustring.match( analyse, | ||
"^ ?([%a&;]+%.?) ?(.*)$" ) | |||
if s then | |||
local n = Parser.monthNumber( s ) | |||
if n then | |||
r.month = n | |||
r.dom = tonumber( ahead ) | |||
r.dom2 = ( #ahead == 2 ) | |||
r = Parser.yearTime( sx, r ) | |||
else | |||
r = false | |||
end | |||
else | |||
r = false | |||
end | |||
end | end | ||
else | elseif adhere == " " then | ||
r = false | -- 23 Dec 2013 | ||
end | s, sx = mw.ustring.match( analyse, | ||
return r | "^([%a&;]+%.?) ?(.*)$" ) | ||
end -- Parser.european() | if s then | ||
local n = Parser.monthNumber( s ) | |||
if n then | |||
r.month = n | |||
r.dom = tonumber( ahead ) | |||
r.dom2 = ( #ahead == 2 ) | |||
r = Parser.yearTime( sx, r ) | |||
else | |||
r = false | |||
end | |||
else | |||
r = false | |||
end | |||
else | |||
r = false | |||
end | |||
return r | |||
end -- Parser.european() | |||
Zeile 461: | Zeile 651: | ||
rO = false | rO = false | ||
end | end | ||
if | if rO then | ||
rO.iso = true | |||
else | |||
rS = false | rS = false | ||
end | end | ||
Zeile 640: | Zeile 832: | ||
s = sx:match( "^%.(%d+)$" ) | s = sx:match( "^%.(%d+)$" ) | ||
if s then | if s then | ||
r.msec = tonumber( s ) | s = s .. "00" | ||
r.msec = tonumber( s:sub( 1, 3 ) ) | |||
if #s >= 6 then | |||
r.mysec = tonumber( s:sub( 4, 6 ) ) | |||
end | |||
else | else | ||
r = false | r = false | ||
Zeile 861: | Zeile 1.057: | ||
Private.factory = function ( assign, alien ) | Private.factory = function ( assign, alien, add ) | ||
-- Create DateTime table (constructor) | -- Create DateTime table (constructor) | ||
-- Parameter: | -- Parameter: | ||
Zeile 868: | Zeile 1.064: | ||
-- false -- empty object | -- false -- empty object | ||
-- alien -- string, with language code, or nil | -- alien -- string, with language code, or nil | ||
-- add -- string, with interval (PHP strtotime), or nil | |||
-- Returns: | -- Returns: | ||
-- table, for DateTime object | -- table, for DateTime object | ||
-- string or false, if failed | -- string or false, if failed | ||
local l = true | local l = true | ||
local slang = mw.text.trim( alien or World.slang or "en" ) | local slang = mw.text.trim( alien or World.slang or "en" ) | ||
local r | |||
if assign == false then | if assign == false then | ||
r = { } | r = { } | ||
else | else | ||
local stamp = ( assign or "now" ) | local stamp = ( assign or "now" ) | ||
local shift | |||
if add then | |||
shift = Private.future( add ) | |||
end | |||
r = false | |||
if stamp == "now" then | if stamp == "now" then | ||
stamp = | stamp = frame():callParserFunction( "#timel", "c", shift ) | ||
shift = false | |||
else | else | ||
local seconds = stamp:match( "^#(%d+)$" ) | local seconds = stamp:match( "^#(%d+)$" ) | ||
Zeile 888: | Zeile 1.090: | ||
end | end | ||
end | end | ||
l, r = pcall( Private.fetch, stamp, slang ) | l, r = pcall( Private.fetch, stamp, slang, shift ) | ||
end | end | ||
if l and type( r ) == "table" then | if l and type( r ) == "table" then | ||
Zeile 900: | Zeile 1.102: | ||
Private.fetch = function ( analyse, alien ) | Private.fetch = function ( analyse, alien, add ) | ||
-- Retrieve object from string | -- Retrieve object from string | ||
-- Parameter: | -- Parameter: | ||
-- analyse -- string to be interpreted | -- analyse -- string to be interpreted | ||
-- alien -- string with language code, or nil | -- alien -- string with language code, or nil | ||
-- add -- string, with interval (PHP strtotime), or nil | |||
-- Returns: | -- Returns: | ||
-- table, if parsed | -- table, if parsed | ||
Zeile 940: | Zeile 1.143: | ||
if not Prototypes.fair( r ) then | if not Prototypes.fair( r ) then | ||
r = false | r = false | ||
elseif add then | |||
r = Prototypes.future( r, add ) | |||
end | end | ||
end | end | ||
Zeile 954: | Zeile 1.159: | ||
Private.foreign = | Private.flow = function ( at1, at2 ) | ||
-- Retrieve localization submodule | -- Compare two objects | ||
if not World.localization then | -- Parameter: | ||
-- at1 -- DateTime | |||
-- at2 -- DateTime | |||
-- Returns: | |||
-- -1, 0, 1 or nil if not comparable | |||
local r = 0 | |||
if at1.bc or at2.bc and at1.bc ~= at2.bc then | |||
if at1.bc then | |||
r = -1 | |||
else | |||
r = 1 | |||
end | |||
else | |||
local order = { "year", "month", "week", "dom", | |||
"hour", "min", "sec", "msec", "mysec" } | |||
local life = false | |||
local s, v1, v2 | |||
for i = 1, 9 do | |||
s = order[ i ] | |||
v1 = at1[ s ] | |||
v2 = at2[ s ] | |||
if v1 or v2 then | |||
if v1 and v2 then | |||
if v1 < v2 then | |||
r = -1 | |||
elseif v1 > v2 then | |||
r = 1 | |||
end | |||
elseif life then | |||
if v2 then | |||
r = -1 | |||
else | |||
r = 1 | |||
end | |||
else | |||
r = nil | |||
end | |||
if r ~= 0 then | |||
if at1.bc and r then | |||
r = r * -1 | |||
end | |||
break -- for i | |||
end | |||
life = true | |||
end | |||
end -- for i | |||
end | |||
return r | |||
end -- Private.flow() | |||
Private.foreign = function () | |||
-- Retrieve localization submodule | |||
if not World.localization then | |||
local l, d = pcall( mw.loadData, "Module:DateTime/local" ) | local l, d = pcall( mw.loadData, "Module:DateTime/local" ) | ||
if l then | if l then | ||
Zeile 980: | Zeile 1.239: | ||
Private.future = function ( add ) | |||
-- | -- Normalize move interval | ||
-- Parameter: | -- Parameter: | ||
-- | -- add -- string or number, to be added | ||
-- Returns: | -- Returns: | ||
-- true, if valid; false, if not | -- string, with shift, or false/nil | ||
local r = ( type( self ) == "table" ) | local r | ||
if add then | |||
local s = type( add ) | |||
if s == "string" and add:match( "^%s*[+-]?%d+%.?%d*%s*$" ) then | |||
r = tonumber( add ) | |||
s = "number" | |||
else | |||
r = add | |||
end | |||
if s == "number" then | |||
if r == 0 then | |||
r = false | |||
else | |||
r = string.format( "%d second", r ) | |||
end | |||
elseif s ~= "string" then | |||
r = false | |||
end | |||
if r then | |||
r = Calc.future( r ) | |||
end | |||
end | |||
return r | |||
end -- Private.future() | |||
Prototypes.fair = function ( self, access, assign ) | |||
-- Check formal validity of table | |||
-- Parameter: | |||
-- self -- table, to be checked | |||
-- access -- string or nil, single item to be checked | |||
-- assign -- single access value to be checked | |||
-- Returns: | |||
-- true, if valid; false, if not | |||
local r = ( type( self ) == "table" ) | |||
if r then | if r then | ||
local defs = { year = { max = MaxYear }, | local defs = { year = { max = MaxYear }, | ||
month = { min = 1, | month = { min = 1, | ||
max = 12 }, | max = 12 }, | ||
week = { min = 1, | |||
max = 53 }, | |||
dom = { min = 1, | dom = { min = 1, | ||
max = 31 }, | max = 31 }, | ||
Zeile 998: | Zeile 1.292: | ||
min = { max = 59 }, | min = { max = 59 }, | ||
sec = { max = 61 }, | sec = { max = 61 }, | ||
msec = { max = | msec = { max = 999 }, | ||
mysec = { max = 999 } | |||
} | } | ||
local fNum = | local fNum = | ||
function ( k, v ) | function ( k, v ) | ||
Zeile 1.044: | Zeile 1.338: | ||
end | end | ||
if m then | if m then | ||
ret = ( d <= months[ m ] ) | ret = ( d <= Calc.months[ m ] ) | ||
if ret then | if ret then | ||
local y | local y | ||
Zeile 1.105: | Zeile 1.399: | ||
end | end | ||
else | else | ||
local order = { "bc", "year", "month", "dom", | local order = { "bc", "year", "month", "week", "dom", | ||
"hour", "min", "sec", "msec" } | "hour", "min", "sec", "msec", "mysec" } | ||
local life = false | local life = false | ||
local leak = false | local leak = false | ||
local s, v | local s, v | ||
for i = 1, | for i = 1, 10 do | ||
s = order[ i ] | s = order[ i ] | ||
v = self[ s ] | v = self[ s ] | ||
Zeile 1.121: | Zeile 1.415: | ||
if not fNum( s, v ) then | if not fNum( s, v ) then | ||
r = false | r = false | ||
break | break -- for i | ||
end | end | ||
life = true | life = true | ||
leak = true | leak = true | ||
end | end | ||
elseif i == 3 then | |||
if not self.week then | |||
life = false | |||
end | |||
elseif i ~= 4 then | |||
life = false | life = false | ||
end | end | ||
end -- for i | end -- for i | ||
if self.week and ( self.month or self.dom ) then | |||
r = false | |||
end | |||
end | end | ||
end | end | ||
Zeile 1.191: | Zeile 1.492: | ||
Prototypes.format = function ( self, ask, adapt ) | Prototypes.flow = function ( self, another, assert ) | ||
-- Format object as string | -- Compare this object with another timestamp | ||
-- Parameter: | |||
-- self -- table, with numbers etc. | |||
-- another -- DateTime or string or nil (now) | |||
-- assert -- nil, or string with operator | |||
-- "lt", "le", "eq", "ne", "ge", "gt", | |||
-- "<", "<=", "==", "~=", "<>", ">=", "=>", ">" | |||
-- Returns: | |||
-- if assert: true or false | |||
-- else: -1, 0, 1 | |||
-- nil if invalid | |||
local r | |||
if type( self ) == "table" then | |||
local d2 | |||
if type( another ) == "table" then | |||
d2 = another | |||
else | |||
d2 = DateTime( another ) | |||
end | |||
if type( d2 ) == "table" then | |||
r = Private.flow( self, d2 ) | |||
if r and type( assert ) == "string" then | |||
local trsl = { lt = "<", | |||
["<"] = "<", | |||
le = "<=", | |||
["<="] = "<=", | |||
eq = "=", | |||
["=="] = "=", | |||
ne = "<>", | |||
["<>"] = "<>", | |||
["~="] = "<>", | |||
ge = ">=", | |||
[">="] = ">=", | |||
["=>"] = ">=", | |||
gt = ">", | |||
[">"] = ">" } | |||
local same = trsl[ assert:lower() ] | |||
if same then | |||
local s = "=" | |||
if r < 0 then | |||
s = "<" | |||
elseif r > 0 then | |||
s = ">" | |||
end | |||
r = ( same:find( s, 1, true ) ~= nil ) | |||
else | |||
r = nil | |||
end | |||
end | |||
end | |||
end | |||
return r | |||
end -- Prototypes.flow() | |||
Prototypes.format = function ( self, ask, adapt ) | |||
-- Format object as string | |||
-- Parameter: | -- Parameter: | ||
-- self -- table, with numbers etc. | -- self -- table, with numbers etc. | ||
Zeile 1.198: | Zeile 1.556: | ||
-- adapt -- table, with options, or nil | -- adapt -- table, with options, or nil | ||
-- .lang -- string, with particular language code | -- .lang -- string, with particular language code | ||
-- .london -- true: UTC output; default: local | |||
-- .lonely -- true: permit lonely hour | -- .lonely -- true: permit lonely hour | ||
-- Returns: | -- Returns: | ||
Zeile 1.249: | Zeile 1.608: | ||
stamp, self.sec ) | stamp, self.sec ) | ||
if self.msec then | if self.msec then | ||
stamp = string.format( "%s.% | stamp = string.format( "%s.%03d", | ||
stamp, self.msec ) | stamp, self.msec ) | ||
if self.mysec then | |||
stamp = string.format( "%s%03d", | |||
stamp, | |||
self.mysec ) | |||
end | |||
end | end | ||
end | end | ||
Zeile 1.349: | Zeile 1.713: | ||
Prototypes.future = function ( self, add ) | |||
-- | -- Relative move by interval | ||
-- Parameter: | -- Parameter: | ||
-- | -- self -- table, to be used as base | ||
-- | -- add -- string or number, to be added | ||
-- Returns: | -- Returns: | ||
-- | -- table, with shift | ||
local r, raw, rel, shift | |||
if type( self ) == "table" then | |||
r = self | |||
shift = add | |||
elseif type( add ) == "table" then | |||
r = add | |||
shift = self | |||
end | |||
if r then | |||
raw = r[ Signature ] | |||
rel = Private.future( shift ) | |||
end | |||
if raw and rel then | |||
for k, v in pairs( rel ) do | |||
raw[ k ] = ( raw[ k ] or 0 ) + v | |||
end -- for k, v | |||
Calc.fair( raw ) | |||
end | |||
return r | |||
end -- Prototypes.future() | |||
Templates.flow = function ( frame, action ) | |||
-- Comparison invokation | |||
-- Parameter: | |||
-- frame -- object | |||
-- Returns: | |||
-- string, either "" or "1" | |||
local r | |||
local s1 = frame.args[ 1 ] | |||
local s2 = frame.args[ 2 ] | |||
if s1 then | |||
s1 = mw.text.trim( s1 ) | |||
if s1 == "" then | |||
s1 = false | |||
end | end | ||
end | |||
local | if s2 then | ||
s2 = mw.text.trim( s2 ) | |||
if s2 == "" then | |||
s2 = false | |||
end | |||
end | |||
if s1 or s2 then | |||
local l | |||
Frame = frame | |||
l, r = pcall( Prototypes.flow, | |||
DateTime( s1 ), s2, action ) | |||
if r == true then | |||
r = "1" | |||
end | |||
end | |||
return r or "" | |||
end -- Templates.flow() | |||
World.templates.formatter = function ( assigned, ask, adapt ) | |||
-- Retrieve format specification string | |||
-- Parameter: | |||
-- assigned -- table, with numbers etc. | |||
-- ask -- string, format spec, or nil | |||
-- adapt -- table, with options | |||
-- .lang -- string, with particular language code | |||
-- .lonely -- true: permit lonely hour | |||
-- Returns: | |||
-- 1 -- string | |||
-- 2 -- string or nil; append suffix (zone) | |||
local r1, r2 | |||
if not ask or ask == "" then | |||
r1 = "c" | |||
else | |||
local template = World.templates[ ask ] | |||
r1 = ask | |||
if not template then | |||
local slang = ( adapt.lang or assigned.lang or World.slang ) | |||
local tmp = World.templates[ slang ] | |||
if tmp then | |||
template = tmp[ ask ] | |||
end | |||
end | |||
if type( template ) == "table" then | |||
local low = ( ask == "ISO" or ask == "ISO-T" ) | |||
r1 = template.spec | |||
if assigned.year then | |||
if not assigned.dom then | if not assigned.dom then | ||
r1 = r1:gsub( "[ .]?[dDjlNwz][ .,%-]*", "" ) | r1 = r1:gsub( "[ .%-]?[dDjlNwz][ .,%-]*", "" ) | ||
:gsub( "^ ", "" ) | :gsub( "^ ", "" ) | ||
if not assigned.month then | |||
r1 = r1:gsub( "[ .%-]?[FmMnt][ .%-]*", "" ) | |||
end | |||
end | |||
else | |||
r1 = r1:gsub( " ?[yY] ?", "" ) | |||
if not assigned.dom then | |||
r1 = r1:gsub( "[ .]?[dDjlNwz][ .,%-]*", "" ) | |||
:gsub( "^ ", "" ) | |||
end | end | ||
end | end | ||
Zeile 1.402: | Zeile 1.831: | ||
stamp = "H:i:s" | stamp = "H:i:s" | ||
if assigned.msec then | if assigned.msec then | ||
stamp = string.format( "%s.% | stamp = string.format( "%s.%03d", | ||
stamp, | stamp, | ||
assigned.msec ) | assigned.msec ) | ||
if assigned.mysec then | |||
stamp = string.format( "%s.%03d", | |||
stamp, | |||
assigned.mysec ) | |||
end | |||
end | end | ||
end | end | ||
Zeile 1.539: | Zeile 1.973: | ||
function p.test( args ) | function p.test( args ) | ||
local slang = args[ 3 ] | |||
local obj = DateTime( args[ 1 ], slang or "de", args[ 4 ] ) | |||
local r | local r | ||
if type( obj ) == "table" then | if type( obj ) == "table" then | ||
local spec = args[ 2 ] | |||
local opt | local opt | ||
if spec then | if spec then | ||
spec = mw.text.trim( spec ) | spec = mw.text.trim( spec ) | ||
end | end | ||
if slang then | if slang then | ||
opt = { lang = mw.text.trim( slang ) } | opt = { lang = mw.text.trim( slang ) } | ||
end | end | ||
r = obj:format( spec, opt ) | r = obj:format( spec, opt ) | ||
else | else | ||
r = ( args.noerror or "0" ) | r = ( args.noerror or "0" ) | ||
if r == "0" then | if r == "0" then | ||
r = fault( "Format nicht erkannt" ) | r = fault( "Format nicht erkannt" ) | ||
else | else | ||
r = "" | r = "" | ||
end | end | ||
end | end | ||
return r | return r | ||
end -- p.test | end -- p.test | ||
function p.failsafe( frame ) | |||
local since = frame.args[ 1 ] | |||
local r | |||
if since then | |||
since = mw.text.trim( since ) | |||
if since == "" then | |||
since = false | |||
end | |||
end | |||
if since then | |||
if since > Serial then | |||
r = "" | |||
else | |||
r = Serial | |||
end | |||
else | |||
r = Serial | |||
end | |||
return r | |||
end -- p.failsafe | |||
function p.format( frame ) | |||
-- 1 -- stamp | |||
-- 2 -- spec | |||
-- 3 -- slang | |||
-- 4 -- shift | |||
local l, r | |||
local v = { frame.args[ 1 ], | |||
frame.args[ 2 ], | |||
frame.args[ 3 ], | |||
frame.args[ 4 ], | |||
noerror = frame.args.noerror } | |||
if not v[ 1 ] or v[ 1 ] == "now" then | |||
v[ 1 ] = frame:callParserFunction( "#timel", "c", v[ 4 ] ) | |||
v[ 4 ] = false | |||
end | |||
Frame = frame | |||
l, r = pcall( p.test, v ) | |||
if not l then | |||
r = fault( r ) | |||
end | |||
return r | |||
end -- p.format | |||
function p. | function p.lt( frame ) | ||
return Templates.flow( frame, "lt" ) | |||
end -- p.lt | |||
function p.le( frame ) | |||
return Templates.flow( frame, "le" ) | |||
end -- p.le | |||
function p.eq( frame ) | |||
return Templates.flow( frame, "eq" ) | |||
end -- p.eq | |||
function p.ne( frame ) | |||
return Templates.flow( frame, "ne" ) | |||
end -- p.ne | |||
function p.ge( frame ) | |||
return | return Templates.flow( frame, "ge" ) | ||
end -- p. | end -- p.ge | ||
function p.gt( frame ) | |||
return Templates.flow( frame, "gt" ) | |||
end -- p.gt | |||