Module:Sandbox/Nathan fraignt/Dates

local table_contains = function (table, element) for _, value in pairs(table) do   if value == element then return true end end return false end

p = {} local weird_years = {"AD", "BCE", "BC"} local circa_words = {"around", "sometime", "uncertain", "circa", "ca"} local months = {"january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"} local months_uppercase = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"} local months_abr = {} for _, month in pairs(months) do	table.insert(months_abr, string.sub(month, 1, 3)) end local months_index={} local months_abr_index={} for k,v in pairs(months) do  months_index[v]=k end for k,v in pairs(months_abr) do  months_abr_index[v]=k end

local getDateType = function(date) nf_date = date if nf_date == nil then return nil end local isDMY = ((string.match(nf_date, "[0-3]?%d.*%s%a+%s%d%d%d+") ~= nil) and true or false) local isMDY = ((string.match(nf_date, "%a+.[0-3]?%d.+%d%d%d+") ~= nil) and true or false) if isDMY or isMDY then local foundMonth = false for word in string.gmatch(nf_date, "%w+") do			if months_abr_index[word:sub(1,3):lower] then foundMonth = true end end if foundMonth then isDMY, isMDY = isDMY, isMDY else isDMY, isMDY = false, false end end local isNumDMY = ((string.match(nf_date, "[0-3]?%d.[0-1]?%d.%d%d%d+") ~= nil) and true or false) local isNumMDY = ((string.match(nf_date, "[0-1]?%d.[0-3]?%d.%d%d%d+") ~= nil) and true or false) local isISO = ((string.match(nf_date, "%d%d%d%d.[0-1]?%d.[0-3]?%d") ~= nil) and true or false) local isYear = ((string.match(nf_date, "%d%d%d+") ~= nil) and true or false) local isMonthYear = false if isYear then local foundMonth = false for word in string.gmatch(nf_date, "%w+") do			if months_abr_index[word:sub(1,3):lower] then foundMonth = true end end isMonthYear = foundMonth isYear = not foundMonth end local isDayMonth = ((string.match(nf_date, "[0-3]?%d%s%a") ~= nil) and true or false) if isDayMonth then local foundMonth = false for word in string.gmatch(nf_date, "%w+") do			if months_abr_index[word:sub(1,3):lower] then foundMonth = true end end isDayMonth = foundMonth end

