Bearbeiten von „Modul:DateTime“
Zur Navigation springen
Zur Suche springen
Die Bearbeitung kann rückgängig gemacht werden. Bitte prüfe den Vergleich unten, um sicherzustellen, dass du dies tun möchtest, und veröffentliche dann unten deine Änderungen, um die Bearbeitung rückgängig zu machen.
Aktuelle Version | Dein Text | ||
Zeile 1: | Zeile 1: | ||
--[=[ 2014-01-31 | |||
Date and time utilities | |||
]=] | |||
-- Date and time | |||
local | -- local globals | ||
local | local DateTime | ||
local Parser = { } | local Parser = { } | ||
local Prototypes = { } | local Prototypes = { } | ||
local World = { slang = "en", | local World = { slang = "en", | ||
monthsLong = { }, | monthsLong = { }, | ||
monthsParse = { } | monthsParse = { } } | ||
local Nbsp = mw.ustring.char( 160 ) | local Nbsp = mw.ustring.char( 160 ) | ||
local Tab = mw.ustring.char( 9 ) | local Tab = mw.ustring.char( 9 ) | ||
World.era = { en = { "BC", "AD" } } | World.era = { en = { "BC", "AD" } } | ||
World.monthsAbbr = { en = { n = 3 } } | World.monthsAbbr = { en = { n = 3 } } | ||
Zeile 47: | Zeile 42: | ||
[ "Sep" ] = 9 | [ "Sep" ] = 9 | ||
} | } | ||
World.templates = { [ "ISO" ] = | World.templates = { [ "ISO" ] = | ||
{ spec = "Y-m-d", | { spec = "Y-m-d", | ||
Zeile 55: | Zeile 48: | ||
{ spec = "c" }, | { spec = "c" }, | ||
[ "timestamp" ] = | [ "timestamp" ] = | ||
{ spec = "YmdHis | { spec = "YmdHis" } | ||
} | } | ||
World.templates.en = { } | World.templates.en = { } | ||
Zeile 107: | Zeile 83: | ||
HST = -1000 -- Hawaiian Standard Time | HST = -1000 -- Hawaiian Standard Time | ||
} | } | ||
Zeile 167: | Zeile 94: | ||
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 -- fault() | ||
Zeile 177: | Zeile 104: | ||
-- Returns: | -- Returns: | ||
-- string, HTML span | -- string, HTML span | ||
return string.format( "<span class=\"error\">%s</span>", a ) | |||
end -- fault() | end -- fault() | ||
DateTime = function ( assign, alien ) | |||
-- Create metatable (constructor) | |||
-- Create | |||
-- 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 | ||
-- alien -- string, with language code, or nil | -- alien -- string, with language code, 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 | ||
Prototypes.foreign() | |||
r = Prototypes.factory( assign, alien ) | |||
if type( r ) == "table" then | if type( r ) == "table" then | ||
r = { [ | local meta = { } | ||
setmetatable( r, | local s = "__datetime" | ||
meta.__index = function( self, access ) | |||
return self[ s ][ access ] | |||
end | |||
meta.__newindex = function( self, access, assign ) | |||
if type( access ) == "string" then | |||
local data = self[ s ] | |||
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 | |||
r = { [ s ] = r } | |||
r.fair = function ( self, ... ) | |||
return Prototypes.fair( self, ... ) | |||
end | |||
r.format = function ( ... ) | |||
return Prototypes.format( r[ s ], ... ) | |||
end | |||
setmetatable( r, meta ) | |||
end | end | ||
return r | return r | ||
end -- | end -- DateTime() | ||
Zeile 526: | Zeile 175: | ||
if amount <= 4 then | if amount <= 4 then | ||
r.year = tonumber( analyse ) | r.year = tonumber( analyse ) | ||
elseif | elseif n == 14 then | ||
-- timestamp | -- timestamp | ||
r.year = tonumber( analyse:sub( 1, | r.year = tonumber( analyse:sub( 1, 4 ) ) | ||
r.month = tonumber( analyse:sub( 5, | r.month = tonumber( analyse:sub( 5, 2 ) ) | ||
r.dom = tonumber( analyse:sub( 7, | r.dom = tonumber( analyse:sub( 7, 2 ) ) | ||
r.hour = tonumber( analyse:sub( 9, | r.hour = tonumber( analyse:sub( 9, 2 ) ) | ||
r.min = tonumber( analyse:sub( 11, | r.min = tonumber( analyse:sub( 11, 2 ) ) | ||
r.sec = tonumber( analyse:sub( 13, | r.sec = tonumber( analyse:sub( 13, 2 ) ) | ||
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+)([%-%.:w]?)(.*)$" ) | ||
r.year = tonumber( s ) | r.year = tonumber( s ) | ||
if sep == "-" then | if sep == "-" then | ||
Zeile 568: | Zeile 217: | ||
end | end | ||
elseif sep:lower() == "w" then | elseif sep:lower() == "w" then | ||
if | if s then | ||
s = | s = s:match( "^(%d%d?)$" ) | ||
if s then | if s then | ||
r.week = tonumber( s ) | r.week = tonumber( s ) | ||
else | else | ||
r = false | r = false | ||
Zeile 583: | Zeile 229: | ||
else | else | ||
r = false | r = false | ||
end | end | ||
elseif amount == 8 then | elseif amount == 8 then | ||
Zeile 606: | Zeile 249: | ||
n = n .. "00" | n = n .. "00" | ||
r.msec = tonumber( n:sub( 1, 3 ) ) | r.msec = tonumber( n:sub( 1, 3 ) ) | ||
sz = s | |||
sz = s | |||
end | end | ||
end | end | ||
Zeile 706: | Zeile 346: | ||
-- 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 725: | Zeile 365: | ||
return r | return r | ||
end -- Parser.european() | end -- Parser.european() | ||
Zeile 828: | Zeile 399: | ||
n = #s2 | n = #s2 | ||
if n <= 2 and #s3 == 4 then | if n <= 2 and #s3 == 4 then | ||
rO.dom = tonumber( | rO.dom = tonumber( n ) | ||
rO.year = tonumber( s3 ) | rO.year = tonumber( s3 ) | ||
rO.dom2 = ( n == 2 ) | rO.dom2 = ( n == 2 ) | ||
Zeile 939: | Zeile 510: | ||
if #s == 2 then | if #s == 2 then | ||
r.min = tonumber( s ) | r.min = tonumber( s ) | ||
else | else | ||
sx = false | sx = false | ||
Zeile 968: | Zeile 536: | ||
s = sx:match( "^%.(%d+)$" ) | s = sx:match( "^%.(%d+)$" ) | ||
if s then | if s then | ||
r.msec = tonumber( s ) | |||
r.msec = tonumber( s | |||
else | else | ||
r = false | r = false | ||
Zeile 1.055: | Zeile 619: | ||
if s then | if s then | ||
sx = analyse:sub( 5 ) | sx = analyse:sub( 5 ) | ||
end | end | ||
end | end | ||
Zeile 1.139: | Zeile 691: | ||
if rO.zone then | if rO.zone then | ||
rS = s | rS = s | ||
else | |||
rO = false | |||
end | end | ||
end | end | ||
Zeile 1.177: | Zeile 731: | ||
end | end | ||
else | else | ||
r, s = Parser.monthHeading( s, r ) | |||
if | if r and s ~= "" then | ||
r = Parser.time( s, r ) | |||
r = Parser.time( | |||
end | end | ||
end | end | ||
Zeile 1.193: | Zeile 742: | ||
Prototypes.factory = function ( assign, alien ) | |||
-- Create DateTime table (constructor) | -- Create DateTime table (constructor) | ||
-- Parameter: | -- Parameter: | ||
Zeile 1.200: | Zeile 749: | ||
-- false -- empty object | -- false -- empty object | ||
-- alien -- string, with language code, or nil | -- alien -- string, with language code, 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 r = false | |||
local slang = mw.text.trim( alien or World.slang or "en" ) | local slang = mw.text.trim( alien or World.slang or "en" ) | ||
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( Prototypes.fetch, stamp, slang ) | |||
l, r = pcall( | |||
end | end | ||
if l and type( r ) == "table" then | if l and type( r ) == "table" then | ||
Zeile 1.234: | Zeile 767: | ||
end | end | ||
return r | return r | ||
end -- | end -- Prototypes.factory() | ||
Zeile 1.508: | Zeile 774: | ||
-- Check formal validity of table | -- Check formal validity of table | ||
-- Parameter: | -- Parameter: | ||
-- self -- table | -- 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 1.515: | Zeile 781: | ||
local r = ( type( self ) == "table" ) | local r = ( type( self ) == "table" ) | ||
if r then | if r then | ||
local defs = { year = { max = | local defs = { year = { max = 2099 }, | ||
month = { | month = { max = 12 }, | ||
dom = { max = 31 }, | |||
dom = { | |||
hour = { max = 23 }, | hour = { max = 23 }, | ||
min = { max = 59 }, | min = { max = 59 }, | ||
sec = { max = 61 }, | sec = { max = 61 }, | ||
msec = { max = | msec = { max = 1000 } | ||
} | } | ||
local months = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } | |||
local fNum = | local fNum = | ||
function ( k, v ) | function ( k, v ) | ||
Zeile 1.533: | Zeile 795: | ||
local dk = defs[ k ] | local dk = defs[ k ] | ||
if dk then | if dk then | ||
if type( | local mx = dk.max | ||
if type( mx ) == "number" then | |||
ret = ( type( v ) == "number" ) | ret = ( type( v ) == "number" ) | ||
if ret then | if ret then | ||
ret = ( v >= 0 and v <= mx | |||
ret = ( v >= | |||
and math.floor( v ) == v ) | and math.floor( v ) == v ) | ||
if ret and dk.f then | if ret and dk.f then | ||
Zeile 1.571: | Zeile 828: | ||
end | end | ||
if m then | if m then | ||
ret = ( d <= | ret = ( d <= months[ m ] ) | ||
if ret then | if ret then | ||
local y | local y | ||
Zeile 1.580: | Zeile 837: | ||
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 % 400 == 0 then | ||
ret = false | ret = false | ||
end | end | ||
Zeile 1.624: | Zeile 879: | ||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
else | else | ||
local life | local order = { "bc", "year", "month", "dom", | ||
local leak | "hour", "min", "sec", "msec" } | ||
local life = false | |||
local leak = false | |||
local s, v | local s, v | ||
for i = 1, | for i = 1, 8 do | ||
s = | s = order[ i ] | ||
v = self[ s ] | v = self[ s ] | ||
if v then | if v then | ||
Zeile 1.648: | Zeile 898: | ||
if not fNum( s, v ) then | if not fNum( s, v ) then | ||
r = false | r = false | ||
break | break | ||
end | end | ||
life = true | life = true | ||
leak = true | leak = true | ||
end | end | ||
else | |||
life = false | life = false | ||
end | end | ||
end -- for i | end -- for i | ||
end | end | ||
end | end | ||
Zeile 1.671: | Zeile 914: | ||
Prototypes. | Prototypes.fetch = function ( analyse, alien ) | ||
-- | -- Retrieve object from string | ||
-- Parameter: | -- Parameter: | ||
-- | -- analyse -- string to be interpreted | ||
-- | -- alien -- string with language code, or nil | ||
-- Returns: | -- Returns: | ||
-- | -- table, if parsed | ||
-- false, if invalid text format | |||
-- string, if serious error (args) | |||
-- | |||
-- string, if | |||
local r | local r | ||
if type( | if type( analyse ) == "string" then | ||
r = analyse:gsub( " ", " " ) | |||
r = | :gsub( " ", " " ) | ||
if r then | :gsub( " ", " " ) | ||
:gsub( Nbsp, " " ) | |||
:gsub( Tab, " " ) | |||
if | :gsub( " +", " " ) | ||
r = mw.text.trim( r ) | |||
local s | if r == "" or slang == "now" then | ||
if | r = { } | ||
else | |||
local slang = ( alien or "" ) | |||
if slang == "" then | |||
slang = "en" | |||
else | |||
local s = slang:match( "^(%a+)%-" ) | |||
if s then | |||
slang = s | |||
end | end | ||
if | end | ||
r = | slang = slang:lower() | ||
if slang == "en" or slang == "de" then | |||
local l | |||
l, r = pcall( Parser.GermanEnglish, r ) | |||
if l and r then | |||
if not Prototypes.fair( r ) then | |||
r = false | |||
end | |||
end | end | ||
else | |||
r = "unknown language" | |||
end | end | ||
end | end | ||
else | else | ||
r = | r = "bad type" | ||
end | end | ||
return r | return r | ||
end -- Prototypes. | end -- Prototypes.fetch() | ||
Prototypes. | Prototypes.foreign = function () | ||
-- | -- Retrieve localization submodule | ||
if not World.localization then | |||
local l, d = pcall( mw.loadData, "Module:DateTime/local" ) | |||
if | if l then | ||
if d.slang then | |||
local | World.slang = d.slang | ||
end | |||
for k, v in pairs( d ) do | |||
if World[ k ].en then | |||
local part = World[ k ] | |||
for subk, subv in pairs( v ) do | |||
part[ subk ] = subv | |||
end -- for k, v | |||
end | |||
else | else | ||
World[ k ] = v | |||
end | end | ||
end | end -- for k, v | ||
end | end | ||
World.localization = true | |||
end | end | ||
end -- Prototypes.foreign() | |||
end -- Prototypes. | |||
Prototypes.format = function ( self, ask, | Prototypes.format = function ( self, ask, alien ) | ||
-- 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 | ||
-- | -- alien -- string, with language code, or nil | ||
-- 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 = self.lang | local slang = ( alien or self.lang ) | ||
local babel = mw.language.new( slang ) | |||
local | |||
if babel then | if babel then | ||
local | local show | ||
local stamp | |||
local suffix | |||
local locally | |||
if self.month then | if self.month then | ||
stamp = World.monthsLong.en[ self.month ] | stamp = World.monthsLong.en[ self.month ] | ||
Zeile 1.838: | Zeile 1.014: | ||
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 | end | ||
elseif self.year then | elseif self.year then | ||
Zeile 1.849: | Zeile 1.019: | ||
end | end | ||
if self.hour then | if self.hour then | ||
stamp = string.format( "%s %02d:", stamp, self.hour ) | |||
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.861: | Zeile 1.026: | ||
stamp, self.sec ) | stamp, self.sec ) | ||
if self.msec then | if self.msec then | ||
stamp = string.format( "%s.% | stamp = string.format( "%s.%d", | ||
stamp, self.msec ) | stamp, self.msec ) | ||
end | end | ||
end | end | ||
Zeile 1.877: | Zeile 1.037: | ||
end | end | ||
end | end | ||
show, suffix = World.templates.formatter( self, ask, | show, suffix = World.templates.formatter( self, ask, alien ) | ||
if | if self.locally or alien then | ||
locally = true | |||
locally = | |||
else | else | ||
locally = | locally = false | ||
end | end | ||
r = babel:formatDate( show, stamp, locally ) | r = babel:formatDate( show, stamp, locally ) | ||
if self.year and self.year < 1000 then | if self.year and self.year < 1000 then | ||
r = r:gsub( string.format( "%04d", self.year ), | r = r:gsub( string.format( "%04d", self.year ), | ||
tostring( self.year ) ) | tostring( self.year ) ) | ||
end | end | ||
if suffix then | if suffix then | ||
Zeile 1.945: | Zeile 1.058: | ||
World.templates.formatter = function ( assigned, ask, alien ) | |||
World.templates.formatter = function ( assigned, ask, | |||
-- 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 | ||
-- | -- alien -- string, with language code, or nil | ||
-- Returns: | -- Returns: | ||
-- 1 -- string | -- 1 -- string | ||
Zeile 2.115: | Zeile 1.070: | ||
if not ask or ask == "" then | if not ask or ask == "" then | ||
r1 = "c" | r1 = "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 = ( alien 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 | end | ||
end | end | ||
if type( template ) == "table" then | if type( template ) == "table" then | ||
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( "[ .]?[jJ][ .,%-]*", "" ) | ||
:gsub( "^ ", "" ) | :gsub( "^ ", "" ) | ||
if not assigned.month then | if not assigned.month then | ||
r1 = r1:gsub( "[ .%-]?[ | r1 = r1:gsub( "[ .%-]?[fFmM][ .%-]*", "" ) | ||
end | end | ||
end | end | ||
Zeile 2.169: | Zeile 1.093: | ||
r1 = r1:gsub( " ?[yY] ?", "" ) | r1 = r1:gsub( " ?[yY] ?", "" ) | ||
if not assigned.dom then | if not assigned.dom then | ||
r1 = r1:gsub( "[ .]?[ | r1 = r1:gsub( "[ .]?[jJ][ .,%-]*", "" ) | ||
:gsub( "^ ", "" ) | :gsub( "^ ", "" ) | ||
end | end | ||
end | end | ||
if template.lift | if template.lift then | ||
local spec = "T. Monat JJJJ hh:mm:ss Zone" | |||
local stamp = false | local stamp = false | ||
if | local low = ( ask == "ISO" or ask == "ISO-T" ) | ||
if assigned.min then | if ask ~= spec then | ||
spec = false | |||
end | |||
if assigned.hour and assigned.min then | |||
stamp = "H:i" | |||
if assigned.sec then | |||
stamp = "H:i:s" | |||
if assigned.msec then | |||
stamp = string.format( "%s.%d", | |||
stamp, assigned.msec ) | |||
end | end | ||
end | end | ||
end | end | ||
if low or | if low or spec then | ||
if stamp then | if stamp then | ||
r1 = string.format( "%s %s", r1, stamp ) | r1 = string.format( "%s %s", r1, stamp ) | ||
Zeile 2.204: | Zeile 1.120: | ||
end | end | ||
if stamp then | if stamp then | ||
if low or | local dewiki = ( ask == "dewiki" or spec ) | ||
if low or dewiki then | |||
local scheme | local scheme | ||
if | if dewiki then | ||
scheme = | scheme = "de" | ||
end | end | ||
r2 = World.zones.formatter( assigned, scheme ) | r2 = World.zones.formatter( assigned, scheme ) | ||
Zeile 2.215: | Zeile 1.131: | ||
end | end | ||
if type ( assigned.bc ) == "boolean" then | if type ( assigned.bc ) == "boolean" then | ||
local eras = World.era[ | local eras = World.era[ alien ] or World.era.en | ||
local i | local i | ||
if not r2 then | if not r2 then | ||
Zeile 2.254: | Zeile 1.170: | ||
if #s == 1 then | if #s == 1 then | ||
-- "YXWVUTSRQPONZABCDEFGHIKLM" | -- "YXWVUTSRQPONZABCDEFGHIKLM" | ||
move = World.zones[ "!" ]:find( s | move = World.zones[ "!" ]:find( s ) | ||
if move then | if move then | ||
move = ( move - 13 ) * 100 | move = ( move - 13 ) * 100 | ||
Zeile 2.269: | Zeile 1.185: | ||
if tmp then | if tmp then | ||
code = tmp[ s ] | code = tmp[ s ] | ||
end | end | ||
end | end | ||
Zeile 2.330: | Zeile 1.241: | ||
local p = { } | local p = { } | ||
function p. | function p.format( frame ) | ||
local | local r = ( frame.args[ 1 ] or "" ) | ||
local | local l, o = pcall( DateTime, r, "de" ) | ||
if l then | |||
if type( o ) == "table" then | |||
l, r = pcall( o, | |||
format, | |||
frame.args[ 2 ], | |||
frame.args[ 3 ] ) | |||
else | |||
l = ( frame.args.noerror or "0" ) | |||
if l == "0" then | |||
r = fault( "Format nicht erkannt" ) | |||
else | |||
r = "" | |||
end | |||
end | end | ||
else | else | ||
r = | r = o | ||
end | end | ||
return r | return r | ||
end -- | end -- format | ||
p.DateTime = function () | p.DateTime = function ( ... ) | ||
return DateTime | return DateTime( ... ) | ||
end -- p.DateTime | end -- p.DateTime | ||
return p | return p |