Module:Time ago/sandbox

From blackwiki
< Module:Time ago
Revision as of 03:55, 13 April 2019 by blackwiki>Johnuniq (tweaks; lazy load of two modules; change seconds in a month based on average over four years—will sometimes give bad result, perhaps less often than current situation)
Jump to navigation Jump to search

Documentation for this module may be created at Module:Time ago/sandbox/doc

-- Replacement for [[Template:Time ago]]

local numberSpell, yesno  -- lazily load

function numberSpell(arg)
	numberSpell = require('Module:NumberSpell')._main
	return numberSpell(arg)
end

function yesno(arg)
	yesno = require('Module:Yesno')
	return yesno(arg)
end

local p = {}

-- Table to convert entered text values to numeric values.
local timeText = {
	['seconds'] = 1,
	['minutes'] = 60,
	['hours'] = 3600,
	['days'] = 86400,
	['weeks'] = 604800,
	['months'] = 2629800,  -- 365.25 * 24 * 60 * 60 / 12
	['years'] = 31557600
}

-- Table containing tables of possible units to use in output.
local timeUnits = {
	[1] = { 'second', 'seconds', "second's", "seconds'" },
	[60] = { 'minute', 'minutes', "minutes'", "minutes'" },
	[3600] = { 'hour', 'hours', "hour's", "hours'" },
	[86400] = { 'day', 'days', "day's", "days'" },
	[604800] = { 'week', 'weeks', "week's", "weeks'" },
	[2629800] = { 'month', 'months', "month's", "months'" },
	[31557600] = { 'year', 'years', "year's", "years'" }
}

function p._main( args )
	-- Initialize variables
	local lang = mw.language.getContentLanguage()
	local auto_magnitude_num
	local min_magnitude_num
	local magnitude = args.magnitude
	local min_magnitude = args.min_magnitude
	local purge = args.purge
	local spell_out = args.spellout
	local spell_out_max = args.spelloutmax

	-- Add a purge link if something (usually "yes") is entered into the purge parameter
	if purge then
		purge = ' <span class="plainlinks">([' .. mw.title.getCurrentTitle():fullUrl('action=purge') .. ' purge])</span>'
	else
		purge = ''
	end

	-- Check that the entered timestamp is valid. If it isn't, then give an error message.
	local success, inputTime = pcall( lang.formatDate, lang, 'U', args[1], true )
	if not success then
		return '<strong class="error">Error: first parameter cannot be parsed as a date or time.</strong>'
	end

	-- Store the difference between the current time and the inputted time, as well as its absolute value.
	local timeDiff = lang:formatDate( 'U', nil, true ) - inputTime
	local absTimeDiff = math.abs( timeDiff )

	if magnitude then
		auto_magnitude_num = 0
		min_magnitude_num = timeText[magnitude]
	else
		-- Calculate the appropriate unit of time if it was not specified as an argument.
		local autoMagnitudeData = {
			{ factor = 2, amn = 31557600 },
			{ factor = 2, amn = 2629800 },
			{ factor = 2, amn = 86400 },
			{ factor = 2, amn = 3600 },
			{ factor = 2, amn = 60 }
		}
		for _, t in ipairs( autoMagnitudeData ) do
			if absTimeDiff / t.amn >= t.factor then
				auto_magnitude_num = t.amn
				break
			end
		end
		auto_magnitude_num = auto_magnitude_num or 1
		if min_magnitude then
			min_magnitude_num = timeText[min_magnitude]
		else
			min_magnitude_num = -1
		end
	end

	if not min_magnitude_num then
		-- Default to seconds if an invalid magnitude is entered.
		min_magnitude_num = 1
	end

	local magnitude_num = math.max( min_magnitude_num, auto_magnitude_num )
	local result_num = math.floor ( absTimeDiff / magnitude_num )

	local punctuation_key, suffix
	if timeDiff >= 0 then -- Past
		if result_num == 1 then
			punctuation_key = 1
		else
			punctuation_key = 2
		end
		if args.ago == '' then
			suffix = ''
		else
			suffix = ' ' .. (args.ago or 'ago')
		end
	else -- Future
		if args.ago == '' then
			suffix = ''
			if result_num == 1 then
				punctuation_key = 1
			else
				punctuation_key = 2
			end
		else
			suffix = ' time'
			if result_num == 1 then
				punctuation_key = 3
			else
				punctuation_key = 4
			end
		end
	end
	local result_unit = timeUnits[ magnitude_num ][ punctuation_key ]

	-- Convert numerals to words if appropriate.
	spell_out_max = tonumber( spell_out_max ) -- Would cause script errors if not a number.
	local result_num_text
	if ( spell_out == 'auto' and 1 <= result_num and result_num <= 9 and result_num <= ( spell_out_max or 9 ) )
		or ( yesno( spell_out ) and 1 <= result_num and result_num <= 100 and result_num <= ( spell_out_max or 100 ) )
	then
		result_num_text = numberSpell( result_num )
	else
		result_num_text = tostring( result_num )
	end

	local result = result_num_text .. ' ' .. result_unit .. suffix -- Spaces for suffix have been added in earlier.
	return result .. purge
end

function p.main( frame )
	local args = require( 'Module:Arguments' ).getArgs( frame, {
		valueFunc = function( k, v )
			if v then
				v = v:match( '^%s*(.-)%s*$' ) -- Trim whitespace.
				if k == 'ago' or v ~= '' then
					return v
				end
			end
			return nil
		end,
		wrappers = 'Template:Time ago'
	})
	return p._main( args )
end

return p