Module:Sandbox/Hellknowz/Test

This is an old revision of this page, as edited by Hellknowz (talk | contribs) at 14:06, 28 August 2013 (hmm). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
local main = {};

local monthIndices = {
    ['january'] = 1,
    ['february'] = 2,
    ['march'] = 3,
    ['april'] = 4,
    ['may'] = 5,
    ['june'] = 6,
    ['july'] = 7,
    ['august'] = 8,
    ['september'] = 9,
    ['october'] = 10,
    ['november'] = 11,
    ['december'] = 12
}

local monthDays = {
    [1] = 31,
    [2] = 29, -- will check below
    [3] = 31,
    [4] = 30,
    [5] = 31,
    [6] = 30,
    [7] = 31,
    [8] = 31,
    [9] = 30,
    [10] = 31,
    [11] = 30,
    [12] = 31
}

function tryParseDateTime(input)

    --1 May 1973, 10:38:27
    --10:38:27, 1 May 1973
    --10:38am
    --10am

    local matchDay, matchMonth, matchYear
    local matchHour, matchMinute, matchSecond

    -- Try dMy hms
    matchDay, matchMonth, matchYear, matchHour, matchMinute, matchSecond = input:match('^([0-9][0-9]?) ([A-Za-z]+) ([0-9][0-9][0-9][0-9]),? ([0-9][0-9]?):([0-9][0-9]?):([0-9][0-9]?)$')

    if (matchDay) then
        local month = monthIndices[matchMonth:lower()]
        if (month == nil) then return nil end

        return tonumber(matchDay), month, tonumber(matchYear), tonumber(matchHour), tonumber(matchMinute), tonumber(matchSecond)
    end

    -- Try Mdy hms
    matchMonth, matchDay, matchYear, matchHour, matchMinute, matchSecond = input:match('^([A-Za-z]+) ([0-9][0-9]?),? ([0-9][0-9][0-9][0-9]),? ([0-9][0-9]?):([0-9][0-9]?):([0-9][0-9]?)$')

    if (matchDay) then
        local month = monthIndices[matchMonth:lower()]
        if (month == nil) then return nil end

        return tonumber(matchDay), month, tonumber(matchYear), tonumber(matchHour), tonumber(matchMinute), tonumber(matchSecond)
    end

    -- Try hms dMy
    matchHour, matchMinute, matchSecond, matchDay, matchMonth, matchYear = input:match('^([0-9][0-9]?):([0-9][0-9]?):([0-9][0-9]?),? ([0-9][0-9]?) ([A-Za-z]+) ([0-9][0-9][0-9][0-9])$')

    if (matchDay) then
        local month = monthIndices[matchMonth:lower()]
        if (month == nil) then return nil end

        return tonumber(matchDay), month, tonumber(matchYear), tonumber(matchHour), tonumber(matchMinute), tonumber(matchSecond)
    end

    -- Try hms Mdy
    matchHour, matchMinute, matchSecond, matchMonth, matchDay, matchYear = input:match('^([0-9][0-9]?):([0-9][0-9]?):([0-9][0-9]?),? ([A-Za-z]+) ([0-9][0-9]?),? ([0-9][0-9][0-9][0-9])$')

    if (matchDay) then
        local month = monthIndices[matchMonth:lower()]
        if (month == nil) then return nil end

        return tonumber(matchDay), month, tonumber(matchYear), tonumber(matchHour), tonumber(matchMinute), tonumber(matchSecond)
    end

    -- todo others

    -- Well, we ran out of valid date formats
    return nil

end

function tryParseDateOnly(input)

    local matchDay, matchMonth, matchYear

    -- Try Y

    matchYear = input:match('^([0-9][0-9][0-9][0-9])$')

    if (matchYear) then
        return nil, nil, tonumber(matchYear)
    end

    -- Try My
    matchMonth, matchYear = input:match('^([A-Za-z]+) ([0-9][0-9][0-9][0-9])$')

    if (matchMonth) then
        local month = monthIndices[matchMonth:lower()]
        if (month == nil) then return nil end

        return nil, month, tonumber(matchYear)
    end

    -- Try dMy
    matchDay, matchMonth, matchYear = input:match('^([0-9][0-9]?) ([A-Za-z]+) ([0-9][0-9][0-9][0-9])$')

    if (matchDay) then
        local month = monthIndices[matchMonth:lower()]
        if (month == nil) then return nil end

        return tonumber(matchDay), month, tonumber(matchYear)
    end

    -- Try Mdy
    matchMonth, matchDay, matchYear = input:match('^([A-Za-z]+) ([0-9][0-9]?),? ([0-9][0-9][0-9][0-9])$')

    if (matchDay) then
        local month = monthIndices[matchMonth:lower()]
        if (month == nil) then return nil end

        return tonumber(matchDay), month, tonumber(matchYear)
    end

    -- Try ymd
    matchYear, matchMonth, matchDay = input:match('^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$')

    if (matchDay) then
        return tonumber(matchDay), tonumber(matchMonth), tonumber(matchYear)
    end

    -- Well, we ran out of valid date formats
    return nil

end

function checkIfDayValid(day, month)
    -- First check that the month can have at least this many days
    if (day > monthDays[month]) then return false end

    -- February leap year check
    if (month == 2) then
        if (day == 29 and not ((year % 4 == 0) and (year % 100 ~= 0) or (year % 400 == 0))) then
             return false
        end
    end

    return true
end

function checkIfMonthValid(year)
    return month ~= 0 and month <= 12  -- <0 never happens with [0-9] pattern
end

function checkIfYearValid(year)
    return year >= 1583 -- up to 9999
end

function checkIfYearValid(hour)
    return hour < 24 -- <0 never happens with [0-9] pattern
end

function checkIfMinuteValid(minute)
    return minute < 60 -- <0 never happens with [0-9] pattern
end

function checkIfSecondValid(second)
    return second < 60 -- <0 never happens with [0-9] pattern
end

function main.parseDate(frame)

    local input = frame.args[1]

    -- First, try to get a date and time
    local day, month, year, hour, minute, second = tryParseDateTime(input)

    return day .. month .. year .. hour .. minute .. second
--[[
    -- If we have a second, we have all 6
    if (second) then

        if (not checkIfYearValid(year) or not checkIfMonthValid(month) or not checkIfDayValid(day, month) or not checkIfHourValid(hour) or not checkIfMinuteValid(minute) or not checkIfSecondValid(second)) then return nil end

        return string.format("%d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second)

    end

    -- Second, try to get just the date
    day, month, year = tryParseDateOnly(input)

    -- No year, no date
    if (not year) then return nil end

    if (year and not month) then

        -- year only

        if (not checkIfYearValid(year)) then return nil end

        return year

    end

    if (year and month and not day) then

        -- month and year only

        if (not checkIfYearValid(year)) then return nil end
        -- Month always comes from month name pattern string, so always valid, can skip the check

        return string.format("%d-%02d", year, month)

    end

    if (not checkIfYearValid(year) or not checkIfMonthValid(month) or not checkIfDayValid(day, month) or not checkIfHourValid(hour)) then return nil end

    --parent stuff (infobox itself)
    --local parent = frame:getParent()
    --local parentArgs = parent.args

    return string.format("%d-%02d-%02d", year, month, day)
]]
end

function main.emitMetadata(frame)

    -- First parse the date and see if we get a valid output date
    local date = main.parseDate(frame)
    if (not date) then return nil end

    local spanClass = frame.args.spanClass or 'bday dtstart published updated'

    return '<span style="display:none">&#160;(<span class="' .. spanClass .. '">' .. date .. '</span>)</span>'

end
 
return main