Module:Sandbox/Nathan fraignt/Dates

Revision as of 11:11, 10 November 2018 by imported>Nathan fraignt
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

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