Modulo:Data/sandbox
Vai alla navigazione
Vai alla ricerca
La documentazione per questo modulo può essere creata in Modulo:Data/sandbox/man
--[[ * Modulo per eseguire operazioni sulle date. * Utilizzato da template come {{Età wikipediana}} e {{Tempo trascorso}}. ]] require('Modulo:No globals') local getArgs = require('Modulo:Arguments').getArgs local errorCategory = '[[Categoria:Voci con errori del modulo Data]]' -- classe esportata local Date = {} ------------------------------------------------------------------------------- -- Funzioni di utilità ------------------------------------------------------------------------------- -- Error handler per xpcall, formatta l'errore local function errhandler(msg) local cat = mw.title.getCurrentTitle().namespace == 0 and errorCategory or '' return string.format('<span class="error">Errore: %s</span>%s', msg, cat) end local function isValidDate(date) return pcall(function() mw.getContentLanguage():formatDate('', date) end) end -- Controlla le date inserite dall'utente e le restituisce come oggetti Date local function parseArgs(args, isCompare) local data1, data2, label1, label2 if isCompare then data1, data2 = 'data1', 'data2' label1, label2 = 'prima data', 'seconda data' else data1, data2 = 'inizio', 'fine' label1, label2 = 'data di partenza', 'data di fine' end if not args[data1] then error(string.format('la %s è obbligatoria', label1), 2) elseif not isValidDate(args[data1]) then error(string.format('la %s non è valida', label1), 2) elseif not args[data2] then error(string.format('la %s è obbligatoria', label2), 2) elseif not isValidDate(args[data2]) then error(string.format('la %s non è valida', label2), 2) end return { d1 = Date:new(args[data1]), d2 = Date:new(args[data2]) } end ------------------------------------------------------------------------------- -- classe Date ------------------------------------------------------------------------------- local function date_eq(t, t2) return t.ut == t2.ut end local function date_lt(t, t2) return t.ut < t2.ut end -- Costruisce un oggetto Date a partire da una stringa nel formato -- accettato dalla funzione parser #time. function Date:new(str, precision) local self = {} setmetatable(self, { __index = Date, __eq = date_eq, __lt = date_lt }) self.ut = tonumber(mw.getContentLanguage():formatDate('U', str, true)) self.precision = precision or 11 return self end -- Costruisce un oggetto Date a partire da una stringa nel formato: -- "giorno mese_per_esteso anno" oppure "mese_per_esteso anno" oppure "anno". function Date:newDMY(str) local months = { gennaio = 1, febbraio = 2, marzo = 3, aprile = 4, maggio = 5, giugno = 6, luglio = 7, agosto = 8, settembre = 9, ottobre = 10, novembre = 11, dicembre = 12 } local success, result = pcall(function() local day, month, year = str:match("(%d+) (%a+) (%d+)") if day then return Date:new(string.format('%d-%d-%d', year, months[month], day)) else month, year = str:match("(%a+) (%d+)") if month then return Date:new(string.format('%d-%d', year, months[month]), 10) else return Date:new(string.format('%d', str:match("(%d+)")), 9) end end end ) return success and result or nil end -- Restituisce una stringa che rappresenta la data, senza l'ora. function Date:getDateString() local fmt = self.precision == 9 and 'Y' or (self.precision == 10 and 'F Y' or (self.precision == 11 and 'j F Y' or 'j F Y')) return (mw.getContentLanguage():formatDate(fmt, '@' .. self.ut):gsub('^1%s', '1º ')) end -- Restituisce un nuovo oggetto Date la cui data è avanzata del numero di giorni specificati. function Date:addDays(days) return Date:new('@' .. (self.ut + days * 86400)) end -- Funzione di utilità per Date:diffYMD e Date:diff -- Aggiunge un eventuale prefisso e suffisso al risultato invece del segno. -- L'ultimo parametro diffVal è utilizzato solo da diff per evitare che -- {{#invoke:Data|diff|inizio=2016/01/01|fine=2015/12/31|magnitudine=anni}} ritorni "-0 anni". local function formatResult(result, date1, date2, dir, diffVal) local ret if dir then -- ritorna il 'fa' anche con date1.ut == date2.ut (si potrebbe configurare con un parametro) ret = date1.ut < date2.ut and 'tra ' .. result or result .. ' fa' else ret = (date1.ut <= date2.ut or diffVal == 0) and result or '-' .. result end return ret end -- Restituisce la differenza con la data date2 in anni, mesi e giorni. function Date:diffYMD(date2, rawTable, dir) local monthdays = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } local d1, d2 = os.date('*t', self.ut), os.date('*t', date2.ut) local ret = { seconds = math.abs(self.ut - date2.ut) } if self.ut >= date2.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 '), self, date2, dir) end -- Funzione di utilità per Date:diff 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 Date:diff 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 -- Restituisce la differenza con la data d2 in solo una tra le unità: -- anni, mesi, settimane, giorni, ore, minuti e secondi. function Date:diff(date2, magnitudine, magnitudine_min, dir) local diff, ret, val, result diff = self:diffYMD(date2, 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, self, date2, dir, val) end ------------------------------------------------------------------------------- -- API ------------------------------------------------------------------------------- local p = { Date = Date } -- Entry point per {{#invoke:Data|diff}} function p.diff(frame) local args = getArgs(frame) local success, result = xpcall(function() return parseArgs(args) end, errhandler) return success and result.d1:diff(result.d2, args.magnitudine, args['magnitudine min'], args.dir) or result end -- Entry point per {{#invoke:Data|diff_ymd}} function p.diff_ymd(frame) local args = getArgs(frame) local success, result = xpcall(function() return parseArgs(args) end, errhandler) return success and result.d1:diffYMD(result.d2, false, args.dir) or result end -- Entry point per {{#invoke:Data|compare}} function p.compare(frame) local success, result = xpcall(function() return parseArgs(getArgs(frame), true) end, errhandler) return success and (result.d1 == result.d2 and 0 or ( result.d1 < result.d2 and -1 or 1 )) or result end return p