Modul:DateTime: Unterschied zwischen den Versionen

28.095 Bytes hinzugefügt ,  3. Juli 2020
K
32 Versionen importiert: Doku-Vorlage
(update)
K (32 Versionen importiert: Doku-Vorlage)
 
(19 dazwischenliegende Versionen von 8 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
--[=[ 2014-11-10
local DateTime  = { serial = "2020-04-08",
Date and time utilities
                    suite  = "DateTime",
]=]
                    item  = 20652535 }
 
-- Date and time objects
 
local Failsafe  = DateTime
 
local GlobalMod  = DateTime
-- local globals
local Calc      = { }
local DateTime
local Meta      = { }
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 18:
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 105: 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 116: 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 -- fault()
end -- capitalize()




Zeile 126: Zeile 177:
     -- Returns:
     -- Returns:
     --    string, HTML span
     --    string, HTML span
     return string.format( "<span class=\"error\">%s</span>", a )
     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 metatable (constructor)
    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
Zeile 143: Zeile 299:
     local r
     local r
     Private.foreign()
     Private.foreign()
     r = Private.factory( assign, alien )
     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
         local meta = { }
         r = { [ Meta.signature ] = r }
        local s    = "__datetime"
         setmetatable( r, Meta.tableI )
        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 ( ... )
                              return Prototypes.fair( ... )
                          end
        r.figure        = function ( ... )
                              return Prototypes.figure( ... )
                          end
        r.first        = function ( ... )
                              return Prototypes.first( ... )
                          end
        r.format        = function ( ... )
                              return Prototypes.format( ... )
                          end
        r.full          = function ( ... )
                              return Prototypes.full( ... )
                          end
         setmetatable( r, meta )
     end
     end
     return r
     return r
end -- DateTime()
end -- Meta.fiat()
setmetatable( DateTime, Meta.tableL )
DateTime.serial = nil
 




Calc.months = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }


Parser.digitsHeading = function ( analyse, alone, amount, add )
 
     -- String analysis, if digits only or at least 4 digits heading
 
--  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:
     -- Parameter:
     --    analyse  -- string to be scanned, starting with digit
     --    adjust   -- table, with date specification
    --                digits only, else starting with exactly 4 digits
    --    alone    -- true, if only digits
    --    amount   -- number of heading digits
    --    add      -- table, to be extended
     -- Returns:
     -- Returns:
     --    table, extended if parsed
     --    number, of days in month
    --    false, if invalid text format
     local r = Calc.months[ adjust.month ]
     local r = add
     if adjust.month == 2  and
     if alone then
      ( adjust.year % 4 ~= 0  or
         -- digits only
        adjust.year % 400 == 0 ) then
        if amount <= 4 then
         r = 28
            r.year = tonumber( analyse )
    end
        elseif n == 14 then
    return r
            -- timestamp
end -- Calc.final()
            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 ) )
Calc.future = function ( add )
            r.min    = tonumber( analyse:sub( 11, 2 ) )
    -- Parse move interval
             r.sec    = tonumber( analyse:sub( 13, 2 ) )
    -- 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
         else
             r = false
             break    -- while true
         end
         end
     elseif amount == 4 then
    end    -- while true
         local s, sep, sx = analyse:match( "^(%d+)([%-%.:w]?)(.*)$" )
    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 amount == 14 then
            -- timestamp
            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(  9, 10 ) )
            r.min    = tonumber( analyse:sub( 11, 12 ) )
            r.sec    = tonumber( analyse:sub( 13, 14 ) )
        else
            r = false
        end
     elseif amount == 4 then
         local s, sep, sx = analyse:match( "^(%d+)([%-%.:Ww]?)(.*)$" )
         r.year = tonumber( s )
         r.year = tonumber( s )
         if sep == "-" then
         if sep == "-" then
Zeile 248: Zeile 568:
             end
             end
         elseif sep:lower() == "w" then
         elseif sep:lower() == "w" then
             if s then
             if sx then
                 s = s:match( "^(%d%d?)$" )
                 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 260: 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 280: Zeile 606:
                         n      = n .. "00"
                         n      = n .. "00"
                         r.msec = tonumber( n:sub( 1, 3 ) )
                         r.msec = tonumber( n:sub( 1, 3 ) )
                         sz     = s
                        if #n >= 6 then
                            r.mysec = tonumber( n:sub( 4, 6 ) )
                        end
                         sz = s
                     end
                     end
                 end
                 end
Zeile 399: Zeile 728:




