Module:Time ago: Difference between revisions

Nothing to hide, but nothing to show you either.
Jump to navigation Jump to search
Content added Content deleted
(see if we can do away with all of those math.floor calls)
m (33 revisions imported from wikipedia:Module:Time_ago)
 
(13 intermediate revisions by 5 users not shown)
Line 1: Line 1:
-- Replacement for [[Template:Time ago]]
-- Implement [[Template:Time ago]]
local getArgs = require('Module:Arguments').getArgs


local p = {}
local numberSpell, yesno -- lazy load


function p.main( frame )
function numberSpell(arg)
numberSpell = require('Module:NumberSpell')._main
local args = getArgs( frame )
return p._main( args )
return numberSpell(arg)
end
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'", unit = 'w' },
[2629800] = { 'month', 'months', "month's", "months'", unit = 'm' },
[31557600] = { 'year', 'years', "year's", "years'", unit = 'y' }
}


function p._main( args )
function p._main( args )
Line 14: Line 42:
local auto_magnitude_num
local auto_magnitude_num
local min_magnitude_num
local min_magnitude_num
local result
local result_unit
local magnitude = args.magnitude
local magnitude = args.magnitude
local min_magnitude = args.min_magnitude
local min_magnitude = args.min_magnitude
local ago = args.ago or 'ago'
local purge = args.purge
local purge = args.purge


Line 29: Line 54:


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


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


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


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


local result_num
local magnitude_num = math.max( min_magnitude_num, auto_magnitude_num )
local magnitude_num = math.max( min_magnitude_num, auto_magnitude_num )
local unit = timeUnits[magnitude_num].unit
local result_num = math.floor ( absTimeDiff / magnitude_num )
if unit and absTimeDiff >= 864000 then
local Date = require('Module:Date')._Date
local input = lang:formatDate('Y-m-d H:i:s', args[1]) -- Date needs a clean date
input = Date(input)
if input then
local id
if input.hour == 0 and input.minute == 0 then
id = 'currentdate'
else
id = 'currentdatetime'
end
result_num = (Date(id) - input):age(unit)
end
end
result_num = result_num or math.floor ( absTimeDiff / magnitude_num )


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

-- Convert numerals to words if appropriate.
local spell_out = args.spellout
local spell_out_max = tonumber(args.spelloutmax)
local result_num_text
if spell_out and (
( 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
-- numeric or string
local numeric_out = args.numeric
local result = ""
if numeric_out then
result = tostring( result_num )
else
result = result_num_text .. ' ' .. result_unit .. suffix -- Spaces for suffix have been added in earlier.
end
end


Line 93: Line 170:
end
end


function p.main( frame )
-- Table to convert entered text values to numeric values.
local args = require( 'Module:Arguments' ).getArgs( frame, {
timeText = {
valueFunc = function( k, v )
['seconds'] = 1,
if v then
['minutes'] = 60,
v = v:match( '^%s*(.-)%s*$' ) -- Trim whitespace.
['hours'] = 3600,
if k == 'ago' or v ~= '' then
['days'] = 86400,
return v
['weeks'] = 604800,
end
['months'] = 2678400,
end
['years'] = 31557600
return nil
}
end,

wrappers = 'Template:Time ago'
-- Table containing tables of possible units to use in output.
})
timeUnits = {
return p._main( args )
[1] = { 'second', 'seconds', 'second\'s', 'seconds\'' },
end
[60] = { 'minute', 'minutes', 'minute\'s', 'minutes\'' },
[3600] = { 'hour', 'hours', 'hour\'s', 'hours\'' },
[86400] = { 'day', 'days', 'day\'s', 'days\'' },
[604800] = { 'week', 'weeks', 'week\'s', 'weeks\'' },
[2678400] = { 'month', 'months', 'month\'s', 'months\'' },
[31557600] = { 'year', 'years', 'year\'s', 'years\'' }
}


return p
return p

Latest revision as of 23:24, 7 June 2021

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

-- Implement [[Template:Time ago]]

local numberSpell, yesno  -- lazy 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'", unit = 'w' },
	[2629800] = { 'month', 'months', "month's", "months'", unit = 'm'  },
	[31557600] = { 'year', 'years', "year's", "years'", unit = 'y'  }
}

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

	-- 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, 'xnU', args[1] )
	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( 'xnU' ) - 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 result_num
	local magnitude_num = math.max( min_magnitude_num, auto_magnitude_num )
	local unit = timeUnits[magnitude_num].unit
	if unit and absTimeDiff >= 864000 then
		local Date = require('Module:Date')._Date
		local input = lang:formatDate('Y-m-d H:i:s', args[1])  -- Date needs a clean date
		input = Date(input)
		if input then
			local id
			if input.hour == 0 and input.minute == 0 then
				id = 'currentdate'
			else
				id = 'currentdatetime'
			end
			result_num = (Date(id) - input):age(unit)
		end
	end
	result_num = result_num or 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.
	local spell_out = args.spellout
	local spell_out_max = tonumber(args.spelloutmax)
	local result_num_text
	if spell_out and (
		( 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
	
	-- numeric or string
	local numeric_out = args.numeric
	local result = ""
	if numeric_out then
		result = tostring( result_num )
	else
		result = result_num_text .. ' ' .. result_unit .. suffix -- Spaces for suffix have been added in earlier.
	end

	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