Documentation for this module may be created at Module:Sandbox/Nathan fraignt/Dates/doc
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 < 0 or month > 12 or day < 0 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