Module:Date : Différence entre versions

De Lagny-sur-Marne Wiki
Aller à : navigation, rechercher
(Ajout function dateISO)
m (retouche de la modification précédente)
Ligne 291 : Ligne 291 :
 
     annee = tonumber ( annee ) or string.match ( annee, '%D(-? ?%d?%d?%d%d)%D')
 
     annee = tonumber ( annee ) or string.match ( annee, '%D(-? ?%d?%d?%d%d)%D')
 
     if annee then
 
     if annee then
         local nommois, numMois = Date.determinationMois( mois, frame )
+
         local nommois, numMois = fun.determinationMois( mois, frame )
 
         if numMois then
 
         if numMois then
 
             if numMois < 10 then
 
             if numMois < 10 then

Version du 4 août 2013 à 00:20

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>' .. "]]&nbsp;"
        else
            res = res .. "[[" .. jour .. " " .. mois .. "|" .. jour .. "]]&nbsp;"
        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 .. "&nbsp;"
    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 .. '&nbsp;'
            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 .. '&nbsp;'
            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
        else
            mois = ''
        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
        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]) .. "&nbsp;" .. 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