Parser.monthHeading = function ( analyse, assign )
Parser.isoDate = function ( analyse, assign )
     -- String analysis, retrieve month heading date (US only)
     -- String analysis, retrieve month heading ISO date
     -- Parameter:
     -- Parameter:
     --    analyse  -- string, with heading word
     --    analyse  -- string, with heading hyphen
     --    assign  -- table
     --    assign  -- table
     -- Returns:
     -- Returns:
     --    1  -- table, extended if parsed
     --    1  -- table, extended if parsed
     --    2  -- stripped string, or false, if invalid text format
     --    2  -- stripped string, or false, if invalid text format
     local rO = assign
     local rO, rS
    local rS = analyse
    if analyse:match( "^%-%-?[0-9]" ) then
    local s, sep = mw.ustring.match( analyse, "^([%a&;]+%.?)([^%a%.]?)" )
        local n, s
    if s then
        rO = assign
        -- might begin with month name  "December 23, 2013"
        rS = analyse:sub( 2 )
        local n = Parser.monthNumber( s )
        s = rS:match( "^([012][0-9])%-" )
        if n then
        if s then
            rO.month = n
            n = tonumber( s )
            if sep == "" then
            if n >= 1  and  n <= 12 then
                 rS = ""
                rO.month = n
                 rS       = rS:sub( 3 )
             else
             else
                 local s2, s3
                 rO = false
                n = mw.ustring.len( s ) +  1
            end
                 s = mw.ustring.sub( analyse, n )
        end
                 s2 = s:match( "^ (%d%d%d?%d?)$" )
        if rO then
                 if s2 then
            if rS:byte( 1, 1 ) == 45 then
                     rO.year = tonumber( s2 )
                 local suffix
                     rS = ""
                 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
                 else
                     s2, s3, rS = s:match( "^ (%d+), (%d+)( ?.*)$" )
                     rS:sub( 2 )
                     if s2 and s3 then
                end
                         n = #s2
            else
                         if n <= 2 and #s3 == 4 then
                rO = false
                             rO.dom  = tonumber( n )
            end
                            rO.year = tonumber( s3 )
            if rO then
                            rO.dom2 = ( n == 2 )
                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
                         else
                             rO = false
                             rO = false
Zeile 441: Zeile 783:
                 end
                 end
             end
             end
        else
            rO = false
         end
         end
     else
     else
         rO = false
         rO = false
     end
     end
     if not rO then
     if rO then
        rO.iso = true
    else
         rS = false
         rS = false
     end
     end
     return rO, rS
     return rO, rS
end -- Parser.monthHeading()
end -- Parser.isoDate()






Parser.monthNumber = function ( analyse )
Parser.monthHeading = function ( analyse, assign )
     -- String analysis, retrieve month number
     -- String analysis, retrieve month heading date (US only)
     -- Parameter:
     -- Parameter:
     --    analyse  -- string, with month name including any period
     --    analyse  -- string, with heading word
    --    assign  -- table
     -- Returns:
     -- Returns:
     --    number, 1...12 if found
     --    1  -- table, extended if parsed
     --    false or nil, if not detected
     --    2  -- stripped string, or false, if invalid text format
     local r = false
     local rO = assign
     local s = mw.ustring.match( analyse, "^([%a&;]+)%.?$" )
    local rS = analyse
     local s, sep = mw.ustring.match( analyse, "^([%a&;]+%.?)([^%a%.]?)" )
     if s then
     if s then
         local given
         -- might begin with month name  "December 23, 2013"
         s = capitalize( s )
         local n = Parser.monthNumber( s )
         for k, v in pairs( World.monthsLong ) do
         if n then
             given = World.monthsParse[ k ]
             rO.month = n
             if given then
             if sep == "" then
                 r = given[ s ]
                 rS = ""
            end
            else
            if not r then
                local s2, s3
                given = World.monthsLong[ k ]
                n = mw.ustring.len( s )  +  1
                 for i = 1, 12 do
                s = mw.ustring.sub( analyse, n )
                     if given[ i ] == s then
                s2 = s:match( "^ (%d%d%d?%d?)$" )
                         r = i
                if s2 then
                         break
                    rO.year = tonumber( s2 )
                    rS = ""
                 else
                    s2, s3, rS = s:match( "^ (%d+), (%d+)( ?.*)$" )
                     if s2 and s3 then
                        n = #s2
                        if n <= 2  and  #s3 == 4 then
                            rO.dom  = tonumber( s2 )
                            rO.year = tonumber( s3 )
                            rO.dom2 = ( n == 2 )
                         else
                            rO = false
                         end
                    else
                        rO = false
                     end
                     end
                 end -- for i
                 end
             end
             end
             if r then
        else
                break
             rO = false
            end
        end
         end -- for k, v
    else
        rO = false
    end
    if not rO then
         rS = false
     end
     end
     return r
     return rO, rS
end -- Parser.monthNumber()
end -- Parser.monthHeading()






