Jump to content

Module:Sandbox/Deimos18/Dates

From Wikipedia, the free encyclopedia

This is the current revision of this page, as edited by Deimos18 (talk | contribs) at 22:52, 13 November 2018. The present address (URL) is a permanent link to this version.

(diff) ← Previous revision | Latest revision (diff) | Newer revision → (diff)
-- 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