--[[
* Modulo per eseguire operazioni sulle date.
* Utilizzato da template come {{Età wikipediana}} e {{Tempo trascorso}}.
]]
local getArgs = require('Modulo:Arguments').getArgs
require('Modulo:No globals')
-------------------------------------------------------------------------------
-- Funzioni di utilità
-------------------------------------------------------------------------------
local function isValidDate(date)
return pcall(function() mw.getContentLanguage():formatDate('', date) end)
end
-- Controlla args.inizio e args.fine e li ritorna in Unix time
local function parseArgs(args)
if not args.inizio then
error('la data di partenza è obbligatoria', 2)
elseif not isValidDate(args.inizio) then
error('la data di partenza non è valida', 2)
elseif not args.fine then
error('la data di arrivo è obbligatoria', 2)
elseif not isValidDate(args.fine) then
error('la data di arrivo non è valida', 2)
end
return {
d1_ut = tonumber(mw.getContentLanguage():formatDate('U', args.inizio, true)),
d2_ut = tonumber(mw.getContentLanguage():formatDate('U', args.fine, true))
}
end
-- Error handler per xpcall, formatta l'errore
local function errhandler(msg)
return string.format('<span class="error">Errore: %s</span>', msg)
end
-- Aggiunge un eventuale prefisso e suffisso al risultato invece del segno.
-- L'ultimo parametro diffVal è utilizzato solo da dateDiff per evitare che
-- {{#invoke:Data|diff|inizio=2016/01/01|fine=2015/12/31|magnitudine=anni}} ritorni "-0 anni".
local function formatResult(result, d1_ut, d2_ut, dir, diffVal)
local ret
if dir then
-- ritorna il 'fa' anche con d1_ut == d2_ut (si potrebbe configurare con un parametro)
ret = d1_ut < d2_ut and 'tra ' .. result or result .. ' fa'
else
ret = (d1_ut <= d2_ut or diffVal == 0) and result or '-' .. result
end
return ret
end
-------------------------------------------------------------------------------
-- dateDiffYMD
-------------------------------------------------------------------------------
-- Ritorna la differenza in anni, mesi e giorni tra le date d1_ut e d2_ut (Unix time).
-- Se rawTable è true ritorna una table con le chiavi: year, month, day, seconds.
local function dateDiffYMD(d1_ut, d2_ut, rawTable, dir)
local monthdays = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
local d1, d2 = os.date('*t', d1_ut), os.date('*t', d2_ut)
local ret = { seconds = math.abs(d1_ut - d2_ut) }
if d1_ut >= d2_ut then d1, d2 = d2, d1 end
-- anni
ret.years = d2.year - d1.year
if ret.years > 0 and (d1.month > d2.month or (d1.month == d2.month and d1.day > d2.day)) then
ret.years = ret.years - 1
end
-- mesi
ret.months = (d2.month - d1.month + 12) % 12
if d1.day > d2.day then
ret.months = (ret.months == 0 and d1.year < d2.year) and 11 or ret.months - 1
end
-- giorni
ret.days = d2.day >= d1.day and d2.day - d1.day or (monthdays[d1.month] - d1.day) + d2.day
-- utilizza la sequence per ritornare anche la versione testuale
if ret.years > 0 then
table.insert(ret, string.format('%s %s', ret.years, ret.years == 1 and 'anno' or 'anni'))
end
if ret.months > 0 then
table.insert(ret, string.format('%s %s', ret.months, ret.months == 1 and 'mese' or 'mesi'))
end
if ret.days > 0 or ret.years + ret.months + ret.days == 0 then
table.insert(ret, string.format('%s %s', ret.days, ret.days == 1 and 'giorno' or 'giorni'))
end
return rawTable and ret or formatResult(mw.text.listToText(ret, ', ', ' e '), d1_ut, d2_ut, dir)
end
-------------------------------------------------------------------------------
-- dateDiff
-------------------------------------------------------------------------------
-- Funzione di utilità per dateDiff
local function getMagnitudine(diff, magnitudine_min)
local units = {
secondi = 0, minuti = 1, ore = 2, giorni = 3, settimane = 4, mesi = 5, anni = 6
}
local ret
if diff.seconds < 120 then -- minore di due minuti
ret = 'secondi'
elseif diff.seconds < 7200 then -- minore di due ore
ret = 'minuti'
elseif diff.seconds < 172800 then -- minore di due giorni
ret = 'ore'
elseif diff.years == 0 and diff.months < 2 then -- minore di due mesi
ret = 'giorni'
elseif diff.years < 2 then -- minore di due anni
ret = 'mesi'
else
ret = 'anni'
end
-- utilizzo di magnitudine_min (il valore minimo quando è automatica)
if magnitudine_min and units[magnitudine_min] then
ret = units[magnitudine_min] > units[ret] and magnitudine_min or ret
end
return ret
end
-- Funzione di utilità per dateDiff
local function convert(seconds, unit, text, text2)
local ret = math.floor(seconds / unit)
return ret, string.format('%s %s', ret, ret == 1 and text or text2)
end
-- Ritorna la differenza tra le date d1 e d2 (Unix time) in solo una tra le unità:
-- anni, mesi, settimane, giorni, ore, minuti e secondi.
local function dateDiff(d1_ut, d2_ut, magnitudine, magnitudine_min, dir)
local diff, ret, val, result
diff = dateDiffYMD(d1_ut, d2_ut, true)
magnitudine = magnitudine or getMagnitudine(diff, magnitudine_min)
if magnitudine == 'secondi' then
val, result = convert(diff.seconds, 1, 'secondo', 'secondi')
elseif magnitudine == 'minuti' then
val, result = convert(diff.seconds, 60, 'minuto', 'minuti')
elseif magnitudine == 'ore' then
val, result = convert(diff.seconds, 3600, 'ora', 'ore')
elseif magnitudine == 'giorni' then
val, result = convert(diff.seconds, 86400, 'giorno', 'giorni')
elseif magnitudine == 'settimane' then
val, result = convert(diff.seconds, 604800, 'settimana', 'settimane')
elseif magnitudine == 'mesi' then
val = diff.years * 12 + diff.months
result = string.format('%s %s', val, val == 1 and 'mese' or 'mesi')
else
val = diff.years
result = string.format('%s %s', diff.years, diff.years == 1 and 'anno' or 'anni')
end
return formatResult(result, d1_ut, d2_ut, dir, val)
end
-------------------------------------------------------------------------------
-- API
-------------------------------------------------------------------------------
local p = {}
-- Per utilizzare diff da un altro modulo.
function p._diff(args)
local success, result = xpcall(function() return parseArgs(args) end, errhandler)
return success and dateDiff(result.d1_ut, result.d2_ut, args.magnitudine, args['magnitudine min'], args.dir) or result
end
-- Per utilizzare diff_ymd da un altro modulo.
function p._diff_ymd(args)
local success, result = xpcall(function() return parseArgs(args) end, errhandler)
return success and dateDiffYMD(result.d1_ut, result.d2_ut, false, args.dir) or result
end
-- Entry point per {{#invoke:Data|diff}}
function p.diff(frame)
return p._diff(getArgs(frame))
end
-- Entry point per {{#invoke:Data|diff_ymd}}
function p.diff_ymd(frame)
return p._diff_ymd(getArgs(frame))
end
return p