Module:Date
Révision datée du 4 août 2013 à 02:54 par Zebulon84 (discussion) (dateISO : pas de jour si le mois n'est pas valide.)
La documentation pour ce module peut être créée à Module:Date/doc
local fun = {} -- génère une erreur function fun.erreurDate(texte) return '<span class="error">' .. (texte or "''aucune erreur indiquée''") .. "</span>" end -- nettoie un paramètre non nommé (vire les espaces au début et à la fin) function fun.nettoie(texte) if (texte == nil or texte == "" or type(texte) ~= "string") then return "" end return mw.text.trim(texte) end -- fonction "#ifexist", en attendant que mw.title soit intégré et fournisse cette fonctionnalité function fun.ifexist(page) if (page == nil or type(page) ~= "string" or page == "") then return false end return mw.title.new( page ).exist end -- Ajoute autant de caractère c que nécessaire à la chaîne str pour arriver à la ongeur length function fun.prepend(str, c, length) local lenstr = mw.ustring.len( str ) if lenstr < length then str = mw.ustring.rep( c, length - lenstr) end return str end -- liste des mois, écriture exacte et simplifiée, en minuscule local liste_mois = { { "janvier", "jan.", "janv.", "jan", "janv", "january" }, { "février", "fevrier", "fev.", "fev", "fév.", "fév", "february" }, { "mars", "mar.", "mar", "march" }, { "avril", "avr.", "avr", "apr", "april" }, { "mai", "may" }, { "juin", "jun", "june" }, { "juillet", "juil.", "juil", "juill.", "juill", "jul", "july" }, { "août", "aout","aou", "aug", "august" }, { "septembre", "sept.", "sept", "sep.", "sep", "september" }, { "octobre", "oct.", "oct", "october" }, { "novembre", "nov.", "nov", "november" }, { "décembre", "decembre", "déc.", "dec.", "dec", "déc", "december" } } -- nom du mois à partir du numéro function fun.nomDuMois(num) if (type(num) ~= "number") then return nil end if ((num < 1) or (num > 12)) then return nil end return (liste_mois[num]) end -- valide que la chaîne passée est un mois valide. -- retourne le nom complet ou nil si non reconnu -- si reconnu, retourne aussi le numéro du mois [1-12] function fun.valideMois(mois) local m = mw.ustring.lower(mois) for i = 1, 12 do local j = 1 while (liste_mois[i][j] ~= nil) do if (liste_mois[i][j] == m) then return liste_mois[i][1], i end j = j + 1 end end -- pas trouvé return nil end -- trouve le numéro du mois et son nom, qu'il soit fournit par son nom, son numéro ou une expression mathématique. -- l'objet frame est facultatif, mais permet de tester si mois est une expression type '2+3' function fun.determinationMois(mois, frame) local num, nom if tonumber(mois) then num = math.floor( math.fmod( tonumber(mois) - 1, 12 ) ) + 1 elseif type(mois) == "string" then nom, num = fun.valideMois(mois) if nom == nil and frame and frame.callParserFunction then -- essai de détermination d'un nombre avec le parser #expr de Mediawiki. -- la fonction s'appelle elle-même mais sans l'objet frame pour ne pas tourner en boucle si ce n'est pas une expression valide. nom, num = fun.determinationMois ( frame:callParserFunction('#expr', mois) ) end end if num and not nom then nom = liste_mois [num][1] end return nom, num end -- émule le modèle {{m|Date}}. Pas complet. function fun.modeleDate(frame) -- local args = frame:getParent().args local args = frame.args --[[ paramètres : 1 : jour (numéro ou "1er"). optionnel, si absent pas de jour 2 : mois (en toutes lettres) 3 : année (nombre) 4 : optionnel, spécialité de l'année Comportement spécial ("truc à deux balles au lieu d'utiliser un paramètre nommé du genre "sans année=oui"...") : si 1 est vide mais que le reste est complet → on n'affiche pas l'année ]]-- local decalage = 0 -- si pas de jour mais que args[2] est un mois on décale tout et on -- n'affiche pas l'année if ((fun.nettoie(args[1]) == "") and (fun.valideMois(fun.nettoie(args[3])) ~= nil)) then decalage = 1 end local bjour = fun.nettoie(args[1+decalage]) -- on traite le jour si présent if (bjour ~= nil and bjour ~= "") then local tmp = tonumber(bjour) if (tmp == nil) then if (bjour == "1er") then jour = 1 else return fun.erreurDate("Jour invalide (" .. bjour .. ")") end else jour = tmp end -- on valide que le jour est correct if ((jour < 1) or (jour > 31)) then -- note : il faudrait valider le jour en fonction du mois (30/31 ou 28/29) return fun.erreurDate("Jour invalide (" .. bjour .. ")") end else jour = nil end -- on traite le mois local bmois = fun.nettoie(args[2+decalage]) if (bmois == "") then return fun.erreurDate("Le mois est obligatoire") end local mois, num = fun.valideMois(bmois) if (mois == nil) then return fun.erreurDate("Mois invalide (" .. bmois .. ")") end -- on regarde si la première lettre est en majuscule if (mw.ustring.match(bmois, "^%u") ~= nil) then if (jour == nil) then -- interdit si le jour est indiqué -- oui, on passe la première lettre en majuscule local debut = mw.ustring.match(mois, "^.") local fin = mw.ustring.match(mois, "^.(.*)$") mois = mw.ustring.upper(debut) .. fin end end -- on traite l'année local bannee = fun.nettoie(args[3+decalage]) if (bannee == "") then return fun.erreurDate("L'année est obligatoire") end local tmp = tonumber(bannee) if (tmp == nil) then return fun.erreurDate("Année avalide (" .. bannee .. ")") end annee = tmp -- le champs optionnel local opt = fun.nettoie(args[4+decalage]) if (opt == "") then opt = nil end -- on génère le résultat local res = "" -- le jour si présent if (jour ~= nil) then if (jour == 1) then res = res .. "[[1er " .. mois .. '|<abbr class="abbr" title="premier">1<sup>er</sup></abbr>' .. "]] " else res = res .. "[[" .. jour .. " " .. mois .. "|" .. jour .. "]] " end end -- le mois local tmp = mois .. " " .. annee if (fun.ifexist(tmp)) then res = res .. "[[" .. tmp .. "|" .. mois .. "]]" else if (mois == "mars" or mois == "Mars") then res = res .. "[[Mars (mois)|" .. mois .. "]]" else res = res .. "[[" .. mois .. "]]" end end -- si suivi de l'année on ajoute l'espace if (decalage == 0) then res = res .. " " end -- l'année if (decalage == 0) then -- seulement si on doit l'afficher if (opt == nil) then tmp = annee else tmp = annee .. " " .. opt end if (fun.ifexist(tmp)) then res = res .. "[[" .. tmp .. "|" .. annee .. "]]" else res = res .. "[[" .. annee .. "]]" end end --On ajoute un peu de sémantique local iso = fun.prepend(tostring(annee), '0', 4) .. "-" .. fun.prepend(tostring(num), '0', 2) if (jour ~= nil) then iso = iso .. "-" .. fun.prepend(tostring(jour), '0', 2) end res = "<time datetime=\"" .. iso .. "\">" .. res .. "</time>" return res end -- voir émule le modèle:Inscription date -- la détection des arguments permet d'utilisé la fonction depuis un modèle, depuis invoke, ou depuis une autre fonction. -- pour facilité l'écriture de lua, annee (sans accent) est accepté lors de l'appel depuis lua. function fun.modeleInscriptionDate(frame) local annee, mois, jour if frame.getParent then annee = frame:getParent().args ['année'] or frame.args ['année'] or frame.args.annee or '' mois = frame:getParent().args.mois or frame.args.mois or '' jour = frame:getParent().args.jour or frame:getParent().args ['quantième'] or frame.args.jour or '' else annee = frame ['année'] or frame.annee or '' mois = frame.mois or '' jour = frame.jour or '' end if annee == '' then -- si annee n'est pas précisé, on utilise la paramètre date annee = frame.getParent and (frame:getParent().args.date or frame.args.date) or frame.date or '' if annee == '' then return '' else return '<span class="nowrap">' .. annee .. '</span>' end else -- si l'année est renseigné, on essaye de trouver le mois mois = fun.determinationMois (mois, frame) if mois then mois = mois .. ' ' if jour ~= '' then -- si le mois est valide on détermine le jour jour = tonumber(jour) or jour -- suppresion des 0 qui trainent if jour == 1 or jour == '1er' then jour = '<abbr class="abbr" title="Premier">1<sup>er</sup></abbr>' end jour = jour .. ' ' end return jour .. mois .. annee else return annee end end end -- la fonction dateISO renvoie un date au format aaaa-mm-jj (sans liens) -- l'année peut être sous la forme 2013 ou [[2013 en litérature|2013]] -- le mois peut être en lettre ou en chiffres -- le jour peut être sous la forme '05', '{{1er}}' ou 'vendredi 13' function fun.dateISO(frame) local annee, mois, jour if frame.getParent then annee = frame:getParent().args ['année'] or frame.args ['année'] or frame.args.annee or '' mois = frame:getParent().args.mois or frame.args.mois or '' jour = frame:getParent().args.jour or frame:getParent().args ['quantième'] or frame.args.jour or '' else annee = frame ['année'] or frame.annee or '' mois = frame.mois or '' jour = frame.jour or '' end annee = tonumber ( annee ) or string.match ( annee, '%D(-? ?%d?%d?%d%d)%D') if annee then local nommois, numMois = fun.determinationMois( mois, frame ) if numMois then if numMois < 10 then mois = '-0' .. numMois else mois = '-' .. numMois end local numJour = tonumber(jour) or tonumber( string.match ( jour, '%D?(%d?%d)%D?') ) if numJour then if numJour < 10 then jour = '-0' .. numJour else jour = '-' .. numJour end else jour = '' end else mois = '' jour = '' end return annee .. mois .. jour end end -- Rang du jour dans l'année -- Usage : do_dayRank{année,mois,jour} function fun.do_dayRank(arguments) local yr = tonumber(arguments.year or arguments[1]) or 1 local mt = tonumber(arguments.month or arguments[2]) or 1 local dy = tonumber(arguments.day or arguments[3]) or 1 -- Rangs des premiers des mois local ranks = {0,31,59,90,120,151,181,212,243,273,304,334} local rank = (ranks[mt] or 0) + dy - 1 if(fun.isLeapYear(yr) and (mt >= 3)) then rank = rank+1 end return rank end -- Nombre de jours entre deux années (du 1er janvier au 1er janvier) -- Suit le calendrier grégorien function fun.do_daysBetween(arguments) local yr1 = tonumber(arguments[1]) or 0 local yr2 = tonumber(arguments[2]) or 0 return fun.daysSinceOrigin(yr2) - fun.daysSinceOrigin(yr1) end -- Nombre de jours depuis l'année 1 (du 1er janvier au 1er janvier) function fun.daysSinceOrigin(year) local yr = year-1 return 365*yr + math.floor(yr/4) - math.floor(yr/100) + math.floor(yr/400) end -- Test d'année bissextile function fun.isLeapYear(year) local yr = tonumber(year) or 1 return (yr%4 == 0) and ((yr%100 ~= 0) or (yr%400 == 0)) end -- Conversion d'un nombre en chiffres romains function fun.toRoman(number) local n = math.floor(number) local letters = {"I","V","X","L","C","D","M","",""} local pattern = {"","0","00","000","01","1","10","100","1000","02"} local result = "" if(n<=0 or n>=4000) then result = "---" else for i=1,7,2 do p = pattern[n%10 + 1] for j=0,2 do p = string.gsub(p,tostring(j),letters[i+j]) end result = p .. result n = math.floor(n/10) end end return result end -- Conversion et affichage d'une date dans le calendrier républicain function fun.dateRepublicain(frame) local pframe = frame:getParent() local arguments = pframe.args return fun.formatRepCal(fun.do_toRepCal(arguments)) end -- Calcul d'une date dans le calendrier républicain -- On suppose que les années 4n+3 sont sextiles (3, 7, 11...) function fun.do_toRepCal(arguments) local yr = tonumber(arguments.year or arguments[1]) or 2000 -- rang absolu du jour demandé, le jour 0 étant le 22 septembre 1792 (1er jour de l'an I) local repDays = fun.do_dayRank(arguments) + fun.do_daysBetween{1792,yr} - fun.do_dayRank{1792,9,22} local repYear = math.floor((repDays+731)/365.25) - 1 local repDayRank = repDays - 365*(repYear-1) - math.floor(repYear/4) local repMonth, repDay = math.floor(repDayRank/30)+1, (repDayRank%30)+1 return {repYear, repMonth, repDay} end -- Formatage d'une date selon le calendrier républicain -- Usage : fun.formatRepCal{année,mois,jour} function fun.formatRepCal(arguments) local months = {"Vendémiaire","Brumaire","Frimaire","Nivôse","Pluviôse","Ventôse","Germinal","Floréal","Prairial","Messidor","Thermidor","Fructidor"} local extras = {"de la vertu","du génie","du travail","des récompenses","de l'opinion","de la révolution"} local result = "" if(arguments[2] < 13) then result = result .. tostring(arguments[3]) .. " " .. months[arguments[2]] else result = result .. "jour " .. extras[arguments[3]] end result = result .. " de l'an " .. fun.toRoman(arguments[1]) return result end return fun