Module:Sandbox/Deimos18/Dates

-- Deimos Google Code-in, Date formatting

-- Plan of action: -- Find type of string -- Separate out day, month and year -- Format date according to desired format -- Add exceptions for February -- Find and remove useless words which taint the text to find the required date -- Find special words like "uncertain" and "around" to replace with "circa"

local p = {}

months = {"january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"} -- for iso-type dates month_s = {"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"} -- for 3-lettered month dates (it won't get shorter than this, would it?) circa = {"around", "sometime around", "uncertain", "approximately", "approx", "about", "probably", "circa"} eralist = {"ce", "bc", "bce", "ad"}

function flUpper (str) local str = str or "" local l_check = string.match(str, "(%a+)") -- To take the first letter-y part of the string out of the complete string (for editing, ofc) local str_fi, str_la = string.find(str, "(%a+)") -- Find the first and last indices of the first letter-y part of string that appears if (str_fi == nil and l_check == nil) then -- checking if the string even consists letters out = str -- return back whatever there is since there's no letter anyways else local str_bef = string.sub(str,1,(str_fi-1)) -- Obtaining the part of the string before the first letter local str_fl = string.sub(l_check,1,1) -- Getting the first letter local str_cap = string.upper(str_fl) -- Capitalizing the first letter local str_end = string.sub(str, str_fi+1) -- Obtaining the rear part of the string i.e. the part after the first letter out = str_bef .. str_cap .. str_end -- Joining together the front, capitalized and rear part to return the complete string end return out end

addCirca = ""

function findType (str) -- To check if data type is other than mdy str = str or "" dateType = "" local fts = "" local fte = "" fts, fte = string.find(str, "(%d+)-(%d+)-(%d+)") if (fts ~= nil) then dateType = "iso" end fts, fte = string.find(str, "(%d+)/(%d+)/(%d+)") if (fts ~= nil) then dateType = "slashed" end for n=1,#circa do		findCirca = string.match(str, circa[n]) if (findCirca ~= nil) then addCirca = "circa " break else addCirca = "" end end if (dateType == nil) then dateType = "dmy" end return dateType end

function isoDates (str) local yeari, monthnum, dayi = string.match(str, "(%d%d%d%d)-(%d%d)-(%d%d)") local monthi = flUpper(months[tonumber(monthnum)]) return dayi, monthi, yeari end

function slashedDates (str) local days, monthnum, years = string.match(str, "(%d%d)/(%d%d)/(%d%d%d%d)") local monthsl = flUpper(months[tonumber(monthnum)]) return days, monthsl, years end

function findEra (str) str = str or "" local era = "" for q=1,#eralist do era = string.match(str, "(%s+)" .. eralist[q]) if (era ~= nil) then era = string.upper(eralist[q]) break else era = "" end end return era end

function findFebruary (day, month, year) local day = tonumber(day) or "" local month = month or "" local year = tonumber(year) or "" local nofeb = "nofeb" if (month == "February") then if ((year%4)==0) then if (day > 29) then return false else return true end else if (day > 28) then return false else return true end end else return nofeb end end

function findIfNumberExists (str) str = str or "" local check = string.match(str, "(%d+)") if (check ~= nil) then return true else return false end end

function changeFormat (day, month, year, addCirca, era, dtype, format) if (dtype == "slashed" and (format == nil or format == "")) then format = "iso" end if (dtype == "iso" and (format == nil or format == "")) then format = "iso" end local format = format or "dmy" local form = "" local era = era or "" if (addCirca == "" or addCirca == nil) then addCirca = "" end if (format == "mdy") then form = addCirca .. month .. " " .. day .. ", " .. year end if (format == "iso") then for e=1,#months do			local monthfind = string.match(string.lower(month), months[e]) if (monthfind ~= nil) then monthnumi = e if (string.match(monthnumi, "[0-9][0-9]") == nil) then monthnumi = "0" .. monthnumi end break end end if (month == nil or month == "" or monthnumi == nil or monthnumi == "") then form = "Invalid Entry" else form = addCirca .. year .. "-" .. monthnumi .. "-" .. day end end if (format == "dmy") then form = addCirca .. day .. " " .. month .. " " .. year .. " " .. era end if (format == "year") then form = addCirca .. year .. " " .. era end if (format == "month and year") then form = addCirca .. month .. " " .. year .. " " .. era end return form end

p.formatDate = function (frame) local text = string.lower(frame.args.text) local format = frame.args.format dtype = findType(text) invEnt = false eras = findEra(text) or "" local out = "" ms = "" me = "" mst = false local msn = "" for i=1,#months do		ms, me = string.find(text,months[i]) if (ms ~= nil) then break end end if (ms == nil) then for i=1,#month_s do			ms, me = string.find(text,month_s[i]) if (ms ~= nil) then msn = i				mst = true break end end end if (ms ~= nil) then if (mst==true) then month = flUpper(months[msn]) else month = flUpper(string.sub(text, ms, me)) end else month = "" end local year = string.match(text, "%d%d%d%d") or "" if (year == "") then year = string.match(text, "%d%d%d") or "" if (year == "" and (eras == nil or eras == "")) then year = string.match(text, "%d%d% %a+ (%d%d)") or "" end if (year == "" and eras ~= nil and eras ~= "") then year = string.match(text, "(%d%d) " .. string.lower(eras)) or "" if (year == "" and eras ~= nil and eras ~= "") then year = string.match(text, "(%d) " .. string.lower(eras)) or "" end end end local leftOutString = string.gsub(text, year, "none", 1) if (month == "" and year ~= "") then day = "" else day = string.match(leftOutString, "(%d+)") end if (dtype == "iso") then day, month, year = isoDates(text) end if (dtype == "slashed") then day, month, year = slashedDates(text) end if (findIfNumberExists(text)==false) then invEnt = true day = "1" end out = out .. changeFormat(day, month, year, addCirca, eras, dtype, format) febCheck = findFebruary(day,month,year) if (febCheck ~= "nofeb" and febCheck==false) then invEnt = true end if ((febCheck == "nofeb") and day ~= "" and (tonumber(day) > 31) and (tonumber(day) < 1)) then invEnt = true end if (invEnt == true) then out = "Invalid Entry" end return out end

return p