Modul:Time interval
--[[ Calculate date and time intervals by invoking Module Date
Currently only provides age in years (age_years) for tests.
Planned to replace various age-related templates, for example:
{{Age in days}} age_days
{{Age in years and months}} age_ym
{{Gregorian serial date}} gsd_ymd
]]
local Date = require('Module:Date')._Date
local MINUS = '−' -- Unicode U+2212 MINUS SIGN
local function number_name(number, singular, plural, sep)
-- Return the given number, converted to a string, with the
-- separator (default space) and singular or plural name appended.
plural = plural or (singular .. 's')
sep = sep or ' '
return tostring(number) .. sep .. ((number == 1) and singular or plural)
-- this uses an interesting trick of Lua:
-- * and reurns false if the first argument is false, and the second otherwise, so (number==1) and singular returns singular if its 1, returns false if it is only 1
-- * or returns the first argument if it is not false, and the second argument if the first is false
-- * so, if number is 1, and evaluates (true and singular) returning (singular); or evaluates (singular or plural), finds singular non-false, and returns singular
-- * but, if number is not 1, and evaluates (false and singular) returning (false); or evaluates (false or plural), and is forced to return plural
end
local function strip_to_nil(text)
-- If text is a non-blank string, return its content with no leading
-- or trailing whitespace.
-- Otherwise return nil (a nil or empty string argument gives a nil
-- result, as does a string argument of only whitespace).
if type(text) == 'string' then
local result = text:match("^%s*(.-)%s*$")
if result ~= '' then
return result
end
end
return nil
end
local function show_args(frame)
local args = frame:getParent().args
local out = ''
for k, v in pairs(args) do
v = strip_to_nil(v)
out = out .. k .. '=' .. (v or 'nil') .. ', '
end
return '<span style="color:black; background-color:#cfc;">' .. 'Received arguments: <br/>' .. out .. '</span>'
end
local function error_wikitext(text)
-- Return message for display when template parameters are invalid.
local prefix = '[[Module talk:Time interval|Module error]]:'
local cat = '[[Category:Error in time interval]]'
return '<span style="color:black; background-color:pink;">' ..
prefix .. ' ' .. text .. cat .. '</span>'
end
local function time_interval(frame)
-- Compute date and time interval between two given dates,
-- or between given date and current date.
local args = frame:getParent().args
local fields = {}
local date1, date2
for i = 1, 2 do
fields[i] = strip_to_nil(args[i])
end
if fields[1] then
date1 = Date(fields[1])
if not date1 then
return error_wikitext('Invalid start date in first parameter')
end
end
if fields[2] then
date2 = Date(fields[2])
if not date2 then
return error_wikitext('Invalid end date in second parameter')
end
else
date2 = Date('currentdatetime')
end
interval = date2 - date1
return interval
end
local function age_years(frame)
-- Formats time interval as an age in years
-- Default shows "15 years"
-- Option disp=raw suppresses unit --> "15"
-- Option disp=age adds " old" --> "15 years old"
local args = frame:getParent().args
local out
local interval = time_interval(frame)
if interval and interval.years then
if args.disp == 'raw' then
out = tostring(interval.years)
else
out = number_name(interval.years, 'year')
end
if args.disp == 'age' then
out = out .. ' old'
end
else
out = ''
end
if frame.args.verbose then
out = out .. '<br/>' .. show_args(frame)
end
return out
end
local function age_generic(frame)
-- Formats time interval as a generic age
-- Default shows "15 years"
-- Option disp=raw suppresses unit --> "15"
-- Option disp=age adds " old" --> "15 years old"
-- Ages under 3 include years and months
-- Ages under 1 include months and days
local args = frame:getParent().args
local out
local interval = time_interval(frame)
if interval and interval.years then
if args.disp == 'raw' then
out = tostring(interval.years)
else
out = number_name(interval.years, 'year')
end
if interval.years < 1 then
if interval.months > 0 then
out = number_name(interval.months, 'month')
else
out = '' -- don't display 0 year and 0 month
end
out = out .. ' ' .. number_name(interval.days, 'day')
elseif interval.years < 3 then
out = out .. ' ' .. number_name(interval.months, 'month')
end
if args.disp == 'age' then
out = out .. ' old'
end
else
out = ''
end
if frame.args.verbose then
out = out .. '<br/>' .. show_args(frame)
end
return out
end
return { age_years = age_years, age = age_generic }