Module:Time ago: Difference between revisions
Appearance
Content deleted Content added
fix unintended globals per Template talk:Time ago#Template-protected edit request on 26 March 2018 |
update from Module:TimeAgo/sandbox per WT:Lua#Module:TimeAgo's calculations sometimes off by a week: tweaks + accurate results for weeks/months/years with little extra overhead |
||
Line 1: | Line 1: | ||
-- |
-- Implement [[Template:Time ago]] |
||
⚫ | |||
local yesno |
local numberSpell, yesno -- lazy load |
||
function numberSpell(arg) |
|||
⚫ | |||
return numberSpell(arg) |
|||
end |
|||
function yesno(arg) |
|||
yesno = require('Module:Yesno') |
|||
return yesno(arg) |
|||
end |
|||
local p = {} |
local p = {} |
||
Line 12: | Line 22: | ||
['days'] = 86400, |
['days'] = 86400, |
||
['weeks'] = 604800, |
['weeks'] = 604800, |
||
['months'] = |
['months'] = 2629800, -- 365.25 * 24 * 60 * 60 / 12 |
||
['years'] = 31557600 |
['years'] = 31557600 |
||
} |
} |
||
Line 22: | Line 32: | ||
[3600] = { 'hour', 'hours', "hour's", "hours'" }, |
[3600] = { 'hour', 'hours', "hour's", "hours'" }, |
||
[86400] = { 'day', 'days', "day's", "days'" }, |
[86400] = { 'day', 'days', "day's", "days'" }, |
||
[604800] = { 'week', 'weeks', "week's", "weeks'" }, |
[604800] = { 'week', 'weeks', "week's", "weeks'", unit = 'w' }, |
||
[ |
[2629800] = { 'month', 'months', "month's", "months'", unit = 'm' }, |
||
[31557600] = { 'year', 'years', "year's", "years'" } |
[31557600] = { 'year', 'years', "year's", "years'", unit = 'y' } |
||
} |
} |
||
Line 32: | Line 42: | ||
local auto_magnitude_num |
local auto_magnitude_num |
||
local min_magnitude_num |
local min_magnitude_num |
||
⚫ | |||
local result_unit |
|||
local magnitude = args.magnitude |
local magnitude = args.magnitude |
||
local min_magnitude = args.min_magnitude |
local min_magnitude = args.min_magnitude |
||
local purge = args.purge |
local purge = args.purge |
||
⚫ | |||
⚫ | |||
-- Add a purge link if something (usually "yes") is entered into the purge parameter |
-- Add a purge link if something (usually "yes") is entered into the purge parameter |
||
Line 48: | 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 |
local success, inputTime = pcall( lang.formatDate, lang, 'xnU', args[1] ) |
||
if not |
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( ' |
local timeDiff = lang:formatDate( 'xnU' ) - inputTime |
||
local absTimeDiff = math.abs( timeDiff ) |
local absTimeDiff = math.abs( timeDiff ) |
||
Line 63: | Line 69: | ||
-- 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 = { |
local autoMagnitudeData = { |
||
{ |
{ factor = 2, amn = 31557600 }, |
||
{ |
{ factor = 2, amn = 2629800 }, |
||
{ |
{ factor = 2, amn = 86400 }, |
||
{ |
{ factor = 2, amn = 3600 }, |
||
{ |
{ factor = 2, amn = 60 } |
||
} |
} |
||
for |
for _, t in ipairs( autoMagnitudeData ) do |
||
if absTimeDiff / t. |
if absTimeDiff / t.amn >= t.factor then |
||
auto_magnitude_num = t.amn |
auto_magnitude_num = t.amn |
||
break |
break |
||
Line 88: | Line 94: | ||
end |
end |
||
⚫ | |||
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 |
|||
⚫ | |||
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 |
|||
⚫ | |||
local punctuation_key, suffix |
local punctuation_key, suffix |
||
Line 120: | Line 142: | ||
end |
end |
||
end |
end |
||
result_unit = timeUnits[ magnitude_num ][ punctuation_key ] |
local result_unit = timeUnits[ magnitude_num ][ punctuation_key ] |
||
-- Convert numerals to words if appropriate. |
-- 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 |
local result_num_text |
||
if ( spell_out == 'auto' and 1 <= result_num and result_num <= 9 and result_num <= ( spell_out_max or 9 ) ) |
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 |
then |
||
result_num_text = numberSpell( result_num ) |
result_num_text = numberSpell( result_num ) |
||
Line 133: | Line 158: | ||
end |
end |
||
result = result_num_text .. ' ' .. result_unit .. suffix -- Spaces for suffix have been added in earlier. |
local result = result_num_text .. ' ' .. result_unit .. suffix -- Spaces for suffix have been added in earlier. |
||
return result .. purge |
return result .. purge |
||
end |
end |
Revision as of 07:23, 18 April 2019
![]() | This module is rated as ready for general use. It has reached a mature form and is thought to be relatively bug-free and ready for use wherever appropriate. It is ready to mention on help pages and other Wikipedia resources as an option for new users to learn. To reduce server load and bad output, it should be improved by sandbox testing rather than repeated trial-and-error editing. |
![]() | This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
![]() | This Lua module is used on approximately 188,000 pages. To avoid major disruption and server load, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Consider discussing changes on the talk page before implementing them. |
The module “Time ago” implements {{Time ago}}. See the template's page for documentation. Test cases can be found at Template:Time ago/testcases.
-- 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
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