Parser.putDate = function ( aYear, aMonth, aDom, assign )
Parser.monthNumber = function ( analyse )
     -- Store date strings
     -- String analysis, retrieve month number
     -- Parameter:
     -- Parameter:
     --    aYear  -- string, with year, or false
     --    analyse -- string, with month name including any period
    --    aMonth -- string, with numeric month
    --    aDom    -- string, with day of month
    --    assign  -- table
     -- Returns:
     -- Returns:
     --    table, extended
     --    number, 1...12 if found
     local r = assign
    --    false or nil, if not detected
     if aYear then
     local r = false
         r.year  = tonumber( aYear )
    local s = mw.ustring.match( analyse, "^([%a&;]+)%.?$" )
     if s then
         local given
        s = capitalize( s )
        for k, v in pairs( World.monthsLong ) do
            given = World.monthsParse[ k ]
            if given then
                r = given[ s ]
            end
            if not r then
                given = World.monthsLong[ k ]
                for i = 1, 12 do
                    if given[ i ] == s then
                        r = i
                        break
                    end
                end -- for i
            end
            if r then
                break
            end
        end -- for k, v
     end
     end
     r.month  = tonumber( aMonth )
    return r
     r.dom    = tonumber( aDom )
end -- Parser.monthNumber()
     r.month2 = ( #aMonth == 2 )
 
     r.dom2  = ( #aDom == 2 )
 
 
Parser.putDate = function ( aYear, aMonth, aDom, assign )
    -- Store date strings
    -- Parameter:
    --    aYear  -- string, with year, or false
    --    aMonth  -- string, with numeric month
    --    aDom    -- string, with day of month
    --    assign  -- table
    -- Returns:
    --    table, extended
    local r = assign
    if aYear then
        r.year  = tonumber( aYear )
    end
     r.month  = tonumber( aMonth )
     r.dom    = tonumber( aDom )
     r.month2 = ( #aMonth == 2 )
     r.dom2  = ( #aDom == 2 )
     return r
     return r
end -- Parser.putDate()
end -- Parser.putDate()
Zeile 570: 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 775: Zeile 1.177:
             end
             end
         else
         else
             r, s = Parser.monthHeading( s, r )
             local rM, sM = Parser.monthHeading( s, r )
             if r and s ~= "" then
            if rM then
                 r = Parser.time( s, r )
                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 786: Zeile 1.193:




Private.factory = function ( assign, alien )
Private.factory = function ( assign, alien, add )
     -- Create DateTime table (constructor)
     -- Create DateTime table (constructor)
     -- Parameter:
     -- Parameter:
Zeile 793: 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 r    = false
     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 = mw.getCurrentFrame():callParserFunction( "#timel",
             stamp = frame():callParserFunction( "#timel", "c", shift )
                                                            "c" )
            shift = false
         else
         else
             local seconds = stamp:match( "^#(%d+)$" )
             local seconds = stamp:match( "^#(%d+)$" )
Zeile 813: Zeile 1.226:
             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 825: Zeile 1.238:




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      -- table, with interval, or nil
     -- Returns:
     -- Returns:
     --    table, if parsed
     --    table, if parsed
Zeile 836: Zeile 1.250:
     local r
     local r
     if type( analyse ) == "string" then
     if type( analyse ) == "string" then
        local strip = mw.ustring.char( 0x5B, 0x200E, 0x200F, 0x5D )
         r =  analyse:gsub( "&nbsp;", " " )
         r =  analyse:gsub( "&nbsp;", " " )
                     :gsub( "&#160;", " " )
                     :gsub( "&#160;", " " )
Zeile 845: Zeile 1.260:
                     :gsub( "%[%[", "" )
                     :gsub( "%[%[", "" )
                     :gsub( "%]%]", "" )
                     :gsub( "%]%]", "" )
                    :gsub( strip, "" )
         r = mw.text.trim( r )
         r = mw.text.trim( r )
         if r == "" then
         if r == "" then
             r = { }
             r = { }
         else
         else
             local slang = ( alien or "" )
             local slang = ( alien or "" )
            local parser = { en  = "GermanEnglish",
                            de  = "GermanEnglish",
                            frr = "GermanEnglish",
                            nds = "GermanEnglish" }
            local suitable
             if slang == "" then
             if slang == "" then
                 slang = "en"
                 slang = "en"
Zeile 858: Zeile 1.279:
                 end
                 end
             end
             end
             slang = slang:lower()
             slang   = slang:lower()
             if slang == "en" or slang == "de" then
             suitable = parser[ slang ]
            if suitable then
                 local l
                 local l
                 l, r = pcall( Parser.GermanEnglish, r )
                 l, r = pcall( Parser[ suitable ], r )
                 if l and r then
                 if l and r then
                     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
                else
                    r = "invalid format"
                 end
                 end
             else
             else
                 r = "unknown language"
                 r = "unknown language: " .. slang
             end
             end
         end
         end
Zeile 879: Zeile 1.305:




Private.foreign = function ()
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
     -- Retrieve localization submodule
     if not World.localization then
     if not Meta.localized then
         local l, d = pcall( mw.loadData, "Module:DateTime/local" )
         local d = foreignModule( DateTime.suite,
         if l then
                                false,
                                "local",
                                DateTime.item )
         if type( d ) == "table" then
             local wk
             local wk
             if d.slang then
             if d.slang then
                Meta.suite  = string.format( "%s %s",
                                            Meta.suite, d.slang )
                 World.slang = d.slang
                 World.slang = d.slang
             end
             end
Zeile 899: Zeile 1.382:
             end -- for k, v
             end -- for k, v
         end
         end
         World.localization = true
         Meta.localized = true
     end
     end
end -- Private.foreign()
end -- Private.foreign()
Zeile 905: Zeile 1.388:




Prototypes.fair = function ( self, access, assign )
Private.from = function ( attempt )
     -- Check formal validity of table
     -- Create valid raw table from arbitrary table
     -- Parameter:
     -- Parameter:
     --    self    -- table, to be checked
     --    attempt  -- table, to be evaluated
    --    access  -- string or nil, single item to be checked
    --    assign  -- single access value to be checked
     -- Returns:
     -- Returns:
     --    true, if valid; false, if not
     --    table, with valid components, or nil
     local r = ( type( self ) == "table" )
    local data = { }
     if r then
     local r
         local defs = { year  = { max = MaxYear },
    for k, v in pairs( Meta.components ) do
                      month = { min 1,
        if v then
                                max = 12 },
            v = ( type( attempt[ k ] ) == v )
                      dom  = { min = 1,
        else
                                max = 31 },
            v = true
                      hour  = { max = 23 },
        end
                      min  = { max = 59 },
        if v then
                      sec  = { max = 61 },
            data[ k ] = attempt[ k ]
                      msec  = { max = 1000 }
        end
         }
    end -- for k, v
         local months = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
     if Prototypes.fair( data ) then
        local fNum =
        r = data
            function ( k, v )
    end
                 local ret = true
    return r
                local dk  = defs[ k ]
end -- Private.from()
                if dk then
 
                    if type( dk.max ) == "number" then
 
                        ret = ( type( v ) == "number" )
 
                        if ret then
Private.future = function ( add )
                            local min
    -- Normalize move interval
                            if dk.min then
    -- Parameter:
                                min = dk.min
    --    add  -- string or number, to be added
                            else
    -- Returns:
                                min = 0
    --    table, with shift, or false/nil
                            end
    local r
                            ret = ( v >= min and v <= dk.max
    if add then
                                    and  math.floor( v ) == v )
         local s = type( add )
                            if ret and dk.f then
        if s == "string"  and add:match( "^%s*[+-]?%d+%.?%d*%s*$" ) then
                                ret = dk.f( v )
            r = tonumber( add )
                            end
            s = "number"
                         end
        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
                return ret
            end
            end -- fNum()
        end
        defs.dom.f =
    end
            function ()
    if type( r ) == "nil" then
                local ret
        if not since  or  since <= Meta.serial then
                local d
            r = Meta.serial
                if access == "dom" then
        else
                    d = assign
            r = false
                else
        end
                    d = self.dom
    end
                end
    return r
                if d then
end -- Prototypes.failsafe()
                    ret = ( d <= 28 )
 
                    if not ret then
 
                        local m
 
                        if access == "month" then
Prototypes.fair = function ( self, access, assign )
                            m = assign
    -- Check formal validity of table
                        else
    -- Parameter:
                            m = self.month
    --    self    -- table, to be checked
                        end
    --    access  -- string or nil, single item to be checked
                        if m then
    --    assign  -- single access value to be checked
                            ret = ( d <= months[ m ] )
    -- Returns:
                            if ret then
    --    true, if valid;  false, if not
                                local y
    local r = ( type( self ) == "table" )
                                if access == "year" then
    if r then
                                    y = assign
        local defs = { year  = { max = MaxYear },
                                else
                      month = { min =  1,
                                    y = self.year
                                max = 12 },
                                end
                      week  = { min =  1,
                                if d == 29 and  m == 2  and  y then
                                max = 53 },
                                     if y % 4 ~= 0 or  y % 400 == 0 then
                      dom   = { min =  1,
                                        ret = false
                                max = 31 },
                                    end
                      hour  = { max = 23 },
                                end
                      min  = { max = 59 },
                             end
                      sec  = { max = 61 },
                         end
                      msec  = { max = 999 },
                      mysec = { max = 999 }
        }
        local fNum =
            function ( k, v )
                local ret = true
                local dk  = defs[ k ]
                if dk then
                    if type( dk.max ) == "number" then
                        ret = ( type( v ) == "number" )
                        if ret then
                            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 )
                            if ret and dk.f then
                                ret = dk.f( v )
                             end
                         end
                     end
                     end
                else
                    ret = true
                 end
                 end
                 return ret
                 return ret
             end -- defs.dom.f()
             end -- fNum()
         defs.sec.f =
         defs.dom.f =
             function ()
             function ()
                 local ret
                 local ret
                 local second
                 local d
                 if access == "sec" then
                 if access == "dom" then
                     second = assign
                     d = assign
                 else
                 else
                     second = self.sec
                     d = self.dom
                 end
                 end
                 if second then
                if d then
                     ret = ( second <= 59 )
                    ret = ( d <= 28 )
                     if not ret and self.leap then
                    if not ret then
                         ret = true
                        local m
                        if access == "month" then
                            m = assign
                        else
                            m = self.month
                        end
                        if m then
                            ret = ( d <= Calc.months[ m ] )
                            if ret then
                                local y
                                if access == "year" then
                                    y = assign
                                else
                                    y = self.year
                                end
                                if d == 29  and  m == 2  and  y then
                                    if y % 4 ~= 0  or
                                      ( y % 100 == 0  and
                                        y % 400 ~= 0 ) then
                                        ret = false
                                    end
                                end
                            end
                        end
                    end
                else
                    ret = true
                end
                return ret
            end -- defs.dom.f()
        defs.sec.f =
            function ()
                local ret
                local second
                if access == "sec" then
                    second = assign
                else
                    second = self.sec
                end
                 if second then
                     ret = ( second <= 59 )
                     if not ret and self.leap then
                         ret = true
                     end
                     end
                 end
                 end
Zeile 1.030: Zeile 1.634:
             end
             end
         else
         else
            local order = { "bc", "year", "month", "dom",
             local life = false
                            "hour", "min", "sec", "msec" }
             local leak = false
             local life = false
             local leak = false
             local s, v
             local s, v
             for i = 1, 8 do
             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 1.046: 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
                 else
                 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.116: Zeile 1.725:




Prototypes.format = function ( self, ask, adapt )
Prototypes.fix = function ( self )
     -- Format object as string
     -- Adapt this object to local time if no explicit zone given
     -- Parameter:
     -- Parameter:
     --    self  -- table, with numbers etc.
    --    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.flow = function ( self, another, assert )
    -- 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 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
                    r = nil
                end
            end
        end
    end
    return r
end -- Prototypes.flow()
 
 
 
Prototypes.format = function ( self, ask, adapt )
    -- Format object as string
    -- Parameter:
     --    self  -- table, with numbers etc.
     --    ask    -- string, format spec, or nil
     --    ask    -- string, format spec, or nil
     --    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.128: Zeile 1.812:
     local r = false
     local r = false
     if type( self ) == "table" then
     if type( self ) == "table" then
         local opts  = { lang = self.lang }
        local slang = self.lang or "en"
         local babel, slang
         local opts  = { lang = slang }
         local babel
         if type( adapt ) == "table" then
         if type( adapt ) == "table" then
             if type( adapt.lang ) == "string" then
             if type( adapt.lang ) == "string" then
                 local i = adapt.lang:find( "-", 3, true )
                 local i = adapt.lang:find( "-", 3, true )
                 if i then
                 if i then
                     slang = adapt.lang
                     slang = adapt.lang:lower()
                     opts.lang = slang:sub( 1,  i - 1 )
                     opts.lang = slang:sub( 1,  i - 1 )
                 else
                 else
                     opts.lang = adapt.lang
                     opts.lang = adapt.lang:lower()
                 end
                 end
             end
             end
            opts.lang  = opts.lang:lower()
             opts.london = adapt.london
             opts.london = adapt.london
             opts.lonely = adapt.lonely
             opts.lonely = adapt.lonely
         end
         end
         babel = mw.language.new( opts.lang )
         babel = mw.language.new( opts.lang:lower() )
         if babel then
         if babel then
             local shift, show, stamp, suffix, limit4, locally
             local shift, show, stamp, suffix, limit4, locally
Zeile 1.155: Zeile 1.839:
                     stamp = string.format( "%d %s", self.dom, stamp )
                     stamp = string.format( "%d %s", self.dom, stamp )
                 end
                 end
                 if ask and ask:find( "Mon4" ) then
                 if ask and ask:find( "Mon4", 1, true ) then
                     local mon4 = World.months4[ opts.lang ]
                     local mon4 = World.months4[ opts.lang:lower() ]
                     if mon4 then
                     if mon4 and  mon4[ self.month ] then
                        if mon4[ self.month ] then
                        limit4 = true
                            limit4 = true
                        end
                     end
                     end
                 end
                 end
Zeile 1.167: Zeile 1.849:
             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.174: Zeile 1.861:
                                               stamp, self.sec )
                                               stamp, self.sec )
                         if self.msec then
                         if self.msec then
                             stamp = string.format( "%s.%d",
                             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.202: Zeile 1.894:
             if self.month then
             if self.month then
                 local bucket, m, suite, x
                 local bucket, m, suite, x
                 if show:find( "F" ) then
                 if show:find( "F", 1, true ) then
                     suite = "monthsLong"
                     suite = "monthsLong"
                 elseif show:find( "M" ) then
                 elseif show:find( "M", 1, true ) then
                     suite = "monthsAbbr"
                     suite = "monthsAbbr"
                 end
                 end
                 bucket = World[ suite ]
                 bucket = World[ suite ]
                 if bucket then
                 if bucket then
                     m = bucket[ opts.lang ]
                     m = bucket[ opts.lang:lower() ]
                     if slang then
                     if slang then
                         x = bucket[ slang ]
                         x = bucket[ slang:lower() ]
                     end
                     end
                     if m then
                     if m then
Zeile 1.274: Zeile 1.966:




World.templates.formatter = function ( assigned, ask, adapt )
Prototypes.future = function ( self, add, allocate )
     -- Retrieve format specification string
     -- Relative move by interval
     -- Parameter:
     -- Parameter:
     --    assigned  -- table, with numbers etc.
     --    self      -- table, to be used as base
     --    ask       -- string, format spec, or nil
     --    add       -- string or number, to be added
    --    adapt    -- table, with options
     --    allocate -- true, if a clone shall be returned
     --                 .lang    -- string, with particular language code
     --                  .lonely -- true: permit lonely hour
     -- Returns:
     -- Returns:
     --    1  -- string
     --    table, with shift
    --    2  -- string or nil; append suffix (zone)
     local r, raw, rel, shift
     local r1, r2
     if type( self ) == "table" then
     if not ask  or  ask == "" then
         r    = self
         r1 = "c"
        shift = add
     else
    elseif type( add ) == "table" then
         local template = World.templates[ ask ]
        r     = add
        r1 = ask
         shift = self
        if not template then
    end
            local slang = ( adapt.lang or assigned.lang or World.slang )
    if r then
             local tmp  = World.templates[ slang ]
        if r[ Meta.signature ] then
             if tmp then
             raw = r[ Meta.signature ]
                template = tmp[ ask ]
        else
            end
             raw = r
         end
         end
         if type( template ) == "table" then
         if type( shift ) == "table" then
             r1 = template.spec
             rel = shift
            if assigned.year then
        else
                if not assigned.dom then
            rel = Private.future( shift )
                    r1 = r1:gsub( "[ .]?[jJ][ .,%-]*", "" )
        end
                          :gsub( "^&#160;", "" )
    end
                    if not assigned.month then
    if raw and rel then
                        r1 = r1:gsub( "[ .%-]?[fFmM][ .%-]*", "" )
        if allocate then
                    end
            r  = Prototypes.clone( r )
                end
            raw = r[ Meta.signature ]
             else
        end
                r1 = r1:gsub( " ?[yY] ?", "" )
        for k, v in pairs( rel ) do
                if not assigned.dom then
            raw[ k ] = ( raw[ k ] or 0 )  +  v
                    r1 = r1:gsub( "[ .]?[jJ][ .,%-]*", "" )
        end -- for k, v
                            :gsub( "^&#160;", "" )
        Calc.fair( raw )
                end
        r[ Meta.signature ] = raw
            end
    end
            if template.lift then
    return r
                local stamp = false
end -- Prototypes.future()
                local low  = ( ask == "ISO" or ask == "ISO-T" )
 
                if assigned.hour then
 
                    if assigned.min then
 
                        stamp = "H:i"
Prototypes.tostring = function ( self )
                        if assigned.sec then
    -- Stringify yourself
                            stamp = "H:i:s"
    -- Parameter:
                            if assigned.msec then
    --    self  -- table, to be stringified
                                stamp = string.format( "%s.%d",
    -- Returns:
                                                      stamp,
    --    string
                                                      assigned.msec )
    local dels = { false, "", "-", "-", "", "", ":", ":", ".", "" }
                            end
    local wids = { false, 4,  2,  2,  2,  2,  2,  2,  3,  3  }
                        end
    local s    = ""
                     elseif adapt.lonely then
    local n, r, spec
                         stamp = "H"
    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
    -- 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"
    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
                 end
                 end
                 if low or ask:find( "hh:mm:ss" ) then
                 r1 = r1 or World.present.time
                    if stamp then
            else
                        r1 = string.format( "%s %s", r1, stamp )
                r1 = World.present.date
                    end
            end
                 end
        end
                if stamp then
        r1 = r1 or "c"
                    if low or template.long then
    else
                        local scheme
        local template = World.templates[ ask ]
                        if template.long then
        r1 = ask
                            scheme = mw.language.getContentLanguage()
        if not template then
                            scheme = scheme.code
            local slang = ( adapt.lang or assigned.lang or World.slang )
                        end
            local tmp  = World.templates[ slang ]
                         r2 = World.zones.formatter( assigned, scheme )
            if tmp then
                 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 ( assigned.bc ) == "boolean" then
        end
                local eras = World.era[ adapt.lang ] or  World.era.en
        if type( template ) == "table" then
                local i
            local low = ( ask == "ISO" or ask == "ISO-T" )
                if not r2 then
            r1 = template.spec
                    r2 = ""
            if assigned.year then
                if not assigned.dom then
                    r1 = r1:gsub( "[ .%-]?[dDjlNwz][ .,%-]*", "" )
                          :gsub( "^&#160;", "" )
                    if not assigned.month then
                        r1 = r1:gsub( "[ .%-]?[FmMnt][ .%-]*", "" )
                    end
                 end
                 end
                 if assigned.bc then
            else
                    i = 1
                r1 = r1:gsub( " ?[yY] ?", "" )
                else
                 if not assigned.dom then
                    i = 2
                    r1 = r1:gsub( "[ .]?[dDjlNwz][ .,%-]*", "" )
                            :gsub( "^&#160;", "" )
                 end
                 end
                r2 = string.format( "%s&#160;%s", r2, eras[ i ] )
             end
             end
        end
            if template.lift and
    end
              ( assigned.dom or
    return r1, r2
                not  ( assigned.month or assigned.year or assigned.bc )
end -- World.templates.formatter()
              ) then
 
                local stamp = false
 
                if assigned.hour then
 
                    if assigned.min then
World.zones.formatter =  function ( assigned, align )
                        stamp = "H:i"
    -- Retrieve time zone specification string
                        if assigned.sec then
    -- Parameter:
                            stamp = "H:i:s"
    --    assigned -- table, with numbers etc.
                            if assigned.msec then
    --                  .zone should be available
                                stamp = string.format( "%s.%03d",
    --    align    -- string, format spec, or nil
                                                      stamp,
    --                  nil, false, "+-"  -- +/- 0000
                                                      assigned.msec )
    --                  "Z"               -- single letter
                                if assigned.mysec then
    --                  "UTC"            -- "UTC", if appropriate
                                    stamp = string.format( "%s.%03d",
    --                  "de"              -- try localized
                                                          stamp,
    -- Returns:
                                                        assigned.mysec )
    --    string
                                end
    local r    = ""
                            end
    local move = 0
                        end
    if assigned.zone then
                    elseif adapt.lonely then
        local s = type( assigned.zone )
                        stamp = "H"
        if s == "string" then
                    end
            s = assigned.zone:upper()
                end
            if #s == 1 then
                 if low or ask:find( "hh:mm:ss", 1, true ) then
                -- "YXWVUTSRQPONZABCDEFGHIKLM"
                    if stamp then
                 move = World.zones[ "!" ]:find( s )
                        r1 = string.format( "%s %s", r1, stamp )
                if move then
                     end
                    move          = ( move - 13 ) * 100
                     assigned.zone = move
                else
                    assigned.zone = false
                 end
                 end
            else
                if stamp then
                local code = World.zones[ s ]
                    if low or template.long then
                 if not code then
                        local scheme
                  local slang = ( assigned.lang or
                        if template.long then
                                  World.slang )
                            scheme = mw.language.getContentLanguage()
                  local tmp  = World.zones[ slang ]
                            scheme = scheme.code
                  if tmp then
                        end
                      code = tmp[ s ]
                        r2 = World.zones.formatter( assigned, scheme )
                  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
                 end
                 if code then
                 if assigned.bc then
                     move          = code
                     i = 1
                     assigned.zone = move
                else
                     i = 2
                 end
                 end
                r2 = string.format( "%s&#160;%s", r2, eras[ i ] )
             end
             end
        elseif s == "number" then
            move = assigned.zone
         end
         end
     end
     end
     if move then
     return r1, r2
        local spec = "+-"
end -- World.templates.formatter()
        if align then
 
            if align == "Z" then
 
                if move % 100 == 0 then
 
                    r = World.zones[ "!" ]:sub( move / 100 + 13, 1 )
World.zones.formatter =  function ( assigned, align )
                    spec = false
    -- Retrieve time zone specification string
                 end
    -- Parameter:
            elseif align ~= "+-" then
    --    assigned  -- table, with numbers etc.
                if move == 0 then
    --                  .zone should be available
                     r    = " UTC"
    --    align    -- string, format spec, or nil
                     spec = false
    --                  nil, false, "+-"  -- +/- 0000
                 else
    --                  "Z"              -- single letter
                    local part = World.zones[ align ]
    --                  "UTC"            -- "UTC", if appropriate
                    if part then
    --                  "de"              -- try localized
                        for k, v in pairs( part ) do
    -- Returns:
                            if v == move then
    --    string
                                r    = string.format( " (%s)", k )
    local r    = ""
                                spec = false
    local move = 0
                                break
    if assigned.zone then
                            end
        local s = type( assigned.zone )
                        end -- for k, v
        if s == "string" then
                     end
            s = assigned.zone:upper()
            if #s == 1 then
                -- "YXWVUTSRQPONZABCDEFGHIKLM"
                move = World.zones[ "!" ]:find( s, 1, true )
                 if move then
                    move         = ( move - 13 ) * 100
                     assigned.zone = move
                else
                     assigned.zone = false
                 end
            else
                local code = World.zones[ s ]
                if not code then
                  local slang = ( assigned.lang or
                                  World.slang )
                  local tmp  = World.zones[ slang ]
                  if tmp then
                      code = tmp[ s ]
                  end
                  if not code  and
                      slang ~= "en"  and
                      World.zones.en then
                      code = World.zones.en[ s ]
                  end
                end
                if code then
                    move          = code
                     assigned.zone = move
                 end
                 end
             end
             end
         end
         elseif s == "number" then
        if spec == "+-" then
             move = assigned.zone
             if move < 0 then
                spec = "%4.4d"
            else
                spec = "+%4.4d"
            end
            r = string.format( spec, move )
            r = string.format( "%s:%s",
                              r:sub( 1, 3), r:sub( 4 ) )
         end
         end
     end
     end
     return r
     if move then
end -- World.zones.formatter()
        local spec = "+-"
 
        if align then
 
            if align == "Z" then
 
                if move % 100 == 0 then
-- Export
                    r = World.zones[ "!" ]:sub( move / 100 + 13,  1 )
local p = { }
                    spec = false
                end
            elseif align ~= "+-" then
                if move == 0 then
                    r    = " UTC"
                    spec = false
                else
                    local part = World.zones[ align ]
                    if part then
                        for k, v in pairs( part ) do
                            if v == move then
                                r    = string.format( " (%s)", k )
                                spec = false
                                break
                            end
                        end -- for k, v
                    end
                end
            end
        end
        if spec == "+-" then
            if move < 0 then
                spec = "%4.4d"
            else
                spec = "+%4.4d"
            end
            r = string.format( spec, move )
            r = string.format( "%s:%s",
                              r:sub( 1, 3), r:sub( 4 ) )
        end
    end
    return r
end -- World.zones.formatter()
 
 


function p.test( args )
-- Export
local p = { }
 
function p.test( args, alien )
    local slang = args.lang or alien
    local obj  = Meta.fiat( args[ 1 ], false, args.shift )
     local r
     local r
    local obj = DateTime( args[ 1 ], "de" )
     if type( obj ) == "table" then
     if type( obj ) == "table" then
        local spec  = args[ 2 ]
         local opt
         local opt
        local spec  = args[ 2 ]
        local slang = args[ 3 ]
         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 invalid" )
         else
         else
             r = ""
             r = ""
         end
         end
     end
     end
     return r
     return r
end -- p.test
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
    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
    return r
end -- p.format






function p.format( frame )
function p.lt( frame )
     local l, r
     return Templates.flow( frame, "lt" )
    local v = { frame.args[ 1 ],
end -- p.lt
                frame.args[ 2 ],
function p.le( frame )
                frame.args[ 3 ],
    return Templates.flow( frame, "le" )
                noerror = frame.args.noerror }
end -- p.le
     if not v[ 1 ]  or  v[ 1 ] == "now" then
function p.eq( frame )
        v[ 1 ] = frame:callParserFunction( "#timel", "c" )
     return Templates.flow( frame, "eq" )
    end
end -- p.eq
    l, r = pcall( p.test, v )
function p.ne( frame )
     if not l then
    return Templates.flow( frame, "ne" )
        r = fault( r )
end -- p.ne
    end
function p.ge( frame )
     return r
     return Templates.flow( frame, "ge" )
end -- p.format
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
395

Bearbeitungen