Module:Sandbox/N3rsti/Dates

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'} }

-- Detect day, month, year and format function detect_date(date_text) -- Variables setup local date_sign = "[^%s]+" local sign = "" local date_table = {} 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 local index={} for k,v in pairs(date_table) do	  index[v]=k end -- Date detection if date_sign == "[^%/]+" then sign = "/" elseif date_sign == "[^%-]+" then sign = "-" end if date_sign == "[^%/]+" or date_sign == "[^%-]+" then day, month, year = string.match(date_text, "(%d+)".. sign .. "(%d+)" .. sign .. "(%d+)") if #day > 2 then return {day=year, month=month, year=day, sign=sign} end return {day=day, month=month, year=year, sign=sign}

else for _, ending in pairs(date_words.number_endings) do day, month, year = string.match(date_text, "(%d+)" .. ending .. " (%w+) (%d+)") if day then return {day=day, month=month, year=year} end day, month, year = string.match(date_text, "(%d+) (%w+) (%d+)") if day then return {day=day, month=month, year=year} end break end end for month=1, #date_words.months do		if string.match(string.lower(date_text), date_words.months[month]) or string.match(string.lower(date_text), date_words.short_months[month]) then local selected_month = date_words.months[month] local month_index = index[selected_month] -- Gets index of month name if string.match(date_text, ",") then month, day, year = string.match(date_text, "(%w+) (%d+), (%d+)") else day, month, year = string.match(date_text, "(%d+) (%w+) (%d+)") -- Month is nil when pattern didn't work so there are 2 options in this case: dmy or my				if not month then for _, ending in pairs(date_words.number_endings) do day, month, year = string.match(date_text, "(%d+)" .. ending .. "(%w+) (%d+)") if day then return {day=day, month=month, year=year} end break end month, year = string.match(date_text, "(%w+) (%d+)") if not month then day, month = string.match(date_text, "(%d+) (%w+)") month = month:gsub("^%l", string.upper) return {day=day, month=month} end month = month:gsub("^%l", string.upper) return {month=month, year=year} end end month = month:gsub("^%l", string.upper) return {day=day, month=month, year=year} end end day, month, year = string.match(date_text, "(%d+) (%w+) (%d+)") if day then return {day=day, month=month, year=year} end end

-- Formatting date function function p.format_date(frame) local date_format = frame.args.format or "" local date_text = frame.args.date or "" local circa_message, out, date_ending = "" local is_valid = false if date_text == "" then return "No parameter supplied" end local date_sign = "[^%s]+" local sign = "" local date_table = {} 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 _, ending in pairs(date_words.accepted_endings) do		if string.match(date_text, ending) then is_valid = true date_ending = ending break end end date_ending = date_ending or "" 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 is_valid = true month = date_words.months[month_num] break end end for _, ending in pairs(date_words.number_endings) do		if string.sub(string.lower(date_text), #ending) == ending then is_valid = true break end end for _, message in pairs(date_words.circa_words) do		if string.match(string.lower(date_text), message) then circa_message = "circa " is_valid = true end end

for _, word in pairs(date_words.accepted_words) do		if string.match(string.lower(date_text), word) then is_valid = true end end

if detect_date(date_text) and (detect_date(date_text).sign == "/" or detect_date(date_text).sign == "-") and date_format == "" then date_format = "iso" end if date_format == "iso" then local month = detect_date(date_text).month if not tonumber(month) then local index={} for k,v in pairs(date_words.months) do			  index[v]=k end month = index[string.lower(month)] local months_days = date_words.months_days[month] end local months_days = date_words.months_days[month] local day = detect_date(date_text).day or "" return circa_message .. (detect_date(date_text).year .. "-" .. month .."-" .. day) .. " " .. date_ending elseif date_format == "mdy" then local month = detect_date(date_text).month local month_num = month if not tonumber(month) then local index={} for k,v in pairs(date_words.months) do			  index[v]=k end month_num = index[string.lower(month)] else month = date_words.months[tonumber(month_num)] end months_days = date_words.months_days[tonumber(month_num)] if tonumber(detect_date(date_text).year) % 4 == 0 then months_days = months_days + 1 end if months_days < tonumber(detect_date(date_text).day) then return "Invalid entry" end month = month:gsub("^%l", string.upper) return circa_message .. (month .. " " .. detect_date(date_text).day ..", " .. detect_date(date_text).year) .. " " .. date_ending elseif date_format == "year" then return circa_message .. detect_date(date_text).year .. " " .. date_ending end local is_number = true if not is_valid then for _, date_word in pairs(date_table) do			if not tonumber(date_word) then is_number = false break end end end if not is_valid and tonumber(date_text) then return date_text elseif is_number then local day, month, year, ending = string.match(date_text, "(%d+) (%w+) (%d+)") if month then for counter, short_month in pairs(date_words.short_months) do				for _, word in pairs(date_table) do					if string.lower(word) == short_month then selected_month = date_words.months[counter] break end end end if selected_month then month_capitalize = selected_month:gsub("^%l", string.upper) date_text = string.gsub(date_text, month, month_capitalize) else month_capitalize = month:gsub("^%l", string.upper) date_text = string.gsub(date_text, month, month_capitalize) end return circa_message .. date_text end for _, word in pairs(date_table) do			for _, num_ending in pairs(date_words.number_endings) do if string.match(word, "(%d+)" .. num_ending) then day = string.gsub(word, num_ending, "") break end end 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 is_valid = true month = date_words.months[month_num] break end end month = month or "" month = month:gsub("^%l", string.upper) _, year = string.match(date_text, "(.+) (%d+)") year = year or "" day = day or date_text if year == month then month = "" end day_table = {} for word in string.gmatch(day, date_sign) do			table.insert(day_table, word) end day_table[1] = day_table[1] or "" return circa_message .. day_table[1] .. " " .. month .. " " .. year .. " " .. date_ending end if not is_valid then return "Invalid entry" end end

return p