Module:Sandbox/N3rsti/Dates2

local p = {}

local date_words = { months={"january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"}, short_months={"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"}, accepted_endings = {"AD", "BCE", "BC", "CE"}, months_days = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, number_endings = {"st", "nd", "rd", "th"}, circa_words = {'circa', 'sometime', 'around', 'uncertain'}, accepted_words = {'year', 'month', 'day'} }

-- Search for keywords function check_valid(date_text, date_table) local date_sign = "[^%s]+" if string.match(date_text, "%-") then date_sign = "[^%-]+" elseif string.match(date_text, "%/") then date_sign = "[^%/]+" end for word in string.gmatch(date_text, date_sign) do			table.insert(date_table, word) end for counter, month in pairs(date_words.months) do		for _, word in pairs(date_table) do			if string.lower(word) == month or string.lower(word) == date_words.short_months[counter] then return {is_valid=true} end end end for _, ending in pairs(date_words.accepted_endings) do		for _, word in pairs(date_table) do			if word == ending then return {is_valid=true} end end end for _, ending in pairs(date_words.circa_words) do		if string.match(date_text, ending) then return {is_valid=true} end end for _, word in pairs(date_words.accepted_words) do		if string.match(date_text, word) then return {is_valid=true} end end end

-- Define format from submitted date function detect_date(date_text) local date_sign = "[^%s]+" local sign, date_ending = "" local circa_ending = "" if string.match(date_text, "%-") then date_sign = "[^%-]+" elseif string.match(date_text, "%/") then date_sign = "[^%/]+" end local date_table = {} for word in string.gmatch(date_text, date_sign) do		table.insert(date_table, word) end for _, ending in pairs(date_words.accepted_endings) do		for _, word in pairs(date_table) do			if word == ending then date_ending = ending end end end for _, num_end in pairs(date_words.number_endings) do		for _, word in pairs(date_table) do			if string.sub(word, -#num_end) == num_end then num_ending = num_end end end end for _, ending in pairs(date_words.circa_words) do		if string.match(date_text, ending) then circa_ending = "circa" end end date_ending = date_ending or "" num_ending = num_ending or "" if #date_table == 1 and tonumber(date_text) then return {day=date_text} end if string.match(date_text, "%-") then date_sign = "[^%-]+" year, month, day = string.match(date_text, "(%d+)-(%d+)-(%d+)") if year then return {day=day, month=month, year=year, date_ending=date_ending, circa_ending=circa_ending} end elseif string.match(date_text, "%/") then date_sign = "[^%/]+" day, month, year = string.match(date_text, "(%d+)/(%d+)/(%d+)") if day then return {day=day, month=month, year=year, date_ending=date_ending, circa_ending=circa_ending} end end if #date_table == 2 and tonumber(date_table[1]) and tonumber(date_table[2]) then local day, year = string.match(date_text, "(%d+) (%d+)") if day then return {year=year, date_ending=date_ending, circa_ending=circa_ending} end end if check_valid(date_text, date_table) then local day, month, year = string.match(date_text, "(%d+)" .. num_ending .. " (%w+) (%d+)") if day then return {day=day, month=month, year=year, date_ending=date_ending, circa_ending=circa_ending} else local day, month, year = string.match(date_text, "(%d+) (%w+) (%d+)") if day then return {day=day, month=month, year=year, date_ending=date_ending, circa_ending=circa_ending} end month, day, year = string.match(date_text, "(%w+) (%d+), (%d+)") -- December 21, 2019 if day then return 	{day=day, month=month, year=year, date_ending=date_ending, circa_ending=circa_ending} end for word in string.gmatch(date_text, date_sign) do				table.insert(date_table, word) end day=string.match(date_text, "(%d+)" .. num_ending) _, year = string.match(date_text, "(.+) (%d+)") if day and year then for _, arr_month in pairs(date_words.months) do					month = arr_month end if month then return {day=day, month=month, year=year, date_ending=date_ending, circa_ending=circa_ending} end end day, month = string.match(date_text, "(%d+) (%d+)") if day then return 	{day=day, year=year, date_ending=date_ending, circa_ending=circa_ending} end day, month = string.match(date_text, "(%d+) (%w+)") if day then return {day=day, month=month, date_ending=date_ending, circa_ending=circa_ending} end end end if check_valid(date_text, date_table) then year = string.match(date_text, "(%d+) (.+)") if year then return {year=year, circa_ending=circa_ending, date_ending=date_ending} end end day, month = string.match(date_text, "(%d+) (%d+)") if day then return {day=day, month=month, year=year, date_ending=date_ending, circa_ending=circa_ending} end end

-- Format date to expected format function p.format_date(frame) local date_text = frame.args.date or "" local date_format = frame.args.format or "" local date_ending = "" local day = "" local month = "" local year = "" local circa_ending = "" local date_ending = "" if (string.match(date_text, "/") and date_format == "") or (string.match(date_text, "-") and date_format == "") then date_format = "iso" end if detect_date(date_text) and detect_date(date_text).day then day = detect_date(date_text).day or "" end if detect_date(date_text) and detect_date(date_text).month then month = detect_date(date_text).month or "" end if detect_date(date_text) and detect_date(date_text).year then year = detect_date(date_text).year or "" end if detect_date(date_text) and detect_date(date_text).date_ending then date_ending = detect_date(date_text).date_ending or "" end if detect_date(date_text) and detect_date(date_text).circa_ending then circa_ending = detect_date(date_text).circa_ending or "" end for month_num=1, #date_words.months do		if string.match(string.lower(date_text), date_words.months[month_num]) or string.match(string.lower(date_text), date_words.short_months[month_num]) then month = date_words.months[month_num] if tonumber(year) and tonumber(year) % 4 == 0 then date_words.months_days[month_num] = date_words.months_days[month_num] + 1 end if tonumber(day) > date_words.months_days[month_num] then return "Invalid entry" end break end end local index={} for k,v in pairs(date_words.months) do	  index[v]=k end month = month:gsub("^%l", string.upper) if date_format == "iso" then if not tonumber(month) then month = tostring(index[string.lower(month)]) if #month == 1 then month = "0" .. month end if #day == 1 then day = "0" .. day end end return circa_ending .. " " .. year .. "-" .. month .. "-" .. day .. " " .. date_ending elseif date_format == "mdy" then if tonumber(month) then month = date_words.months[tonumber(month)] or "" month = month:gsub("^%l", string.upper) or "" end return circa_ending .. " " .. month .. " " .. day .. ", " .. year .. " " .. date_ending elseif date_format == "year" then return circa_ending .. " " .. year .. " " .. date_ending end if day == "" and month == "" and year == "" then return "Invalid entry" end if tonumber(month) then month = date_words.months[tonumber(month)] or "" month = month:gsub("^%l", string.upper) or "" end if month == date_ending then month = "" end if year == date_ending then year = "" end return circa_ending .. " " .. day .. " " .. month .. " " .. year .. " " .. date_ending end

return p