Halo Esports Wiki

We are currently performing extensive maintenance to this wiki and as a result there will likely be errors. Please be patient while we work to fix all problems.

READ MORE

Halo Esports Wiki
Advertisement

Documentation for this module may be created at Module:TimedeltaAbstract/doc

local util_args = require("Module:ArgsUtil")
local util_table = require("Module:TableUtil")
local util_time = require("Module:TimeUtil")
local util_vars = require("Module:VarsUtil")
local LCS = require('Module:LuaClassSystem')

local p = LCS.class.abstract()
local h = {}

p.DAYS_PER_MONTH = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }

function p:main(s, e, fuzzy)
	-- expect string inputs
	local sDate = util_time.strToDateFuzzy(s)
	local eDate = util_time.strToDateFuzzy(e)
	if not sDate.year or not eDate.year then
		return self.outputUnknown
	end
	if not sDate.month or not eDate.month then
		return self:approxDurationFuzzyMonth(sDate, eDate)
	end
	if not sDate.day or not eDate.day then
		return self:approxDurationFuzzyDay(sDate, eDate)
	end
	return self:addFuzzyPrefixIffNeeded(self:approxDurationExact(sDate, eDate), fuzzy)
end

function p:approxDurationFuzzyMonth(sDate, eDate)
	if sDate.year >= eDate.year - 1 then
		return self:approxDurationFuzzyMonthSameYear(sDate, eDate) .. self.clarifyApprox
	end
	if not sDate.month then
		sDate.month = 7
		sDate.day = eDate.day or 1
	end
	if not eDate.day then
		eDate.month = 7
		eDate.day = sDate.day or 1
	end
	return self.fuzzyPrefix .. self:approxDurationExact(sDate, eDate)
end

function p:approxDurationFuzzyMonthSameYear(sDate, eDate)
	if (not sDate.month or sDate.month == 1) and (not eDate.month or eDate.month == 12) then
		return self.lessThanOneYear
	end
	sDate.month = sDate.month or 1
	eDate.month = eDate.month or 12
	sDate.day = sDate.day or eDate.day or 1
	eDaysPerMonth = h.getDaysPerMonth(eDate)
	eDate.day = eDate.day or sDate.day or eDaysPerMonth[eDate.month]
	return self.lessThan .. self:approxDurationExact(sDate, eDate)
end

function p:approxDurationFuzzyDay(sDate, eDate)
	if sDate.month == eDate.month then
		return self:approxDurationFuzzyDaySameMonth(sDate, eDate)
	end
	if not sDate.day and not eDate.day then
		-- since February rounds differently, and if we don't know either day we want to say just 1 month
		-- in this case just "cheat" and assign both as 1 instead of dealing with midpoint differences
		sDate.day = 1
		eDate.day = 1
	elseif not sDate.day then
		sDate.day = sDate.month == 2 and 14 or 15
	elseif not eDate.day then
		eDate.day = eDate.month == 2 and 14 or 15
	end
	return self.fuzzyPrefix .. self:approxDurationExact(sDate, eDate)
end

function p:addFuzzyPrefixIffNeeded(output, fuzzy)
	if not util_args.castAsBool(fuzzy) then return output end
	if output:find('≈') then return output end
	return '≈' .. output
end

function p:approxDurationFuzzyDaySameMonth(sDate, eDate)
	local eDaysPerMonth = h.getDaysPerMonth(eDate)
	if (not sDate.day or sDate.day == 1) and (not eDate.day or eDate.day == eDaysPerMonth[eDate.month]) then
		return self:lessThanOneMonth(eDaysPerMonth[eDate.month])
	end
	if not sDate.day then sDate.day = 1 end
	if not eDate.day then
		eDate.day = eDaysPerMonth[eDate.month]
	end
	return self.lessThan .. self:approxDurationExact(sDate, eDate)
end

function p:lessThanOneMonth(month) end

function p:approxDurationExact(sDate, eDate)
	local numberOfYears = h.getYearDiff(sDate, eDate)
	local numberOfMonths = h.getMonthDiff(sDate, eDate)
	local numberOfDays = h.getDayDiff(sDate, eDate)
	local tbl = {
		h.printNumberOfYears(numberOfYears),
		h.printNumberOfMonths(numberOfMonths),
		h.printNumberOfDays(numberOfYears, numberOfMonths, numberOfDays),
	}
	util_table.removeFalseEntries(tbl)
	return table.concat(tbl, ' ')
end

function h.getYearDiff(sDate, eDate)
	local monthOffset = eDate.month >= sDate.month and 0 or 1
	return eDate.year - sDate.year - monthOffset
end

function h.getMonthDiff(sDate, eDate)
	if not eDate.day then
		error(('Missing day input in end: %s'):format(e))
	end
	if not sDate.day then
		error(('Missing day input in start: %s'):format(s))
	end
	local dayOffset = eDate.day >= sDate.day and 0 or 1
	if eDate.month >= sDate.month then
		return eDate.month - sDate.month - dayOffset
	end
	return 12 - (sDate.month - eDate.month) - dayOffset
end

function h.getDayDiff(sDate, eDate)
	if eDate.day >= sDate.day then
		return eDate.day - sDate.day
	end
	local sDaysPerMonth = h.getDaysPerMonth(sDate)
	return sDaysPerMonth[sDate.month] - (sDate.day - eDate.day)
end

function h.getDaysPerMonth(date)
	local ret = mw.clone(p.DAYS_PER_MONTH)
	if date.month ~= 2 then return ret end
	if math.floor(date.year / 1000) == date.year / 1000 then
		ret[2] = 29
		return ret
	end
	if math.floor(date.year / 100) == date.year / 100 then
		return ret
	end
	if math.floor(date.year / 4) ~= date.year / 4 then
		return ret
	end
	ret[2] = 29
	return ret
end

function h.printNumberOfYears(numberOfYears)
	if numberOfYears <= 0 then return false end
	return ('%syr'):format(numberOfYears)
end

function h.printNumberOfMonths(numberOfMonths)
	if numberOfMonths <= 0 then return false end
	return ('%smo'):format(numberOfMonths)
end

function h.printNumberOfDays(numberOfYears, numberOfMonths, numberOfDays)
	if numberOfYears > 0 and numberOfMonths > 0 then return false end
	if numberOfDays <= 0 then return '' end
	return ('%sd'):format(numberOfDays)
end
return p
Advertisement