395
Bearbeitungen
(update) |
K (32 Versionen importiert: Doku-Vorlage) |
||
(33 dazwischenliegende Versionen von 9 Benutzern werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
-- | local DateTime = { serial = "2020-04-08", | ||
Date and time | suite = "DateTime", | ||
item = 20652535 } | |||
-- Date and time objects | |||
local Failsafe = DateTime | |||
local GlobalMod = DateTime | |||
local Calc = { } | |||
local | local Meta = { } | ||
local Parser = { } | local Parser = { } | ||
local Private = { } | |||
local Prototypes = { } | local Prototypes = { } | ||
local Templates = { } | |||
local World = { slang = "en", | local World = { slang = "en", | ||
monthsLong = { }, | monthsLong = { }, | ||
monthsParse = { } } | monthsParse = { }, | ||
months4 = { } } | |||
local MaxYear = 2099 | |||
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.monthsAbbr = { en = { n = 3 } } | World.monthsAbbr = { en = { n = 3 } } | ||
World.monthsLong.en = { "January", | World.monthsLong.en = { "January", | ||
Zeile 41: | Zeile 47: | ||
[ "Sep" ] = 9 | [ "Sep" ] = 9 | ||
} | } | ||
World.months4.en = { [ 6 ] = true, | |||
[ 7 ] = true } | |||
World.templates = { [ "ISO" ] = | World.templates = { [ "ISO" ] = | ||
{ spec = "Y-m-d", | { spec = "Y-m-d", | ||
Zeile 47: | Zeile 55: | ||
{ spec = "c" }, | { spec = "c" }, | ||
[ "timestamp" ] = | [ "timestamp" ] = | ||
{ spec = "YmdHis" } | { spec = "YmdHis" }, | ||
[ "default" ] = | |||
{ spec = "H:i, j M Y", | |||
long = true }, | |||
[ "$dmy" ] = | |||
{ spec = "H:i, j M Y", | |||
long = true }, | |||
[ "$ymd" ] = | |||
{ spec = "H:i, Y M j", | |||
long = true }, | |||
[ "$dmyt" ] = | |||
{ spec = "j M Y, H:i", | |||
long = true }, | |||
[ "$dmyts" ] = | |||
{ spec = "j M Y, H:i:s", | |||
long = true }, | |||
[ "data-sort-type:date" ] = | |||
{ spec = "j M Y" } | |||
} | } | ||
World.templates.en = { } | World.templates.en = { } | ||
Zeile 82: | Zeile 107: | ||
HST = -1000 -- Hawaiian Standard Time | HST = -1000 -- Hawaiian Standard Time | ||
} | } | ||
local foreignModule = function ( access, advanced, append, alt, alert ) | |||
-- Fetch global module | |||
-- Precondition: | |||
-- access -- string, with name of base module | |||
-- advanced -- true, for require(); else mw.loadData() | |||
-- append -- string, with subpage part, if any; or false | |||
-- alt -- number, of wikidata item of root; or false | |||
-- alert -- true, for throwing error on data problem | |||
-- Postcondition: | |||
-- Returns whatever, probably table | |||
-- 2019-10-20 | |||
local storage = access | |||
local fun, lucky, r | |||
if advanced then | |||
fun = require | |||
else | |||
fun = mw.loadData | |||
end | |||
if append then | |||
storage = string.format( "%s/%s", storage, append ) | |||
end | |||
lucky, r = pcall( fun, "Module:" .. storage ) | |||
if not lucky then | |||
local suited | |||
GlobalMod.globalModules = GlobalMod.globalModules or { } | |||
suited = GlobalMod.globalModules[ access ] | |||
if not suited and | |||
type( alt ) == "number" and | |||
alt > 0 then | |||
suited = string.format( "Q%d", alt ) | |||
suited = mw.wikibase.getSitelink( suited ) | |||
GlobalMod.globalModules[ access ] = suited or true | |||
end | |||
if type( suited ) == "string" then | |||
storage = suited | |||
if append then | |||
storage = string.format( "%s/%s", storage, append ) | |||
end | |||
lucky, r = pcall( fun, storage ) | |||
end | |||
if not lucky and alert then | |||
error( "Missing or invalid page: " .. storage, 0 ) | |||
end | |||
end | |||
return r | |||
end -- foreignModule() | |||
Zeile 93: | Zeile 167: | ||
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 103: | Zeile 177: | ||
-- Returns: | -- Returns: | ||
-- string, HTML span | -- string, HTML span | ||
local e = mw.html.create( "span" ) | |||
:addClass( "error" ) | |||
:wikitext( a ) | |||
return tostring( e ) | |||
end -- fault() | end -- fault() | ||
DateTime = function ( assign, alien ) | local function frame() | ||
-- Create | if not Frame then | ||
Frame = mw.getCurrentFrame() | |||
end | |||
return Frame | |||
end -- frame() | |||
Meta.localized = false | |||
Meta.serial = DateTime.serial | |||
Meta.signature = "__datetime" | |||
Meta.suite = "{DateTime}" | |||
Meta.components = { lang = "string", | |||
bc = "boolean", | |||
year = "number", | |||
month = "number", | |||
week = "number", | |||
dom = "number", | |||
hour = "number", | |||
min = "number", | |||
sec = "number", | |||
msec = "number", | |||
mysec = "number", | |||
zone = false, | |||
leap = "boolean", | |||
jul = "boolean" } | |||
Meta.order = { "bc", "year", "month", "week", "dom", | |||
"hour", "min", "sec", "msec", "mysec" } | |||
Meta.tableI = { -- instance metatable | |||
__index = function ( self, access ) | |||
local r = self[ Meta.signature ][ access ] | |||
if r == nil then | |||
if access == "serial" then | |||
r = Meta.serial | |||
elseif access == "suite" then | |||
r = "DateTime" | |||
else | |||
r = Prototypes[ access ] | |||
end | |||
end | |||
return r | |||
end, | |||
__newindex = function ( self, access, assign ) | |||
if type( access ) == "string" then | |||
local data = self[ Meta.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, true ) | |||
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, | |||
__tostring = function ( e ) | |||
return Prototypes.tostring( e ) | |||
end, | |||
__call = function ( func, ... ) | |||
return Meta.fiat( ... ) | |||
end | |||
} -- Meta.tableI | |||
Meta.tableL = { -- library metatable | |||
__index = function ( self, access ) | |||
local r | |||
if access == "serial" then | |||
r = Meta.serial | |||
elseif access == "suite" then | |||
r = Meta.suite | |||
end | |||
return r | |||
end, | |||
__newindex = function () | |||
return | |||
end, | |||
__tostring = function () | |||
return Meta.suite | |||
end, | |||
__call = function ( func, ... ) | |||
return Meta.fiat( ... ) | |||
end | |||
} -- Meta.tableL | |||
Meta.fiat = function ( assign, alien, add ) | |||
-- Create instance object (constructor) | |||
-- Parameter: | -- Parameter: | ||
-- assign -- string, with initial timestamp, or nil | -- assign -- string, with initial timestamp, or nil | ||
-- nil -- now | -- nil -- now | ||
-- false -- empty object | -- false -- empty object | ||
-- table -- clone this object, or copy from raw | |||
-- ignore remaining parameters | |||
-- 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 | ||
-- string or false, if failed | -- string or false, if failed | ||
local r | local r | ||
Private.foreign() | |||
r = | if type( assign ) == "table" then | ||
if assign.suite == Meta.suite and | |||
getmetatable( assign ) == Meta.tableI then | |||
r = assign[ Meta.signature ] | |||
else | |||
r = Private.from( assign ) | |||
end | |||
else | |||
r = Private.factory( assign, alien, add ) | |||
end | |||
if type( r ) == "table" then | if type( r ) == "table" then | ||
r = { [ Meta.signature ] = r } | |||
local | setmetatable( r, Meta.tableI ) | ||
end | |||
return r | |||
end -- Meta.fiat() | |||
setmetatable( DateTime, Meta.tableL ) | |||
DateTime.serial = nil | |||
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: | |||
-- adjust -- table, with raw numbers | |||
local ranges = { year = { min = -999, | |||
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, s | |||
for i = 10, 2, -1 do | |||
s = Meta.order[ i ] | |||
n = adjust[ s ] | |||
if n or move then | |||
range = ranges[ s ] | |||
if range then | |||
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 | |||
adjust.month >= 1 and | |||
adjust.month <= 12 and | |||
adjust.year > 1900 then | |||
if n > 0 then | |||
max = Calc.final( adjust ) | |||
while n > max do | |||
n = n - max | |||
if adjust.month < 12 then | |||
adjust.month = adjust.month + 1 | |||
else | |||
adjust.month = 1 | |||
adjust.year = adjust.year + 1 | |||
end | |||
max = Calc.final( adjust ) | |||
end -- while n <= max | |||
else | |||
while n < 1 do | |||
if adjust.month == 1 then | |||
adjust.month = 12 | |||
adjust.year = adjust.year - 1 | |||
else | |||
adjust.month = adjust.month - 1 | |||
end | |||
max = Calc.final( adjust ) | |||
n = n + max | |||
end -- while n < 1 | |||
end | |||
end | |||
end | |||
end | |||
adjust[ s ] = n | |||
end | |||
end | |||
end -- for i | |||
end -- Calc.fair() | |||
Calc.final = function ( adjust ) | |||
-- Retrieve number of days in particular month | |||
-- Parameter: | |||
-- adjust -- table, with date specification | |||
-- Returns: | |||
-- number, of days in month | |||
local r = Calc.months[ adjust.month ] | |||
if adjust.month == 2 and | |||
( adjust.year % 4 ~= 0 or | |||
adjust.year % 400 == 0 ) then | |||
r = 28 | |||
end | end | ||
return r | return r | ||
end -- | end -- Calc.final() | ||
Calc.future = function ( add ) | |||
-- Parse move interval | |||
-- Parameter: | |||
-- add -- string, with GNU relative items | |||
-- Returns: | |||
-- table, with numeric components, or false | |||
local r, token | |||
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 | |||
break -- while true | |||
end | |||
end -- while true | |||
return r | |||
end -- Calc.future() | |||
Zeile 174: | Zeile 526: | ||
if amount <= 4 then | if amount <= 4 then | ||
r.year = tonumber( analyse ) | r.year = tonumber( analyse ) | ||
elseif | elseif amount == 14 then | ||
-- timestamp | -- timestamp | ||
r.year = tonumber( analyse:sub( 1, 4 ) ) | r.year = tonumber( analyse:sub( 1, 4 ) ) | ||
r.month = tonumber( analyse:sub( 5, | r.month = tonumber( analyse:sub( 5, 6 ) ) | ||
r.dom = tonumber( analyse:sub( 7, | r.dom = tonumber( analyse:sub( 7, 8 ) ) | ||
r.hour = tonumber( analyse:sub( 9, | r.hour = tonumber( analyse:sub( 9, 10 ) ) | ||
r.min = tonumber( analyse:sub( 11, | r.min = tonumber( analyse:sub( 11, 12 ) ) | ||
r.sec = tonumber( analyse:sub( 13, | r.sec = tonumber( analyse:sub( 13, 14 ) ) | ||
else | else | ||
r = false | r = false | ||
end | end | ||
elseif amount == 4 then | elseif amount == 4 then | ||
local s, sep, sx = analyse:match( "^(%d+)([%-%.: | local s, sep, sx = analyse:match( "^(%d+)([%-%.:Ww]?)(.*)$" ) | ||
r.year = tonumber( s ) | r.year = tonumber( s ) | ||
if sep == "-" then | if sep == "-" then | ||
Zeile 216: | Zeile 568: | ||
end | end | ||
elseif sep:lower() == "w" then | elseif sep:lower() == "w" then | ||
if | if sx then | ||
s = | s = sx:match( "^(%d%d?)$" ) | ||
if s then | if s then | ||
r.week = tonumber( s ) | r.week = tonumber( s ) | ||
if r.week < 1 or r.week > 53 then | |||
r = false | |||
end | |||
else | else | ||
r = false | r = false | ||
Zeile 228: | Zeile 583: | ||
else | else | ||
r = false | r = false | ||
end | |||
if r then | |||
r.iso = true | |||
end | end | ||
elseif amount == 8 then | elseif amount == 8 then | ||
Zeile 248: | Zeile 606: | ||
n = n .. "00" | n = n .. "00" | ||
r.msec = tonumber( n:sub( 1, 3 ) ) | r.msec = tonumber( n:sub( 1, 3 ) ) | ||
sz | if #n >= 6 then | ||
r.mysec = tonumber( n:sub( 4, 6 ) ) | |||
end | |||
sz = s | |||
end | end | ||
end | end | ||
Zeile 341: | Zeile 702: | ||
r = false | r = false | ||
end | end | ||
end | end | ||
elseif adhere == " " then | elseif adhere == " " then | ||
-- 23 Dec 2013 | -- 23 Dec 2013 | ||
s, sx = mw.ustring.match( analyse, | s, sx = mw.ustring.match( analyse, | ||
"^([%a&;]+%.?) (.*)$" ) | "^([%a&;]+%.?) ?(.*)$" ) | ||
if s then | if s then | ||
local n = Parser.monthNumber( s ) | local n = Parser.monthNumber( s ) | ||
Zeile 375: | Zeile 725: | ||
return r | return r | ||
end -- Parser.european() | end -- Parser.european() | ||
Parser.isoDate = function ( analyse, assign ) | |||
-- String analysis, retrieve month heading ISO date | |||
-- Parameter: | |||
-- analyse -- string, with heading hyphen | |||
-- assign -- table | |||
-- Returns: | |||
-- 1 -- table, extended if parsed | |||
-- 2 -- stripped string, or false, if invalid text format | |||
local rO, rS | |||
if analyse:match( "^%-%-?[0-9]" ) then | |||
local n, s | |||
rO = assign | |||
rS = analyse:sub( 2 ) | |||
s = rS:match( "^([012][0-9])%-" ) | |||
if s then | |||
n = tonumber( s ) | |||
if n >= 1 and n <= 12 then | |||
rO.month = n | |||
rS = rS:sub( 3 ) | |||
else | |||
rO = false | |||
end | |||
end | |||
if rO then | |||
if rS:byte( 1, 1 ) == 45 then | |||
local suffix | |||
s = rS:match( "^%-([012][0-9])" ) | |||
if s then | |||
n = tonumber( s ) | |||
if n >= 1 and n <= 31 then | |||
rO.dom = n | |||
rS = rS:sub( 4 ) | |||
else | |||
rO = false | |||
end | |||
else | |||
rS:sub( 2 ) | |||
end | |||
else | |||
rO = false | |||
end | |||
if rO then | |||
if #rS > 0 then | |||
if rO.dom then | |||
n = rS:byte( 1, 1 ) | |||
if n == 32 or n == 84 then | |||
rS = rS:sub( 2 ) | |||
else | |||
rO = false | |||
end | |||
else | |||
rO = false | |||
end | |||
end | |||
end | |||
end | |||
else | |||
rO = false | |||
end | |||
if rO then | |||
rO.iso = true | |||
else | |||
rS = false | |||
end | |||
return rO, rS | |||
end -- Parser.isoDate() | |||
Zeile 409: | Zeile 828: | ||
n = #s2 | n = #s2 | ||
if n <= 2 and #s3 == 4 then | if n <= 2 and #s3 == 4 then | ||
rO.dom = tonumber( | rO.dom = tonumber( s2 ) | ||
rO.year = tonumber( s3 ) | rO.year = tonumber( s3 ) | ||
rO.dom2 = ( n == 2 ) | rO.dom2 = ( n == 2 ) | ||
Zeile 520: | Zeile 939: | ||
if #s == 2 then | if #s == 2 then | ||
r.min = tonumber( s ) | r.min = tonumber( s ) | ||
if sx == "" then | |||
sx = false | |||
end | |||
else | else | ||
sx = false | sx = false | ||
Zeile 546: | Zeile 968: | ||
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 629: | Zeile 1.055: | ||
if s then | if s then | ||
sx = analyse:sub( 5 ) | sx = analyse:sub( 5 ) | ||
else | |||
local suffix | |||
s, sx, suffix = analyse:match( "^(%d+)([ ,]?)(.*)$" ) | |||
if s then | |||
local j = #sx | |||
n = #s | |||
if n < 4 and ( j == 1 or #suffix == 0 ) then | |||
sx = analyse:sub( n + j ) | |||
else | |||
s = false | |||
end | |||
end | |||
end | end | ||
end | end | ||
Zeile 701: | Zeile 1.139: | ||
if rO.zone then | if rO.zone then | ||
rS = s | rS = s | ||
end | end | ||
end | end | ||
Zeile 721: | Zeile 1.157: | ||
r, s = Parser.zone( s, r ) | r, s = Parser.zone( s, r ) | ||
if r then | if r then | ||
local start, sep, sx = s:match( "^(%d+)([ %-%.: | local start, sep, sx = s:match( "^(%d+)([ %-%.:WwT]?)(.*)$" ) | ||
if start then | if start then | ||
-- begins with one or more digits (ASCII) | -- begins with one or more digits (ASCII) | ||
Zeile 741: | Zeile 1.177: | ||
end | end | ||
else | else | ||
r, | local rM, sM = Parser.monthHeading( s, r ) | ||
if r and | if rM then | ||
r = Parser.time( | r = rM | ||
else | |||
r, sM = Parser.isoDate( s, r ) | |||
end | |||
if r and sM ~= "" then | |||
r = Parser.time( sM, r ) | |||
end | end | ||
end | end | ||
Zeile 752: | Zeile 1.193: | ||
Private.factory = function ( assign, alien, add ) | |||
-- Create DateTime table (constructor) | -- Create DateTime table (constructor) | ||
-- Parameter: | -- Parameter: | ||
Zeile 759: | Zeile 1.200: | ||
-- 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" ) | ||
l, r = pcall( | local shift | ||
if add then | |||
shift = Private.future( add ) | |||
end | |||
r = false | |||
if stamp == "now" then | |||
stamp = frame():callParserFunction( "#timel", "c", shift ) | |||
shift = false | |||
else | |||
local seconds = stamp:match( "^#(%d+)$" ) | |||
if seconds then | |||
stamp = os.date( "!%Y-%m-%dT%H:%M:%S", | |||
tonumber( seconds ) ) | |||
end | |||
end | |||
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 777: | Zeile 1.234: | ||
end | end | ||
return r | return r | ||
end -- Prototypes. | end -- Private.factory() | ||
Private.fetch = function ( analyse, alien, add ) | |||
-- Retrieve object from string | |||
-- Parameter: | |||
-- analyse -- string to be interpreted | |||
-- alien -- string with language code, or nil | |||
-- add -- table, with interval, or nil | |||
-- Returns: | |||
-- table, if parsed | |||
-- false, if invalid text format | |||
-- string, if serious error (args) | |||
local r | |||
if type( analyse ) == "string" then | |||
local strip = mw.ustring.char( 0x5B, 0x200E, 0x200F, 0x5D ) | |||
r = analyse:gsub( " ", " " ) | |||
:gsub( " ", " " ) | |||
:gsub( "&#x[aA]0;", " " ) | |||
:gsub( " ", " " ) | |||
:gsub( Nbsp, " " ) | |||
:gsub( Tab, " " ) | |||
:gsub( " +", " " ) | |||
:gsub( "%[%[", "" ) | |||
:gsub( "%]%]", "" ) | |||
:gsub( strip, "" ) | |||
r = mw.text.trim( r ) | |||
if r == "" then | |||
r = { } | |||
else | |||
local slang = ( alien or "" ) | |||
local parser = { en = "GermanEnglish", | |||
de = "GermanEnglish", | |||
frr = "GermanEnglish", | |||
nds = "GermanEnglish" } | |||
local suitable | |||
if slang == "" then | |||
slang = "en" | |||
else | |||
local s = slang:match( "^(%a+)%-" ) | |||
if s then | |||
slang = s | |||
end | |||
end | |||
slang = slang:lower() | |||
suitable = parser[ slang ] | |||
if suitable then | |||
local l | |||
l, r = pcall( Parser[ suitable ], r ) | |||
if l and r then | |||
if not Prototypes.fair( r ) then | |||
r = false | |||
elseif add then | |||
r = Prototypes.future( r, add ) | |||
end | |||
else | |||
r = "invalid format" | |||
end | |||
else | |||
r = "unknown language: " .. slang | |||
end | |||
end | |||
else | |||
r = "bad type" | |||
end | |||
return r | |||
end -- Private.fetch() | |||
Private.flow = function ( at1, at2 ) | |||
-- Compare two objects | |||
-- 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 life = false | |||
local s, v1, v2 | |||
for i = 2, 10 do | |||
s = Meta.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 Meta.localized then | |||
local d = foreignModule( DateTime.suite, | |||
false, | |||
"local", | |||
DateTime.item ) | |||
if type( d ) == "table" then | |||
local wk | |||
if d.slang then | |||
Meta.suite = string.format( "%s %s", | |||
Meta.suite, d.slang ) | |||
World.slang = d.slang | |||
end | |||
for k, v in pairs( d ) do | |||
wk = World[ k ] | |||
if wk and wk.en then | |||
for subk, subv in pairs( v ) do | |||
wk[ subk ] = subv | |||
end -- for k, v | |||
else | |||
World[ k ] = v | |||
end | |||
end -- for k, v | |||
end | |||
Meta.localized = true | |||
end | |||
end -- Private.foreign() | |||
Private.from = function ( attempt ) | |||
-- Create valid raw table from arbitrary table | |||
-- Parameter: | |||
-- attempt -- table, to be evaluated | |||
-- Returns: | |||
-- table, with valid components, or nil | |||
local data = { } | |||
local r | |||
for k, v in pairs( Meta.components ) do | |||
if v then | |||
v = ( type( attempt[ k ] ) == v ) | |||
else | |||
v = true | |||
end | |||
if v then | |||
data[ k ] = attempt[ k ] | |||
end | |||
end -- for k, v | |||
if Prototypes.fair( data ) then | |||
r = data | |||
end | |||
return r | |||
end -- Private.from() | |||
Private.future = function ( add ) | |||
-- Normalize move interval | |||
-- Parameter: | |||
-- add -- string or number, to be added | |||
-- Returns: | |||
-- table, with shift, or false/nil | |||
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" | |||
end | |||
if s == "number" then | |||
if r == 0 then | |||
r = false | |||
else | |||
r = string.format( "%d second", r or add ) | |||
end | |||
elseif s == "string" then | |||
r = add | |||
else | |||
r = false | |||
end | |||
if r then | |||
r = Calc.future( r ) | |||
end | |||
end | |||
return r | |||
end -- Private.future() | |||
Prototypes.clone = function ( self ) | |||
-- Clone object | |||
-- Parameter: | |||
-- self -- table, with object, to be cloned | |||
-- Returns: | |||
-- table, with object | |||
local r = { [ Meta.signature ] = self[ Meta.signature ] } | |||
setmetatable( r, Meta.tableI ) | |||
return r | |||
end -- Prototypes.clone() | |||
Prototypes.failsafe = function ( self, atleast ) | |||
-- Retrieve versioning and check for compliance | |||
-- Precondition: | |||
-- atleast -- string, with required version or "wikidata" or "~" | |||
-- or false | |||
-- Postcondition: | |||
-- Returns string -- with queried version, also if problem | |||
-- false -- if appropriate | |||
local last = ( atleast == "~" ) | |||
local since = atleast | |||
local r | |||
if last or since == "wikidata" then | |||
local item = Meta.item | |||
since = false | |||
if type( item ) == "number" and item > 0 then | |||
local entity = mw.wikibase.getEntity( string.format( "Q%d", | |||
item ) ) | |||
if type( entity ) == "table" then | |||
local seek = Failsafe.serialProperty or "P348" | |||
local vsn = entity:formatPropertyValues( seek ) | |||
if type( vsn ) == "table" and | |||
type( vsn.value ) == "string" and | |||
vsn.value ~= "" then | |||
if last and | |||
vsn.value == ( Meta.serial or DateTime.serial ) then | |||
r = false | |||
else | |||
r = vsn.value | |||
end | |||
end | |||
end | |||
end | |||
end | |||
if type( r ) == "nil" then | |||
if not since or since <= Meta.serial then | |||
r = Meta.serial | |||
else | |||
r = false | |||
end | |||
end | |||
return r | |||
end -- Prototypes.failsafe() | |||
Zeile 784: | Zeile 1.508: | ||
-- Check formal validity of table | -- Check formal validity of table | ||
-- Parameter: | -- Parameter: | ||
-- self -- table to be checked | -- self -- table, to be checked | ||
-- access -- string or nil, single item to be checked | -- access -- string or nil, single item to be checked | ||
-- assign -- single access value to be checked | -- assign -- single access value to be checked | ||
Zeile 791: | Zeile 1.515: | ||
local r = ( type( self ) == "table" ) | local r = ( type( self ) == "table" ) | ||
if r then | if r then | ||
local defs = { year = { max = | local defs = { year = { max = MaxYear }, | ||
month = { max = 12 }, | month = { min = 1, | ||
dom = { max = 31 }, | max = 12 }, | ||
week = { min = 1, | |||
max = 53 }, | |||
dom = { min = 1, | |||
max = 31 }, | |||
hour = { max = 23 }, | hour = { max = 23 }, | ||
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 805: | Zeile 1.533: | ||
local dk = defs[ k ] | local dk = defs[ k ] | ||
if dk then | if dk then | ||
if type( dk.max ) == "number" then | |||
ret = ( type( v ) == "number" ) | ret = ( type( v ) == "number" ) | ||
if ret then | if ret then | ||
ret = ( v >= | local min | ||
if dk.min then | |||
min = dk.min | |||
else | |||
min = 0 | |||
end | |||
ret = ( v >= min and v <= dk.max | |||
and math.floor( v ) == v ) | and math.floor( v ) == v ) | ||
if ret and dk.f then | if ret and dk.f then | ||
Zeile 838: | Zeile 1.571: | ||
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 847: | Zeile 1.580: | ||
end | end | ||
if d == 29 and m == 2 and y then | if d == 29 and m == 2 and y then | ||
if y % 4 ~= 0 | if y % 4 ~= 0 or | ||
( y % 100 == 0 and | |||
y % 400 ~= 0 ) then | |||
ret = false | ret = false | ||
end | end | ||
Zeile 889: | Zeile 1.624: | ||
end | end | ||
end | end | ||
elseif access == "lang" then | |||
r = ( type( assign ) == "string" ) | |||
if r then | |||
r = assign:match( "^%l%l%l?-?%a*$" ) | |||
end | |||
elseif access == "london" then | |||
r = ( type( assign ) == "boolean" ) | |||
end | end | ||
end | end | ||
else | else | ||
local life = false | |||
local leak = false | |||
local life = false | |||
local leak = false | |||
local s, v | local s, v | ||
for i = 1, | for i = 1, 10 do | ||
s = order[ i ] | s = Meta.order[ i ] | ||
v = self[ s ] | v = self[ s ] | ||
if v then | if v then | ||
Zeile 908: | Zeile 1.648: | ||
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 924: | Zeile 1.671: | ||
Prototypes. | Prototypes.figure = function ( self, assign ) | ||
-- Retrieve | -- Assign month by name | ||
-- Parameter: | |||
-- self -- table, to be filled | |||
-- assign -- string, with month name | |||
-- Returns: | |||
-- number 1...12, if valid; false, if not | |||
local r = false | |||
if type( self ) == "table" and type( assign ) == "string" then | |||
r = Parser.monthNumber( assign ) | |||
if r then | |||
self.month = r | |||
end | |||
end | |||
return r | |||
end -- Prototypes.figure() | |||
Prototypes.first = function ( self ) | |||
-- Retrieve abbreviated month name in current language | |||
-- Parameter: | -- Parameter: | ||
-- | -- self -- table, to be evaluated | ||
-- Returns: | -- Returns: | ||
-- | -- string, if defined; false, if not | ||
local r | local r | ||
if type( | if type( self ) == "table" and self.month then | ||
local slang = ( self.lang or World.slang ) | |||
r = World.monthsLong[ slang ] | |||
if r then | |||
local brief = World.monthsAbbr[ slang ] | |||
r = r[ self.month ] | |||
if brief then | |||
r = | local ex = brief[ self.month ] | ||
if r = | local s = brief.suffix | ||
r = | if ex then | ||
r = ex[ 2 ] | |||
else | |||
local n = brief.n or 3 | |||
r = mw.ustring.sub( r, 1, n ) | |||
end | |||
if s then | if s then | ||
r = r .. s | |||
end | end | ||
end | end | ||
end | end | ||
else | else | ||
r = | r = false | ||
end | end | ||
return r | return r | ||
end -- Prototypes. | end -- Prototypes.first() | ||
Prototypes.fix = function ( self ) | |||
-- Adapt this object to local time if no explicit zone given | |||
-- Parameter: | |||
-- self -- table, with numbers etc. | |||
if type( self ) == "table" and | |||
not self.zone then | |||
local seconds = Prototypes.format( self, "Z" ) | |||
Prototypes.future( self, - tonumber( seconds ) ) | |||
end | |||
end -- Prototypes.fix() | |||
Prototypes. | |||
-- | |||
Prototypes.flow = function ( self, another, assert ) | |||
-- Compare this object with another timestamp | |||
if | -- 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 | |||
end | -- nil if invalid | ||
local base, other, r | |||
if type( self ) == "table" then | |||
base = self | |||
other = another | |||
elseif type( another ) == "table" then | |||
base = another | |||
other = self | |||
end | |||
if base then | |||
if type( other ) ~= "table" then | |||
other = Meta.fiat( other ) | |||
end | |||
if type( other ) == "table" then | |||
r = Private.flow( base, other ) | |||
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 | else | ||
r = nil | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
end -- Prototypes. | return r | ||
end -- Prototypes.flow() | |||
Prototypes.format = function ( self, ask, | Prototypes.format = function ( self, ask, adapt ) | ||
-- Format object as string | -- Format object as string | ||
-- Parameter: | -- Parameter: | ||
-- self -- table, with numbers etc. | -- self -- table, with numbers etc. | ||
-- ask -- string, format spec, or nil | -- ask -- string, format spec, or nil | ||
-- | -- adapt -- table, with options, or nil | ||
-- .lang -- string, with particular language code | |||
-- .london -- true: UTC output; default: local | |||
-- .lonely -- true: permit lonely hour | |||
-- Returns: | -- Returns: | ||
-- string, or false, if invalid | -- string, or false, if invalid | ||
local r = false | local r = false | ||
if type( self ) == "table" then | if type( self ) == "table" then | ||
local slang = ( | local slang = self.lang or "en" | ||
local opts = { lang = slang } | |||
local babel | |||
if type( adapt ) == "table" then | |||
if type( adapt.lang ) == "string" then | |||
local i = adapt.lang:find( "-", 3, true ) | |||
if i then | |||
slang = adapt.lang:lower() | |||
opts.lang = slang:sub( 1, i - 1 ) | |||
else | |||
opts.lang = adapt.lang:lower() | |||
end | |||
end | |||
opts.london = adapt.london | |||
opts.lonely = adapt.lonely | |||
end | |||
babel = mw.language.new( opts.lang:lower() ) | |||
if babel then | if babel then | ||
local show | local shift, show, stamp, suffix, limit4, locally | ||
if self.month then | if self.month then | ||
stamp = World.monthsLong.en[ self.month ] | stamp = World.monthsLong.en[ self.month ] | ||
if self.year then | if self.year then | ||
stamp = string.format( "%s % | stamp = string.format( "%s %04d", stamp, self.year ) | ||
end | end | ||
if self.dom then | if self.dom then | ||
stamp = string.format( "%d %s", self.dom, stamp ) | stamp = string.format( "%d %s", self.dom, stamp ) | ||
end | |||
if ask and ask:find( "Mon4", 1, true ) then | |||
local mon4 = World.months4[ opts.lang:lower() ] | |||
if mon4 and mon4[ self.month ] then | |||
limit4 = true | |||
end | |||
end | end | ||
elseif self.year then | elseif self.year then | ||
stamp = | stamp = string.format( "%04d", self.year ) | ||
end | end | ||
if self.hour then | if self.hour then | ||
stamp = string.format( "%s %02d:", stamp, self.hour ) | if stamp then | ||
stamp = stamp .. " " | |||
else | |||
stamp = "" | |||
end | |||
stamp = string.format( "%s%02d:", stamp, self.hour ) | |||
if self.min then | if self.min then | ||
stamp = string.format( "%s%02d", stamp, self.min ) | stamp = string.format( "%s%02d", stamp, self.min ) | ||
Zeile 1.036: | Zeile 1.861: | ||
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.047: | Zeile 1.877: | ||
end | end | ||
end | end | ||
show, suffix = World.templates.formatter( self, ask, | show, suffix = World.templates.formatter( self, ask, opts ) | ||
if | if limit4 then | ||
show = show:gsub( "M", "F" ) | |||
end | |||
if type( opts.london ) == "boolean" then | |||
locally = not opts.london | |||
else | |||
locally = true | locally = true | ||
end | end | ||
r = babel:formatDate( show, stamp, locally ) | r = babel:formatDate( show, stamp, locally ) | ||
r = r:gsub( " $", "" ) | |||
if self.year and self.year < 1000 then | |||
r = r:gsub( string.format( "%04d", self.year ), | |||
tostring( self.year ) ) | |||
end | |||
if self.month then | |||
local bucket, m, suite, x | |||
if show:find( "F", 1, true ) then | |||
suite = "monthsLong" | |||
elseif show:find( "M", 1, true ) then | |||
suite = "monthsAbbr" | |||
end | |||
bucket = World[ suite ] | |||
if bucket then | |||
m = bucket[ opts.lang:lower() ] | |||
if slang then | |||
x = bucket[ slang:lower() ] | |||
end | |||
if m then | |||
local base = m[ self.month ] | |||
local ex | |||
if x then | |||
ex = x[ self.month ] | |||
end | |||
if suite == "monthsAbbr" then | |||
local stop | |||
if ex then | |||
stop = x.suffix | |||
base = ex | |||
else | |||
stop = m.suffix | |||
end | |||
if base and stop then | |||
local shift, std | |||
std = string.format( "%s%%%s", | |||
base[ 1 ], stop ) | |||
shift = string.format( "%s%s", | |||
base[ 2 ], stop ) | |||
r = mw.ustring.gsub( r, std, shift ) | |||
end | |||
elseif suite == "monthsLong" then | |||
if base and ex then | |||
r = mw.ustring.gsub( r, base, ex ) | |||
end | |||
end | |||
end | |||
end | |||
end | |||
if suffix then | if suffix then | ||
r = r .. suffix | r = r .. suffix | ||
Zeile 1.064: | Zeile 1.945: | ||
World.templates.formatter = | Prototypes.full = function ( self ) | ||
-- Retrieve month name in current language | |||
-- Parameter: | |||
-- self -- table, to be evaluated | |||
-- Returns: | |||
-- string, if defined; false, if not | |||
local r | |||
if type( self ) == "table" and self.month then | |||
local slang = ( self.lang or World.slang ) | |||
r = World.monthsLong[ slang ] | |||
if r then | |||
r = r[ self.month ] | |||
end | |||
else | |||
r = false | |||
end | |||
return r | |||
end -- Prototypes.full() | |||
Prototypes.future = function ( self, add, allocate ) | |||
-- Relative move by interval | |||
-- Parameter: | |||
-- self -- table, to be used as base | |||
-- add -- string or number, to be added | |||
-- allocate -- true, if a clone shall be returned | |||
-- 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 | |||
if r[ Meta.signature ] then | |||
raw = r[ Meta.signature ] | |||
else | |||
raw = r | |||
end | |||
if type( shift ) == "table" then | |||
rel = shift | |||
else | |||
rel = Private.future( shift ) | |||
end | |||
end | |||
if raw and rel then | |||
if allocate then | |||
r = Prototypes.clone( r ) | |||
raw = r[ Meta.signature ] | |||
end | |||
for k, v in pairs( rel ) do | |||
raw[ k ] = ( raw[ k ] or 0 ) + v | |||
end -- for k, v | |||
Calc.fair( raw ) | |||
r[ Meta.signature ] = raw | |||
end | |||
return r | |||
end -- Prototypes.future() | |||
Prototypes.tostring = function ( self ) | |||
-- Stringify yourself | |||
-- Parameter: | |||
-- self -- table, to be stringified | |||
-- Returns: | |||
-- string | |||
local dels = { false, "", "-", "-", "", "", ":", ":", ".", "" } | |||
local wids = { false, 4, 2, 2, 2, 2, 2, 2, 3, 3 } | |||
local s = "" | |||
local n, r, spec | |||
local f = function ( a ) | |||
n = self[ Meta.order[ a ] ] | |||
s = s .. dels[ a ] | |||
if n then | |||
spec = string.format( "%%s%%0%dd", wids[ a ] ) | |||
s = string.format( spec, s, n ) | |||
end | |||
end -- f() | |||
for i = 2, 5 do | |||
f( i ) | |||
end -- for i | |||
r = s | |||
s = "" | |||
for i = 6, 10 do | |||
f( i ) | |||
end -- for i | |||
if s == "::." then | |||
r = r:gsub( "%-+$", "" ) | |||
else | |||
if r == "--" then | |||
r = s | |||
else | |||
r = string.format( "%sT%s", r, s ) | |||
end | |||
end | |||
r = r:gsub( "%.$", "" ) | |||
return r | |||
end -- Prototypes.tostring() | |||
Prototypes.valueOf = function ( self ) | |||
-- Returns yourselves primitive value (primitive table) | |||
-- Parameter: | |||
-- self -- table, to be dumped | |||
-- Returns: | |||
-- table, or false | |||
local r | |||
if type( self ) == "table" then | |||
r = self[ Meta.signature ] | |||
end | |||
return r or false | |||
end -- Prototypes.valueOf() | |||
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 | |||
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, | |||
Meta.fiat( 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 | -- Retrieve format specification string | ||
-- Parameter: | -- Parameter: | ||
-- assigned -- table, with numbers etc. | -- assigned -- table, with numbers etc. | ||
-- ask -- string, format spec, or nil | -- ask -- string, format spec, or nil | ||
-- | -- adapt -- table, with options | ||
-- .lang -- string, with particular language code | |||
-- .lonely -- true: permit lonely hour | |||
-- Returns: | -- Returns: | ||
-- 1 -- string | -- 1 -- string | ||
Zeile 1.076: | Zeile 2.115: | ||
if not ask or ask == "" then | if not ask or ask == "" then | ||
r1 = "c" | r1 = "c" | ||
elseif ask == "*" then | |||
if World.present then | |||
if assigned.hour then | |||
if assigned.dom or assigned.month or assigned.year then | |||
if World.present.both and | |||
World.present.date and | |||
World.present.time then | |||
r1 = World.present.both | |||
:gsub( "$date", World.present.date ) | |||
:gsub( "$time", World.present.time ) | |||
else | |||
r1 = World.present.date | |||
end | |||
end | |||
r1 = r1 or World.present.time | |||
else | |||
r1 = World.present.date | |||
end | |||
end | |||
r1 = r1 or "c" | |||
else | else | ||
local template = World.templates[ ask ] | local template = World.templates[ ask ] | ||
r1 = ask | r1 = ask | ||
if not template then | if not template then | ||
local slang = ( | local slang = ( adapt.lang or assigned.lang or World.slang ) | ||
local tmp = World.templates[ slang ] | local tmp = World.templates[ slang ] | ||
if tmp then | if tmp then | ||
template = tmp[ ask ] | template = tmp[ ask ] | ||
end | |||
if not template then | |||
local i = slang:find( "-", 3, true ) | |||
if i then | |||
slang = slang:sub( 1, i - 1 ):lower() | |||
tmp = World.templates[ slang ] | |||
if tmp then | |||
template = tmp[ ask ] | |||
end | |||
end | |||
end | end | ||
end | end | ||
if type( template ) == "table" then | if type( template ) == "table" then | ||
local low = ( ask == "ISO" or ask == "ISO-T" ) | |||
r1 = template.spec | r1 = template.spec | ||
if assigned.year then | if assigned.year then | ||
if not assigned.dom then | if not assigned.dom then | ||
r1 = r1:gsub( "[ . | r1 = r1:gsub( "[ .%-]?[dDjlNwz][ .,%-]*", "" ) | ||
:gsub( "^ ", "" ) | :gsub( "^ ", "" ) | ||
if not assigned.month then | if not assigned.month then | ||
r1 = r1:gsub( "[ . | r1 = r1:gsub( "[ .%-]?[FmMnt][ .%-]*", "" ) | ||
end | end | ||
end | end | ||
else | else | ||
r1 = r1:gsub( " ?[yY] ?", "" ) | r1 = r1:gsub( " ?[yY] ?", "" ) | ||
if not assigned.dom then | |||
r1 = r1:gsub( "[ .]?[dDjlNwz][ .,%-]*", "" ) | |||
:gsub( "^ ", "" ) | |||
end | |||
end | end | ||
if template.lift | if template.lift and | ||
( assigned.dom or | |||
not ( assigned.month or assigned.year or assigned.bc ) | |||
) then | |||
local stamp = false | local stamp = false | ||
if assigned.hour then | |||
if | if assigned.min then | ||
stamp = "H:i" | |||
if assigned.sec then | |||
stamp = "H:i:s" | |||
if assigned.msec then | |||
stamp = string.format( "%s.%03d", | |||
stamp, | |||
assigned.msec ) | |||
if assigned.mysec then | |||
stamp = string.format( "%s.%03d", | |||
stamp, | |||
assigned.mysec ) | |||
end | |||
end | |||
end | end | ||
elseif adapt.lonely then | |||
stamp = "H" | |||
end | end | ||
end | end | ||
if low or | if low or ask:find( "hh:mm:ss", 1, true ) then | ||
if stamp then | if stamp then | ||
r1 = string.format( "%s %s", r1, stamp ) | r1 = string.format( "%s %s", r1, stamp ) | ||
Zeile 1.122: | Zeile 2.204: | ||
end | end | ||
if stamp then | if stamp then | ||
if low or template.long then | |||
if low or | |||
local scheme | local scheme | ||
if | if template.long then | ||
scheme = | scheme = mw.language.getContentLanguage() | ||
scheme = scheme.code | |||
end | end | ||
r2 = World.zones.formatter( assigned, scheme ) | r2 = World.zones.formatter( assigned, scheme ) | ||
end | end | ||
end | end | ||
end | |||
if type ( assigned.bc ) == "boolean" then | |||
local eras = World.era[ adapt.lang ] or World.era.en | |||
local i | |||
if not r2 then | |||
r2 = "" | |||
end | |||
if assigned.bc then | |||
i = 1 | |||
else | |||
i = 2 | |||
end | |||
r2 = string.format( "%s %s", r2, eras[ i ] ) | |||
end | end | ||
end | end | ||
Zeile 1.159: | Zeile 2.254: | ||
if #s == 1 then | if #s == 1 then | ||
-- "YXWVUTSRQPONZABCDEFGHIKLM" | -- "YXWVUTSRQPONZABCDEFGHIKLM" | ||
move = World.zones[ "!" ]:find( s ) | move = World.zones[ "!" ]:find( s, 1, true ) | ||
if move then | if move then | ||
move = ( move - 13 ) * 100 | move = ( move - 13 ) * 100 | ||
Zeile 1.174: | Zeile 2.269: | ||
if tmp then | if tmp then | ||
code = tmp[ s ] | code = tmp[ s ] | ||
end | |||
if not code and | |||
slang ~= "en" and | |||
World.zones.en then | |||
code = World.zones.en[ s ] | |||
end | end | ||
end | end | ||
Zeile 1.230: | Zeile 2.330: | ||
local p = { } | local p = { } | ||
function p. | function p.test( args, alien ) | ||
local | local slang = args.lang or alien | ||
local | local obj = Meta.fiat( args[ 1 ], false, args.shift ) | ||
local r | |||
if type( obj ) == "table" then | |||
local spec = args[ 2 ] | |||
local opt | |||
if spec then | |||
spec = mw.text.trim( spec ) | |||
end | |||
if slang then | |||
opt = { lang = mw.text.trim( slang ) } | |||
end | |||
r = obj:format( spec, opt ) | |||
else | |||
r = ( args.noerror or "0" ) | |||
if r == "0" then | |||
r = fault( "Format invalid" ) | |||
else | else | ||
r = "" | |||
end | |||
end | |||
return r | |||
end -- p.test | |||
function p.failsafe( frame ) | |||
local s = type( frame ) | |||
local r, since | |||
if s == "table" then | |||
since = frame.args[ 1 ] | |||
elseif s == "string" then | |||
since = mw.text.trim( since ) | |||
if since == "" then | |||
since = false | |||
end | end | ||
end | |||
r = | return Prototypes.failsafe( false, since ) or "" | ||
end -- p.failsafe | |||
function p.format( frame ) | |||
-- 1 -- stamp | |||
-- 2 -- spec | |||
-- lang | |||
-- shift | |||
-- noerror | |||
local l, r | |||
local v = { frame.args[ 1 ], | |||
frame.args[ 2 ], | |||
shift = frame.args.shift, | |||
noerror = frame.args.noerror } | |||
if not v[ 1 ] or v[ 1 ] == "now" then | |||
v[ 1 ] = frame:callParserFunction( "#timel", "c", v.shift ) | |||
v.shift = false | |||
end | |||
Frame = frame | |||
l, r = pcall( p.test, v, frame.args[ 3 ] or frame.args.lang ) | |||
if not l then | |||
r = fault( r ) | |||
end | end | ||
return r | return r | ||
end -- format | end -- p.format | ||
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 Templates.flow( frame, "ge" ) | |||
end -- p.ge | |||
function p.gt( frame ) | |||
return Templates.flow( frame, "gt" ) | |||
end -- p.gt | |||
p.DateTime = function ( | p.DateTime = function () | ||
return DateTime | return DateTime | ||
end -- p.DateTime | end -- p.DateTime | ||
return p | return p |