if isDMY then return "DMY" end if isMDY then return "MDY" end if isNumDMY then return "NDMY" end if isNumMDY then return "NMDY" end if isISO then return "ISO" end if isYear then return "YEAR" end if isMonthYear then return "MY" end if isDayMonth then return "DM" end return false end p.getDate = function(frame) local dateToISO = function(nf_date, format) local day, month, year if format == "DMY" then local monthName, monthName_abr day, monthName, year = string.match(nf_date, "(%d+) (%w+) (%d%d%d+)") if monthName == nil then monthName = "" end month = months_abr_index[string.lower(monthName)] or months_index[string.lower(monthName)] -- returns if format was something like 15 Jan 2013 if month ~= nil then return year .. "-" .. month .. "-" .. day end day = string.match(nf_date, "(%d%d?)") year = string.match(nf_date, "(%d%d%d+)") for _, mon in pairs(months_abr) do					monthName_abr = string.match(string.lower(nf_date), mon) if monthName_abr ~= nil then break end end month = months_abr_index[monthName_abr] return year .. "-" .. month .. "-" .. day elseif format == "NDMY" then day, month, year = string.match(nf_date, "(%d%d?).(%d%d?).(%d%d%d+)") return year .. "-" .. month .. "-" .. day elseif format == "MDY" then local monthName, monthName_abr monthName, day, year = string.match(nf_date, "(%w+) (%d+) (%d%d%d+)") if monthName == nil then monthName = "" end month = months_abr_index[string.lower(monthName)] or months_index[string.lower(monthName)] if month ~= nil then return year .. "-" .. month .. "-" .. day end day = string.match(nf_date, "(%d%d?)") year = string.match(nf_date, "(%d%d%d+)") for _, mon in pairs(months_abr) do					monthName_abr = string.match(string.lower(nf_date), mon) if monthName_abr ~= nil then break end end month = months_abr_index[monthName_abr] return year .. "-" .. month .. "-" .. day elseif format == "NMDY" then month, day, year = string.match(nf_date, "(%d%d?).(%d%d?).(%d%d%d+)") return year .. "-" .. month .. "-" .. day elseif format == "ISO" then year, month, day = string.match(nf_date, "(%d%d%d+).(%d%d?).(%d%d?)") return year .. "-" .. month .. "-" .. day elseif format == "YEAR" then year = string.match(nf_date, "(%d%d%d+)") return year elseif format == "MY" then year = string.match(nf_date, "(%d%d%d+)") for _, mon in pairs(months_abr) do					monthName_abr = string.match(string.lower(nf_date), mon) if monthName_abr ~= nil then break end end month = months_abr_index[monthName_abr] return year .. "-" .. month elseif format == "DM" then day = string.match(nf_date, "(%d%d?)") for _, mon in pairs(months_abr) do					monthName_abr = string.match(string.lower(nf_date), mon) if monthName_abr ~= nil then break end end month = months_abr_index[monthName_abr] return month .. "-" .. day end return nil end local isoToFormat = function(iso_date, formatTo) local format, monthName local toDMY = {"DMY", "NDMY"} local toMDY = {"MDY", "NMDY"} if table_contains(toDMY, formatTo) then format = "DMY" elseif table_contains(toMDY, formatTo) then format = "MDY" else format = formatTo end local year, month, day = string.match(iso_date, "(%d+).(%d+).(%d+)") if format == "DMY" then monthName = months_uppercase[tonumber(month)] return day .. " " .. monthName .. " " .. year elseif format == "MDY" then monthName = months_uppercase[tonumber(month)] return monthName .. " " .. day .. ", " .. year elseif format == "ISO" then return iso_date elseif format == "YEAR" then return iso_date elseif format == "MY" then year, month = string.match(iso_date, "(%d+).(%d+)") monthName = months_uppercase[tonumber(month)] return monthName .. " " .. year elseif format == "DM" then month, day = string.match(iso_date, "(%d+).(%d+)") monthName = months_uppercase[tonumber(month)] return day .. " " .. monthName end return nil end local addQuirks = function(f_date, nf_date, dateType) local yearPart, useCirca if dateType ~= "DM" then for _, weirdYear in pairs(weird_years) do				if string.match(nf_date, weirdYear) ~= nil then yearPart = weirdYear break end end end for _, circaWord in pairs(circa_words) do			if string.match(string.lower(nf_date), circaWord) ~= nil then useCirca = true break end end local returnValue = f_date if yearPart ~= nil then returnValue = returnValue .. " " .. yearPart end if useCirca ~= nil then returnValue = "circa " .. returnValue end return returnValue end local isValidDate = function(iso_date, dateType) if (dateType == "YEAR") then if tonumber(iso_date) < 0 then return false else return true end end if (dateType == "DM" ) then local month, day = string.match(iso_date, "(%d+).(%d+)") month, day = tonumber(month), tonumber(day) if month > 12 or day > 31 then return false end if month == 4 or month == 6 or month == 9 or month == 11 then return day <= 30 end return true end if (dateType == "MY") then local year, month = string.match(iso_date, "(%d+).(%d+)") if tonumber(year) < 0 then return false end if tonumber(month) > 12 then return false end return true end local year, month, day = string.match(iso_date, "(%d+).(%d+).(%d+)") year, month, day = tonumber(year), tonumber(month), tonumber(day) if year < 0 or month 12 or day 31 then return false end if month == 4 or month == 6 or month == 9 or month == 11 then return day <= 30 end if month == 2 then if (year % 100 ~= 0 and year % 4 == 0) or year % 400 == 0 then return day <= 29 else return day <= 28 end end return true end local nf_date = frame.args.date local dateType = getDateType(nf_date) -- return dateType if not dateType then return "Invalid Entry" end local formatTo = frame.args.format or dateType local iso_date = dateToISO(nf_date, dateType) -- return iso_date if not isValidDate(iso_date, dateType) then return "Invalid Entry" end local f_date = isoToFormat(iso_date, formatTo) f_date = addQuirks(f_date, nf_date, formatTo) return f_date

end

return p