« Module:Date » : différence entre les versions

De Lagny-sur-Marne Wiki
Aller à la navigation Aller à la recherche
0x010D (discussion | contributions)
WP:DIPP : Inversion de l'ordre des dates avec "julien=oui" (d'abord le calendrier grégorien, ensuite le calendrier julien entre parenthèses). Auteur : Hunsu
m Révocation des modifications de Zebulon84 (discussion) vers la dernière version de 0x010C
 
(45 versions intermédiaires par 2 utilisateurs non affichées)
Ligne 3 : Ligne 3 :
local TableBuilder = require( 'Module:TableBuilder' )
local TableBuilder = require( 'Module:TableBuilder' )
local Outils = require( 'Module:Outils' )
local Outils = require( 'Module:Outils' )
 
-- chargement de la base de donnée répertoriant certaines pages existant ou n'existant pas pour éviter les "ifexist".
local dataLiens
local success, resultat = pcall ( mw.loadData, 'Module:Date/Data' )
if success then
dataLiens = resultat
else
-- protection au cas ou le sous module serait mal modifié
dataLiens = { [''] = { mois = { aucun = 1000, tous = { 1773, 2014 } }, } }
end


-- nettoie un paramètre non nommé (vire les espaces au début et à la fin)
-- nettoie un paramètre non nommé (vire les espaces au début et à la fin)
Ligne 9 : Ligne 17 :
local trim = Outils.trim
local trim = Outils.trim


-- Fonction destiné à mettre la première lettre du mois en majuscule du mois :
-- utilisation de string car aucun mois ne commance par une lettre non ascii en français ou anglais.
local function ucfirst( str )
local function ucfirst( str )
    return mw.ustring.upper( mw.ustring.sub( str, 1, 1 ) ) .. mw.ustring.sub( str, 2 )
return str:sub( 1, 1 ):upper() .. str:sub( 2 )
end
end
local modelePremier = '<abbr class="abbr" title="premier">1<sup>er</sup></abbr>'




-- liste des mois, écriture exacte et simplifiée, en minuscule
-- liste des mois, écriture exacte et simplifiée, en minuscule
local liste_mois = {
local liste_mois = {
    { "janvier", "jan.", "janv.", "jan", "janv", "january", nJour = 31 },
{ "janvier", "jan.", "janv.", "jan", "janv", "january", nJour = 31 },
    { "février", "fevrier", "fev.", "fev", "fév.", "fév", "february", nJour = 29 },
{ "février", "fevrier", "fev.", "fev", "fév.", "fév", "february", nJour = 29 },
    { "mars", "mar.", "mar", "march", nJour = 31 },
{ "mars", "mar.", "mar", "march", nJour = 31 },
    { "avril", "avr.", "avr", "apr", "april", nJour = 30 },
{ "avril", "avr.", "avr", "apr", "april", nJour = 30 },
    { "mai", "may", nJour = 31 },
{ "mai", "may", nJour = 31 },
    { "juin", "jun", "june", nJour = 30 },
{ "juin", "jun", "june", nJour = 30 },
    { "juillet", "juil.", "juil", "juill.", "juill", "jul", "july", nJour = 31 },
{ "juillet", "juil.", "juil", "juill.", "juill", "jul", "july", nJour = 31 },
    { "août", "aout","aou", "aug", "august", nJour = 31 },
{ "août", "aout", "aou", "aug", "august", nJour = 31 },
    { "septembre", "sept.", "sept", "sep.", "sep", "september", nJour = 30 },
{ "septembre", "sept.", "sept", "sep.", "sep", "september", nJour = 30 },
    { "octobre", "oct.", "oct", "october", nJour = 31 },
{ "octobre", "oct.", "oct", "october", nJour = 31 },
    { "novembre", "nov.", "nov", "november", nJour = 30 },
{ "novembre", "nov.", "nov", "november", nJour = 30 },
    { "décembre", "decembre", "déc.", "dec.", "dec", "déc", "december", nJour = 31 },
{ "décembre", "decembre", "déc.", "dec.", "dec", "déc", "december", nJour = 31 },
}
fun.liste_mois = liste_mois
 
local liste_saison = {
{ 'printemps', 'spring', },
{ 'été', 'summer', },
{ 'automne', 'autumn', },
{ 'hiver', 'winter', },
}
}


-- nom du mois à partir du numéro
-- nom du mois à partir du numéro
function fun.nomDuMois( num )
function fun.nomDuMois( num )
    if type( num ) ~= "number" or num < 1 or num > 12 then
if type( num ) ~= "number" or num < 1 or num > 12 then
        return nil
return nil
    end
end
    return liste_mois[num][1]
return liste_mois[num][1]
end
end


Ligne 43 : Ligne 63 :
-- si reconnu, retourne aussi le numéro du mois [1-12]
-- si reconnu, retourne aussi le numéro du mois [1-12]
function fun.valideMois( mois )
function fun.valideMois( mois )
    if type( mois ) ~= "string" then  
local m = trim( mois )
        return nil
if m then
    end
m = mw.ustring.lower( m )
   
for i = 1, 12 do
    local m = mw.ustring.lower( mw.text.trim( mois ) )
local j = 1
while liste_mois[i][j] do
if liste_mois[i][j] == m then
return liste_mois[i][1], i
end
j = j + 1
end
end
end
-- pas trouvé = return nil
end


    for i = 1, 12 do
---
        local j = 1
-- valide que la chaîne passée est un mois valide.
        while liste_mois[i][j] ~= nil do
-- retourne le nom complet ou nil si non reconnu
          if liste_mois[i][j] == m then
-- si reconnu, retourne aussi le numéro du mois [1-12]
              return liste_mois[i][1], i
function fun.valideSaison( saison )
          end
if type( saison ) ~= "string" then
          j = j + 1
return nil
        end
end
    end
    -- pas trouvé = return nil
local m = mw.ustring.lower( trim( saison ) )
for i = 1, 4 do
local j = 1
while liste_saison[i][j] ~= nil do
if liste_saison[i][j] == m then
return liste_saison[i][1]
end
j = j + 1
end
end
-- pas trouvé = return nil
end
end


---
---
-- determinationMois trouve le numéro du mois et son nom,  
-- determinationMois trouve le numéro du mois et son nom,
-- à partir de son nom, de son numéro ou d'une expression mathématique.
-- à partir de son nom, de son numéro ou d'une expression mathématique.
-- l'objet frame est facultatif, mais permet de tester si mois est une expression type '2+3'
-- Si le deuxième paramètre est vrai, les nombres supérieur à 12 ou non entiers sont acceptés. 
function fun.determinationMois( mois, frame )
function fun.determinationMois( mois, mod, boucle )
    local num, nom
local num, nom
    if tonumber( mois ) then
if tonumber( mois ) then
        num = math.floor( math.fmod( tonumber( mois ) - 1, 12 )  ) + 1
num = math.floor( tonumber( mois ) )
    elseif type( mois ) == "string" then
if mod then
        nom, num = fun.valideMois( mois )
-- si le nombre du mois est calculé par une exression, le résultat peut être supérieur à 12, ou inférieur à 1
        if nom == nil and frame and frame.callParserFunction then
num = math.fmod( num + 239, 12 ) + 1 -- +239 car fmod(-1) = -1 et non 11
            -- essai de détermination d'un nombre avec le parser #expr de Mediawiki.
elseif num < 1 or num > 12 then
            -- la fonction s'appelle sans l'objet frame pour ne pas tourner en boucle.
num = nil
            nom, num = fun.determinationMois( frame:callParserFunction( '#expr', mois ) )
end
        end
elseif trim( mois ) then
    end
nom, num = fun.valideMois( mois )
    if num and not nom then  
if nom == nil and boucle == nil then
        nom = liste_mois[num][1]
-- essai de détermination d'un nombre avec le parser #expr de Mediawiki.
    end
-- le paramètre boucle évite de tourner en boucle.
    return nom, num
nom, num = fun.determinationMois( mw.getCurrentFrame():callParserFunction( '#expr', mois ), true, true )
end
end
if num and not nom then
nom = liste_mois[num][1]
end
return nom, num
end
end


Ligne 86 : Ligne 133 :
--  fonction interne à modeleDate, pour déterminer si on peut se passer de faire un ifexit
--  fonction interne à modeleDate, pour déterminer si on peut se passer de faire un ifexit
local function existDate( dataQualificatif, annee, mois )
local function existDate( dataQualificatif, annee, mois )
    local data
local data
    if mois then
if mois then
        data = dataQualificatif.mois
data = dataQualificatif.mois
    else
else
        data = dataQualificatif.annee
data = dataQualificatif.annee
    end
end
    if type( data ) ~= 'table' then  
if type( data ) ~= 'table' then
        -- si data n'existe pas c'est que l'on considère qu'il n'y a pas de lien.
-- si data n'existe pas c'est que l'on considère qu'il n'y a pas de lien.
        return  
return
    end
end
    -- le qualificatif est remplacer par celui de la base de donnée, ce qui permet des alias.
-- le qualificatif est remplacer par celui de la base de donnée, ce qui permet des alias.
    local lien = annee .. ' ' .. ( dataQualificatif.qualificatif or '' )
local lien = annee .. ' ' .. ( dataQualificatif.qualificatif or '' )
    local seul = annee
local seul = annee
    if mois then  
if mois then
        lien = mois .. ' ' .. lien
lien = mois .. ' ' .. lien
        seul = ucfirst( mois ) .. ' ' .. annee
seul = ucfirst( mois ) .. ' ' .. annee
    end
end
    local aucun = tonumber( data.aucun )
local aucun = tonumber( data.aucun )
    if aucun and annee <= aucun then
if aucun and annee <= aucun then
        -- si la l'année est dans la partie 'aucun' on teste s'il y a malgré tout un lien isolé
-- si la l'année est dans la partie 'aucun' on teste s'il y a malgré tout un lien isolé
        if type( data.seul ) == 'table' then
if type( data.seul ) == 'table' then
            for i, v in ipairs( data.seul ) do
for i, v in ipairs( data.seul ) do
                if seul == v or seul == tonumber( v ) then
if seul == v or seul == tonumber( v ) then
                    return lien
return lien
                end
end
            end
end
        end
end
        -- partie aucun et pas de lien => nil
-- partie aucun et pas de lien => nil
        return nil
return nil
    elseif type( data.tous ) == 'table' then
elseif type( data.tous ) == 'table' then
        local tous1, tous2 = tonumber( data.tous[1] ), tonumber( data.tous[2] )
local tous1, tous2 = tonumber( data.tous[1] ), tonumber( data.tous[2] )
        if tous1 and tous2 and annee >= tous1 and annee <= tous2 then
if tous1 and tous2 and annee >= tous1 and annee <= tous2 then
            -- l'année est dans la partie 'tous' donc on retourne le lien
-- l'année est dans la partie 'tous' donc on retourne le lien
            return lien
return lien
        end
end
    end
end
    -- l'annee n'est ni dans la partie aucun, ni dans la partie tous donc il faut tester si la page existe.
-- l'annee n'est ni dans la partie aucun, ni dans la partie tous donc il faut tester si la page existe.
    mw.log( 'ifexist : ' .. lien )
local cibleLien = mw.title.new( lien )
    cibleLien = mw.title.new( lien )
if cibleLien and cibleLien.exists then
    if cibleLien and cibleLien.exists then
return lien
        return lien
end
    end
end
end


---
---
-- émule le modèle {{m|Date}}.
-- Supprime le jour de la semaine, et "le" avant une date
-- Paramètres :
function fun.nettoyageJour( jour )
--      1 : jour (numéro ou "1er"). optionnel, si absent pas de jour
if type( jour ) == 'string' then
--      2 : mois (en toutes lettres)
local nomJour = { '[Ll]undi', '[Mm]ardi', '[Mm]ercredi', '[Jj]eudi', '[Vv]endredi',
--      3 : année (nombre)
'[Ss]amedi', '[Dd]imanche', '^ *[Ll]e' }
--      4 : optionnel, spécialité de l'année
local premier = { '<abbr class="abbr" title="Premier" >1<sup>er</sup></abbr>', '1<sup>er</sup>', '1er' }
--      Comportement spécial ("truc à deux balles au lieu d'utiliser un
for i, v in ipairs( nomJour ) do
--      paramètre nommé du genre "sans année=oui"...") : si 1 est vide
jour = jour:gsub( v, '' )
--      mais que le reste est complet → on n'affiche pas l'année
end
function fun.modeleDate( frame )
for i, v in ipairs( premier ) do
    local args = Outils.extractArgs( frame )
jour = jour:gsub( v, '1' )
   
end
    -- chargement de la base de donnée répertoriant certaines pages existant ou n'existant pas pour éviter les "ifexist".
jour = trim( jour )
    local dataLiens       
end
    local success, resultat = pcall ( mw.loadData, 'Module:Date/Data' )
return jour
    if success then
end
        dataLiens = resultat
    else
        -- protection au cas ou le sous module serait mal modifié
        dataLiens = { [''] = { mois = { aucun = 1000, tous = { 1938, 2013 } }, }, parametresPage = { } }
    end
   
    local annee, mois, numMois, jour
    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 trim( args[1] ) == nil and fun.valideMois( trim( args[3] ) ) ~= nil then
        decalage = 1
    end
   
    -- on traite l'année
    local bannee = args[3 + decalage]
    if Outils.notEmpty( bannee ) then
        annee = tonumber( bannee )
        if annee == nil and type( bannee ) == 'string' then
            -- test si l'année contient av. J.-C.
            annee = mw.ustring.match( mw.ustring.upper( bannee ), '^(%d+)%sAV%.?%s?J%.?%-?C' )
            annee = tonumber( annee )
            if annee then
                annee = 0 - annee
            else
            local namespaceCategorisation = { [0] = true, [4] = true, [10] = true, [14] = true, [100] = true }
      if namespaceCategorisation[ mw.title.getCurrentTitle().namespace ] then
              return Outils.erreur( 'Année invalide (' .. bannee .. ')[[Catégorie:Page utilisant le modèle date avec une syntaxe erronée|A]]')
              else
              return Outils.erreur( 'Année invalide (' .. bannee .. ')')
              end
            end
        end
    else
        annee = nil
    end


    -- on traite le mois
---
    local bmois = args[2 + decalage]
-- Sépare une chaine date en un table contenant les champs jour, mois et annee.
    if Outils.notEmpty( bmois ) then
-- la date doit contenir le mois.
        mois, numMois = fun.valideMois( bmois )
function fun.separationJourMoisAnnee( date )
        if mois == nil then  
date = trim( date )
            -- on teste si le mois est fourni sous forme numérique
if date then
            numMois = tonumber( bmois )
local function erreur( periode, valeur )
            mois = fun.nomDuMois( numMois )
return false, Outils.erreur( periode .. ' invalide (' .. valeur .. ')' )
        end
end
        if mois == nil then
local jour, mois, annee, masquerMois, masquerAnnee, separateur
            local namespaceCategorisation = { [0] = true, [4] = true, [10] = true, [14] = true, [100] = true }
-- variable pour construire les regex
      if namespaceCategorisation[ mw.title.getCurrentTitle().namespace ] then
local j = '([0-3]?%d)'      -- jour
              return Outils.erreur( 'Mois invalide (' .. bmois .. ')[[Catégorie:Page utilisant le modèle date avec une syntaxe erronée|M]]')
local m = '([01]?%d)'      -- mois numérique
              else
local mmm = '([^%s%p%d]+[.]?)' -- mois en toute lettre
              return Outils.erreur( 'Mois invalide (' .. bmois .. ')')
local aj = '(%-?%d+)'      -- année ou jour
              end
local s = '[ ./-]+'          -- séparateur simple
        else
local sep = '([ ./-]+)'      -- séparateur avec capture, pour le détecter deux fois
       
local moins = '(%-?)'        -- signe moins pour signifier qu'il ne faut pas afficher cette donnée
            -- on traite le jour si présent
local regexb = {
            local bjour = args[1 + decalage]
jmmm = '^'..j..s..mmm..moins..'$',
            if Outils.notEmpty( bjour ) then
mmmjva = '^'..mmm..s..j..', ?'..aj..'$',
                jour = tonumber( bjour )
}
                if jour == nil and type( bjour ) == 'string' then
                bjour = mw.text.trim( bjour )
date = fun.nettoyageJour( date )
                    if bjour == '1er'  
-- suppression catégorie, liens, balises
                        or bjour == '<abbr class="abbr" title="Premier" >1<sup>er</sup></abbr>' -- correspond à {{1er}}
date = mw.ustring.gsub( date, '%[%[[Cc]at[ée]gor[yi]e?:.-%]%]', '' )
                    then
date = date :gsub( '%b<>', '' )
                        jour = 1
:gsub( '%[%[([^%[%]|]*)|?([^%[%]]*)%]%]', function ( l, t ) return trim( t ) or l end )
                    else
-- suppression des espaces insécables
                        local namespaceCategorisation = { [0] = true, [4] = true, [10] = true, [14] = true, [100] = true }
:gsub( '\194\160', ' ' )
      if namespaceCategorisation[ mw.title.getCurrentTitle().namespace ] then
:gsub( '&nbsp;', ' ' )
              return Outils.erreur( 'Jour invalide (' .. bjour .. ')[[Catégorie:Page utilisant le modèle date avec une syntaxe erronée|J]]')
:gsub( '\226\128\175', ' ' )
              else
:gsub( '&nnbsp;', ' ' )
              return Outils.erreur( 'Jour invalide (' .. bjour .. ')')
:gsub( '\226\128\137', ' ' )
              end
:gsub( '&thinsp;', ' ' )
                    end
:gsub( '&#32;', ' ' )
                end
:gsub( ' +', ' ' )
                -- on valide que le jour est correct
-- réduction av. J-C pour simplifier un peu les regex :
                if jour < 1 or jour > 31 then
:gsub( '(%d+) ?[Aa][Vv]%.? ?[Jj][ .-]*[Cc]%.?', '-%1' )
                    return Outils.erreur( 'Jour invalide (' .. bjour .. ')' )
-- supression de l'heure dans les date ISO
                elseif jour > liste_mois[numMois].nJour then
:gsub( '^+?([%d-]*%d%d%-%d%d)T%d%d[%d:,.+-]*Z?$' , '%1')
                    local namespaceCategorisation = { [0] = true, [4] = true, [10] = true, [14] = true, [100] = true }
      if namespaceCategorisation[ mw.title.getCurrentTitle().namespace ] then
-- test année seule
              return Outils.erreur( 'Jour invalide (' .. bjour .. ')[[Catégorie:Page utilisant le modèle date avec une syntaxe erronée|J]]')
if date:match( '^'..aj..'$' ) then
              else
annee = date:match( '^'..aj..'$' )
              return Outils.erreur( 'Jour invalide (' .. bjour .. ')')
elseif date:match( '^'..aj..s..aj..moins..'$' ) then
              end
-- jj/mm, mm/aaaa ou aaaa/mm
                    -- l'année bisextile n'est pas testée pour accepter les dates juliennes.
local a, separateur, b, sb = date:match( '^'..aj..sep..aj..moins..'$' )
                end
a, b = tonumber( a ), tonumber( b )
            else
if separateur:match( '^.+%-$' ) then
                -- S'il n'y a pas de jour on regarde si la première lettre du mois est en majuscule
-- probablement mm/-aaaa, année av.JC
                if mw.ustring.match( bmois, '^%u' ) then
b = 0 - b
                    -- oui, on passe la première lettre en majuscule
end
                    mois = ucfirst( mois )
if  a > 12 and ( b < 1 or b > 31 ) or
                end
b > 12 and ( a < 1 or a > 31 ) then
                -- s'il n'y a pas d'année non plus on retourne le mois simple
return erreur( 'Date', date )
            end
elseif b < 1 or b > 31 then
        end
mois, annee, masquerAnnee = a, b, sb
    -- else
elseif a < 1 or a > 31 then
    --   return Outils.erreur("Le mois est obligatoire")
annee, mois  = a, b
    end
elseif b > 12 then
return erreur( 'Mois', b )
else
jour, mois, masquerMois = a, b, sb
end
elseif date:match( '^'..aj..sep..m..moins..'%2'..aj..moins..'$' ) then
-- jj/mm/aaaa ou aaaa/mm/jj
jour, separateur, mois, masquerMois, annee, masquerAnnee =  date:match( '^'..aj..sep..m..moins..'%2'..aj..moins..'$' )
if separateur == '-' and masquerMois == '-' and masquerAnnee == '' and tonumber( annee ) > 0 then
-- date au format jj-mm--aaaa type 17-06--44 pour 17 juin 44 av. JC
masquerMois = nil
annee = 0 - annee
end
elseif date:match( '^'..j..sep..mmm..moins..'%2'..aj..moins..'$' ) then
-- jj mmm aaaa
jour, separateur, mois, masquerMois, annee, masquerAnnee = date:match( '^'..j..sep..mmm..moins..'%2'..aj..moins..'$' )
elseif date:match( '^'..mmm..s..aj..moins..'$' ) then
-- mmm aaaa
mois, separateur, annee, masquerAnnee = date:match( '^'..mmm..sep..aj..moins..'$' )
if separateur:match( '^.+%-$' ) then
annee = '-' .. annee
end
elseif date:match( '^'..j..s..mmm..moins..'$' ) then
-- jj mmmm
jour, mois, masquerMois = date:match( '^'..j..s..mmm..moins..'$' )
elseif date:match( '^'..mmm..s..j..', ?'..aj..'$') then
-- mmm jj, aaaa (format anglo-saxon)
mois, jour, annee = date:match( '^'..mmm..s..j..', ?'..aj..'$')
elseif date:match( '^'..mmm..'$' ) then
mois = date
else
return erreur( 'Date', date )
end
local jn, an = tonumber( jour ), tonumber( annee )
if jn and an and ( jn > 31 or jn < 0 or #jour >= 3 ) and an <= 31 then
-- cas notamment des date ISO 2015-06-17, -0044-06-17 et -0002-06-17
-- inversion du jour et de l'année
local temp = annee
annee = jour
jour = temp
end
return fun.validationJourMoisAnnee{
jour, mois, annee,
masquerAnnee = trim( masquerAnnee ) and true or nil,
masquerMois = ( trim( masquerAnnee ) or not annee ) and trim( masquerMois ) and true or nil,
-- or nil sert juste à éviter de trainer une valeur false dans tous les tests unitaires.
}
else
return true, {}
end
end


    -- on traite le champs optionnel
    local qualificatif = trim( args[4 + decalage] ) or dataLiens.parametresPage.qualificatif
   
    -- on traite l'age
    local age = trim( args['âge'] or args['age'] )
    age = age and  fun.age( annee, numMois, jour )
   
    -- on traite le calendrier
    local gannee, gmois, gjour = annee, numMois, jour      -- date suivant le calendrier grégorien pour <time>
    local jannee, jmois, jjour, julien = annee, mois, jour  -- servira éventuellement à a affiché la date selon le calendrier julien
    local julien2, julien3 = nil, nil            -- servira éventuellement à a affiché des parenthèses
    local julien = trim( string.lower( args.julien or dataLiens.parametresPage.julien or '' ) )
    if annee and jour then
        local amj = annee * 10000 + numMois * 100 + jour
        if amj < 15821014 then
            gannee, gmois, gjour = fun.julianToGregorian( annee, numMois, jour )
        elseif julien == 'oui' then 
            gannee, gmois, gjour = fun.julianToGregorian( annee, numMois, jour )
            annee, mois, jour = gannee, liste_mois[gmois][1], gjour
        end
    end


   
---
    -- on génère le résultat
-- separationJourMoisAnnee prend jusqu'a cinq paramètre et essaie de les séparer en jour, mois, annee et qualificatif
   
-- la date peut être dans le premier paramètre ou séparée dans les paramètre 1 à 3 ou 2 à 4.
    -- Déclarations des variables
-- Le qualificatif est cherché dans le paramètre suivant.
    local wikiListe = TableBuilder.new()   -- reçois le texte affiché pour chaque paramètre
-- La fonction retourne true suivit d'une table avec la date en paramètres nommé (sans accent sur année)
    local iso = TableBuilder.new()         -- reçois le format date ISO de ce paramètre
-- ou false suivit d'un message d'erreur.
function fun.validationJourMoisAnnee( frame, ... )
local args = Outils.extractArgs( frame, ... )
local jour, mois, numMois, annee, erreur
local bjour = args[1] or args['jour'] or ''
local bmois = tostring( args[2] or args['mois'] or '' )
local bannee = args[3] or args['annee'] or args['année'] or ''
local function erreur( periode, valeur )
return false, Outils.erreur( periode .. ' invalide (' .. valeur .. ')' )
end
-- on traite l'année
if Outils.notEmpty( bannee ) then
annee = tonumber( bannee )
if annee == nil and type( bannee ) == 'string'  then
-- test si l'année contient av. J.-C.
annee = string.match( string.upper( bannee ), '^(%d+) ?[Aa][Vv]%.? ?[Jj][ .-]*[Cc]%.?' )
annee = tonumber( annee )
if annee then
annee = 0 - annee
else
return erreur( 'Année', bannee )
end
end
else
annee = nil
end
-- on traite le mois
if Outils.notEmpty( bmois ) then
mois, numMois = fun.determinationMois( bmois )
if mois == nil then
mois = fun.valideSaison( bmois )
if mois == nil then
return erreur( 'Mois', bmois )
end
else
-- on traite le jour si présent
if Outils.notEmpty( bjour ) then
jour = tonumber( bjour )
if jour == nil then
jour = tonumber( fun.nettoyageJour( bjour ) )
end
if jour == nil then
return erreur( 'Jour', bjour )
end
-- on valide que le jour est correct
if jour < 1 or jour > 31 then
return erreur( 'Jour', bjour )
elseif jour > liste_mois[numMois].nJour then
return erreur( 'Jour', bjour .. ' ' .. mois )
elseif jour == 29 and numMois == 2 and annee and ( math.fmod( annee, 4 ) ~= 0 ) then
-- l'année bisextile sur les siècles est toujours acceptée pour être compatible avec les dates juliennes.
return erreur( 'Jour', '29 février ' .. annee  )
end
else
-- S'il n'y a pas de jour on regarde si la première lettre du mois est en majuscule
if bmois:match( '^%u' ) then
-- oui, on passe la première lettre en majuscule
mois = ucfirst( mois )
end
-- s'il n'y a pas d'année non plus on retourne le mois simple
end
end
else
-- on teste le jour si présent
if Outils.notEmpty( bjour ) then
if annee then
return erreur( 'Mois', 'absent' )
else
bjour = fun.nettoyageJour( bjour )
jour = tonumber( bjour )
if jour then
if jour > 31 or jour < 1 then
annee = jour
jour = nil
else
return erreur( 'Date', 'jour seul : ' .. bjour )
end
else
return erreur( 'Jour', bjour )
end
end
end
end
-- vérification de l'absence d'un décalage
if annee and annee < 13 and annee > 0 and not jour and ( tonumber( bmois ) or (not mois and tonumber( args[4] ) ) ) then
return false, Outils.erreur( 'année improbable (' .. annee .. ')' )
end
local resultat = {
jour = jour,
mois = mois,
numMois = numMois,
annee = annee,
masquerAnnee = args.masquerAnnee,
masquerMois = args.masquerMois,
}
return true, resultat
end


    local dataQualificatif = dataLiens[qualificatif or '']
function fun.modeleDateAnalyseJMA( args )
    if type( dataQualificatif ) ~= 'table' then
local function masquerParam( p ) -- sépare le signe moins final éventuel signifiant que le paramètre ne soit pas être affiché.
        -- si le qualifiquatif n'est pas dans la base de donnée, on crée une table minimum,
local s
        -- qui imposera un test sur l'annee, mais considère qu'il n'y a pas de lien sur le jour ou le mois
if trim( p ) then
        dataQualificatif = { qualificatif = ' ' .. qualificatif, annee = { } }
p, s = p:match( '^(.-)(%-?)%s*$' )
    end
end
    local dataCat = dataLiens[dataQualificatif.cat]
return p, ( s == '-' or nil )
    if type( dataCat ) ~= 'table' or dataCat == dataQualificatif then
end
        dataCat = { qualificatif = '' }
    end
local test, resultat
local arg1, arg2, arg3 = fun.nettoyageJour( args[1] ), trim( args[2] ), trim( args[3] )
if type( arg1 ) == 'string' and arg3 == nil and ( arg1:match( '[^ ./-][ ./-]+[^ ./-]' ) or arg2 == nil or dataLiens[arg2] or mw.ustring.match( arg2, '%a %a' ) ) then
-- la date est dans le premier paramètre
test, resultat = fun.separationJourMoisAnnee( arg1 )
if test then
resultat.qualificatif = arg2
end
else
local param, masquerM, masquerA
param = { args[1] or args.jour }
param[2], masquerM = masquerParam( args[2] or args.mois )
param[3], masquerA = masquerParam( args[3] or args.annee or args['annee'] )
param[4] = masquerParam( args[4] )
test, resultat = fun.validationJourMoisAnnee( param )
if test then
resultat.masquerAnnee = masquerA
resultat.masquerMois = masquerM
resultat.qualificatif = trim( args[4] )
end
end
return test, resultat
end


-- Date julienne
---
    if jjour ~= jour then
-- émule le modèle {{m|Date}}.
        if jjour == 1 then
-- Paramètres :
              jjour = '<abbr class="abbr" title="premier">1<sup>er</sup></abbr>'
-- 1 : jour (numéro ou "1er"). optionnel, si absent pas de jour
        end
-- 2 : mois (en toutes lettres)
        if jannee ~= annee then
-- 3 : année (nombre)
        julien3 = '(<abbr class=abbr title="selon le calendrier julien">' .. jjour .. ' ' .. jmois .. ' ' .. jannee .. '</abbr>)'
-- 4 : optionnel, spécialité de l'année
        else
-- Comportement spécial ("truc à deux balles au lieu d'utiliser un
            julien2 = '(<abbr class=abbr title="selon le calendrier julien">' .. jjour .. ' ' .. jmois .. '</abbr>)'
-- paramètre nommé du genre "sans année=oui"...") : si 1 est vide
        end
-- mais que le reste est complet → on n'affiche pas l'année
    end
function fun.modeleDate( frame )
local args = Outils.extractArgs( frame )
local test, params = fun.modeleDateAnalyseJMA( args )
local cat, resultat = ''
if test then
local listeParam = {
qualificatif = 'qualificatif',
age = 'âge',
['âge'] = 'âge',
naissance = 'naissance',
mort = 'mort',
['décès'] = 'mort',
julien = 'julien',
avJC = 'avJC',
nolinks = 'nolinks',
}
for n, v in pairs( listeParam ) do
params[v] = params[v] or args[n]
end
resultat = fun._modeleDate( params )


else
local namespaceCategorisation = { [0] = true, [4] = true, [10] = true, [14] = true, [100] = true }
if namespaceCategorisation[ mw.title.getCurrentTitle().namespace ] and not Outils.notEmpty( args.nocat ) then
cat = '[[Catégorie:Page utilisant le modèle date avec une syntaxe erronée]]'
end
resultat = params .. cat
end
return resultat or ''
end


    -- le jour si présent
function fun._modeleDate( args )
    local qualifJour = ''
local annee, mois, numMois, jour = args.annee, args.mois, args.numMois, args.jour
    if jour then
local qualificatif = args.qualificatif
        -- éphémérides du qualificatif, ou de sa catégorie, ou générale.
        qualifJour = dataQualificatif.jour and dataQualificatif.qualificatif
if ( annee or mois or jour ) == nil then
            or dataCat.jour and dataCat.qualificatif
return
            or ''
end
        local lien = jour .. ' ' .. mois .. ' ' .. qualifJour
        if jour == 1 then
-- on traite l'age, naissance et mort
            jour = '<abbr class="abbr" title="premier">1<sup>er</sup></abbr>'
local age = trim( args['âge'] or args['age'] )
            lien = '1er ' .. mois .. ' ' .. qualifJour
age = age and  fun.age( annee, numMois, jour )
        end
local naissance = trim( args.naissance )
        -- s'il n'y a pas de lien sur le mois, il sera affiché avec le jour.  
local mort = trim( args.mort )
        wikiListe.insert( '[[' .. lien .. '|' .. jour .. ']]' )
        wikiListe.insert( '[[' .. lien .. '|' .. jour .. ' '.. mois .. ']]' )
-- on traite le calendrier
        iso.insert( 1, string.sub( '0' .. gjour, -2 ) )
local gannee, gmois, gjour = annee, numMois, jour       -- date suivant le calendrier grégorien pour <time>
    end
local jannee, jmois, jjour = annee, mois, jour  -- servira éventuellement à a affiché la date selon le calendrier julien
local julien2, julien3 = nil, nil                        -- servira éventuellement à a affiché des parenthèses
local julien = trim( string.lower( args.julien or '' ) )
if annee and jour then
local amj = annee * 10000 + numMois * 100 + jour
if amj < 15821014 then
if annee > 0 then
gannee, gmois, gjour = fun.julianToGregorian( annee, numMois, jour )
else
-- calendrier grégorien proleptique avec année 0.
gannee, gmois, gjour = fun.julianToGregorian( annee + 1, numMois, jour )
end
elseif julien == 'oui' then
gannee, gmois, gjour = fun.julianToGregorian( annee, numMois, jour )
annee, mois, jour = gannee, liste_mois[gmois][1], gjour
end
else
if annee and annee < 0 then
gannee = gannee + 1
end
end
-- on génère le résultat
-- Déclarations des variables
local wikiListe = TableBuilder.new()  -- reçois le texte affiché pour chaque paramètre
local iso = TableBuilder.new()        -- reçois le format date ISO de ce paramètre
local dataQualificatif, dataCat
if not args.nolinks then
dataQualificatif = dataLiens[qualificatif or '']
if type( dataQualificatif ) ~= 'table' then
-- si le qualifiquatif n'est pas dans la base de donnée, on crée une table minimum,
-- qui imposera un test sur l'annee, mais considère qu'il n'y a pas de lien sur le jour ou le mois
dataQualificatif = { qualificatif = ' ' .. qualificatif, annee = { } }
end
dataCat = dataLiens[dataQualificatif.cat]
if type( dataCat ) ~= 'table' or dataCat == dataQualificatif then
dataCat = { qualificatif = '' }
end
end
local function wikiLien( lien, texte )
if lien == texte then
return texte
else
return texte
end
end
-- Date julienne
if jjour ~= jour then
if jjour == 1 then
jjour = '<abbr class="abbr" title="premier">1<sup>er</sup></abbr>'
end
if jannee ~= annee then
julien3 = '(<abbr class=abbr title="selon le calendrier julien">' .. jjour .. ' ' .. jmois .. ' ' .. jannee .. '</abbr>)'
else
julien2 = '(<abbr class=abbr title="selon le calendrier julien">' .. jjour .. ' ' .. jmois .. '</abbr>)'
end
end


    -- le mois
-- le jour si présent
    if mois then
local qualifJour = ''
        local lien
if jour then
        if annee then
local texteJour = jour
            lien = existDate( dataQualificatif, annee, mois ) or existDate( dataCat, annee, mois )
if args.nolinks then
            if lien == nil and qualificatif and qualifJour == '' then
if jour == 1 then
                -- test nouveau test sans le qualificatif uniquement s'il n'y a pas d'éphémérides pour ce qualificatif.
jour = modelePremier
                lien = existDate( dataLiens[''], annee, mois )
end
            end
wikiListe.insert( jour )
        end  
else
        if lien then
qualifJour = dataQualificatif.jour and dataQualificatif.qualificatif
            -- s'il y a un lien on retire le lien affichant 'jour mois' pour ajouter '[[mois annee|mois']]
or dataCat.jour and dataCat.qualificatif
            wikiListe.remove()
or ''
            wikiListe.insert( '[[' .. lien .. '|' .. mois .. ']]' )
local lien = jour .. ' ' .. mois .. ' ' .. qualifJour
        else
if jour == 1 then
            -- sinon on retire le lien affichant 'jour' pour ne garder que le lien 'jour mois'  
jour = '1<sup>er</sup>'
            wikiListe.remove( #wikiListe - 1 )
lien = '1er ' .. mois .. ' ' .. qualifJour
            -- s'il n'y avait pas je jour, la liste est vide mais ça ne pose pas de problème
end
            -- sauf si l'année n'est pas affichée :
-- s'il n'y a pas de lien sur le mois, il sera affiché avec le jour.
            if #wikiListe == 0 and ( annee == nil or decalage > 0 ) then
wikiListe.insert( wikiLien( lien, jour ) )
                return mois
wikiListe.insert( wikiLien( lien, jour .. ' '.. mois ) )
            end
end
        end
iso.insert( 1, string.sub( '0' .. gjour, -2 ) )
        iso.insert( 1, string.sub( '0' .. gmois, -2 ) )
end
    end
    if( julien2 ) then
-- le mois
if mois then
if #wikiListe == 0 and annee == nil then
return mois
end
if args.nolinks then
if not args.masquerMois then
wikiListe.insert( mois )
end
else
local lien
if annee then
lien = existDate( dataQualificatif, annee, mois ) or existDate( dataCat, annee, mois )
if lien == nil and qualificatif and qualifJour == '' then
-- test nouveau test sans le qualificatif uniquement s'il n'y a pas d'éphémérides pour ce qualificatif.
lien = existDate( dataLiens[''], annee, mois )
end
end
if lien or args.masquerMois then
-- s'il y a un lien on retire le lien affichant 'jour mois' pour ajouter '[[mois annee|mois']]
wikiListe.remove()
if not args.masquerMois then
wikiListe.insert( wikiLien( lien, mois ) )
end
elseif #wikiListe > 0 then
-- sinon on retire le lien affichant 'jour' pour ne garder que le lien 'jour mois'
wikiListe.remove( #wikiListe - 1 )
elseif args.masquerAnnee then
-- s'il n'y a pas de jour et que l'année n'est pas affichée, on insère le mois seul.
wikiListe.insert( mois )
end
end
if gmois then
iso.insert( 1, string.sub( '0' .. gmois, -2 ) )
end
end
if( julien2 ) then
wikiListe.insert( julien2 )
wikiListe.insert( julien2 )
end
end
    -- l'année
    if annee and decalage == 0 then -- seulement si on doit l'affichée
-- l'année
        local lien = existDate( dataQualificatif, annee ) or existDate( dataCat, annee )
if annee then
        local texte = annee
if not args.masquerAnnee then
        if annee < 0 then
local texteAnnee = annee
            local annneeAvJc = 0 - annee
local lien
            lien = lien or ( annneeAvJc .. ' av. J.-C.' )
if annee < 0 then
            local avJC = trim( string.lower( args.avJC or dataLiens.parametresPage.avJC or '' ) )
local annneeAvJc = 0 - annee
            if args.avJC == 'non' then
lien = lien or ( annneeAvJc .. ' av. J.-C.' )
                texte = annneeAvJc
local avJC = trim( string.lower( args.avJC or '' ) )
            else
if args.avJC == 'non' then
                texte = annneeAvJc .. '&nbsp;<abbr class="abbr" title="'  
texteAnnee = annneeAvJc
                    .. annneeAvJc .. ' avant Jésus-Christ">av.&nbsp;J.-C.</abbr>'
else
            end
texteAnnee = annneeAvJc .. ' <abbr class="abbr" title="'
        end
.. annneeAvJc .. ' avant Jésus-Christ">av. J.-C.</abbr>'
        lien = lien or annee
end
        if mois and #wikiListe == 0 then
end
            -- si le mois n'a pas de lien et n'est pas affiché avec le jour, il est affiché avec l'année.
if args.nolinks then -- seulement si on doit l'affichée
            texte = mois .. ' ' .. texte
wikiListe.insert( texteAnnee )
        end
else
        wikiListe.insert( '[[' .. lien .. '|' .. texte .. ']]' )
lien = existDate( dataQualificatif, annee ) or existDate( dataCat, annee ) or lien or annee
        iso.insert( 1, string.sub( '000' .. annee , -4 ) )
if mois and #wikiListe == 0 then
    end
-- si le mois n'a pas de lien et n'est pas affiché avec le jour, il est affiché avec l'année.
    if( julien3 ) then
texteAnnee = mois .. ' ' .. texteAnnee
    wikiListe.insert( julien3 )
end
    end
wikiListe.insert( wikiLien( lien, texteAnnee ) )
    -- l'age  
end
        local classAge
end
    if type( age ) == 'number' and age >= 0 then
if gannee > 999 then
        if age == 0 then
iso.insert( 1, gannee )
            age = '<span class="noprint"> (moins d\'1 an)</span>'
elseif gannee > -1 then
        elseif age == 1 then  
iso.insert( 1, string.sub( '000' .. gannee , -4 ) )
            age = '<span class="noprint"> (1 an)</span>'
elseif gannee > -999 then
        else
-- calendrier grégorien proleptique avec année 0.
            age = '<span class="noprint"> (' .. age .. ' ans)</span>'
iso.insert( 1, 'U-' .. string.sub( '000' .. ( 0 - gannee ), -4 ) )
        end
else
        classAge = 'class="bday" '
iso.insert( 1, 'U' .. gannee )
    else
end
        age = ''
end
        classAge = ''
if( julien3 ) then
    end
wikiListe.insert( julien3 )
   
end
    -- compilation du résultat
 
    local wikiText = wikiListe.concat( '&nbsp;' )
    -- On ajoute un peu de sémantique. La date doit être dans le calendrier grégorien proleptique
-- l'age
    -- ce formatage ne s'applique pas avant J.C.
if type( age ) == 'number' and age >= 0 and ( not naissance or age < 120 ) then
    if wikiText ~= '' and ( gannee == nil or gannee > 0) then  
if age == 0 then
        wikiText = '<time '.. classAge .. 'datetime="' .. iso.concat( '-' ) .. '">' .. wikiText .. '</time>'
age = '(moins d’un&nbsp;an)'
    end
elseif age == 1 then
   
age = '(1&nbsp;an)'
    return wikiText .. age
else
age = '(' .. age .. '&nbsp;ans)'
end
else
age = false
end
-- compilation du résultat
local wikiTexte = wikiListe.concat( ' ' )
local isoTexte = iso.concat( '-' )
-- On ajoute un peu de sémantique.
local wikiHtml = mw.html.create( '' )
local dateHtml = wikiHtml:tag( 'time' )
:wikitext( wikiTexte )
if wikiTexte:match( ' ' ) then
dateHtml:addClass( 'nowrap' )
end
if isoTexte ~= wikiTexte then
dateHtml:attr( 'datetime', isoTexte )
end
if not args.nolinks then
dateHtml:addClass( 'date-lien' )
end
if naissance then
dateHtml:addClass( 'bday' )
elseif mort then
dateHtml:addClass( 'dday' )
end
if age then
wikiHtml:wikitext( ' ' )
:tag( 'span' )
:addClass( 'noprint')
:wikitext( age )
:done()
end
return tostring( wikiHtml )
end
end


---
---
-- voir émule le modèle:Inscription date
-- fonction destinée aux infobox, notamment pour afficher les dates de naissance et de mort
-- la détection des arguments permet d'utilisé la fonction depuis un modèle, depuis invoke, ou depuis une autre fonction.
-- les liens présent dans les dates fournies sont automatiquement supprimées pour gérer les cas ou
-- pour facilité l'écriture de lua, annee (sans accent) est accepté lors de l'appel depuis lua.
-- le paramètre contient déjà un modèle date.
function fun.inscriptionDate( frame )
-- Paramètres :
local args = Outils.extractArgs( frame )
-- 1 : type de date à afficher (naissance / n, mort / m, ou date / d)
local annee = Outils.notEmpty( args['année'], args.annee, args.year )
-- 1 : Date ou date de naissance
if annee then
-- 2 : Date de mort si type n ou m
-- si l'année est renseigné, on essaye de trouver le mois
-- qualificatif = suffixe des page de date à lier (exemple : en musique)
local mois = Outils.notEmpty( args.mois, args.month )
-- nolinks : n'affiche pas de lien
function fun.dateInfobox( frame )
if mois then
local args = frame.args
mois = fun.determinationMois( mois, frame ) or mois
if type( args ) ~= 'table' or not ( args[1] and args[2] ) then
local jour = Outils.notEmpty( args.jour, args.day, args['quantième'] )
return
if jour then  
end
-- si le mois est valide on détermine le jour
jour = tonumber( jour ) or jour   -- suppresion des 0 qui trainent
local function analyseDate( d )
if jour == 1 or jour == '1er' then
if trim( d ) then
jour = '<abbr class="abbr" title="Premier">1<sup>er</sup></abbr>'
-- supprime les liens
end
local analyse = d:match( ' ou ') or d:match( 'entre ' ) or d:match( 'vers ' ) or d:match( 'après ' ) or d:match( 'avant ' )
return jour .. '&nbsp;' .. mois .. '&nbsp;' .. annee
if analyse then  
return d
end
analyse = d:match( 'datetime="([%d-]+)"' ) or d
local debut, fin = analyse:match( '(.-%d%d%d%]*%-?)([\127 ].+)' )
if not debut then
debut, fin = analyse:match( '(.-%d%d%d%]*%-?)(<br ?/?>.+)' )
end
analyse = debut or analyse
analyse = analyse:gsub( '%[%[([^%[%]|]*)|?([^%[%]]*)%]%]', function ( l, t ) return trim( t ) or l end )
local t, r = fun.separationJourMoisAnnee( analyse )
if t then
return r, fin
else
else
return mois .. '&nbsp;' .. annee
return d, fin
end
end
end
end
local naissance = args[1]:match( '^n' )
local mort = args[1]:match( '^m' ) or args[1]:match( 'décès' )
local affichageDate, qualificatif = args[2], args[4]
local affichageDateTab, resultatDate, complementDate
local dateNaissance, dateMort
if mort then
affichageDate = args[3]
end
if not trim( affichageDate ) then
return
end
if affichageDate:match( '</time>' ) then
-- S'il y a des liens il y a probablement déjà un modèle date, évitons de l'exècuter une 2e fois
if ( naissance or mort ) and ( affichageDate:match( 'wikidata%-linkback' ))  then
dateNaissance = analyseDate( args[2] )
dateMort = analyseDate( args[3] )
resultatDate = affichageDate
else  
else  
return annee
return affichageDate
end
end
else
else
-- si annee n'est pas précisé, on utilise la paramètre date
affichageDateTab, complementDate = analyseDate( affichageDate )
local date = Outils.validTextArg( args, 'date' )
if type( affichageDateTab ) ~= 'table' then
if date then  
return affichageDateTab
return '<span class="nowrap">' .. date .. '</span>'
else
else
if naissance then
return ''
dateNaissance = affichageDateTab
dateMort = analyseDate( args[3] )
elseif mort then
dateNaissance = analyseDate( args[2] )
dateMort = affichageDateTab
else
qualificatif = args[3]
end
affichageDateTab.naissance = naissance
affichageDateTab.mort = mort
affichageDateTab.qualificatif = args.qualificatif or qualificatif
affichageDateTab.nolinks = args.nolinks
affichageDateTab.nocat = args.nocat
affichageDateTab.julien = args.julien
end
end
resultatDate = resultatDate or fun.modeleDate( affichageDateTab )
local age, prefixAge, suffixAge, calculAge = '', ' <span class="noprint">(', ')</span>', nil
if naissance and dateNaissance and not dateMort and type( dateNaissance ) == 'table' then
calculAge = fun.age( dateNaissance.annee, dateNaissance.numMois, dateNaissance.jour )
if calculAge and calculAge > 120 then
calculAge = nil
end
elseif mort and dateNaissance and dateMort and type( dateNaissance ) == 'table' and type( dateMort ) == 'table' then
calculAge = fun.age( dateNaissance.annee, dateNaissance.numMois, dateNaissance.jour, dateMort.annee, dateMort.numMois, dateMort.jour )
prefixAge = ' (à '
suffixAge = ')'
end
if tonumber( calculAge ) then
if calculAge > 1 then
age = prefixAge .. calculAge .. '&nbsp;ans' .. suffixAge
elseif calculAge == 1 then
age = prefixAge .. 'un&nbsp;an' .. suffixAge
elseif calculAge == 0 then
age = prefixAge .. 'moins d’un&nbsp;an' .. suffixAge
end
if complementDate and complementDate:match( 'ans?%)' ) then
complementDate = ''
end
end
end
end
return resultatDate .. ( complementDate or '' ) .. age
end
end


---
---
Ligne 444 : Ligne 846 :
local args = Outils.extractArgs( frame )
local args = Outils.extractArgs( frame )
local annee = Outils.notEmpty( args['année'], args.annee, args.year, args.date )
local annee = Outils.notEmpty( args['année'], args.annee, args.year, args.date )
-- extraction de l'année  
-- extraction de l'année
if type( annee ) == 'string' then  
if type( annee ) == 'string' then
annee = ( tonumber( annee ) -- match '2013'
annee = ( tonumber( annee ) -- match '2013'
or string.match ( annee, '%D(%d%d%d%d)%D' ) -- match  '[[2013 en musique|2013]]'
or string.match ( annee, '%D(%d%d%d%d)%D' ) -- match  '[[2013 en musique|2013]]'
or string.match ( annee, '%D(%d%d%d%d)$' )  -- match '17 septembre 2013'
or string.match ( annee, '%D(%d%d%d%d)$' )  -- match '17 septembre 2013'
or string.match ( annee, '^(%d%d%d%d)%D' )  -- match '2013-09-17'
or string.match ( annee, '^(%d%d%d%d)%D' )  -- match '2013-09-17'
)
)
end
end
annee = tonumber( annee )
annee = tonumber( annee )
-- le format de date iso est défini suivant le calendrier grégorien.  
-- le format de date iso est défini suivant le calendrier grégorien.
-- Avant l'année 1583 la date est calendrier est probablement du calendrier julien,  
-- Avant l'année 1583 la date est calendrier est probablement du calendrier julien,
-- donc autant s'abstenir.
-- donc autant s'abstenir.
if annee and annee > 1582  then
if annee and annee > 1582  then
Ligne 485 : Ligne 887 :
-- Usage : do_dayRank{année,mois,jour}
-- Usage : do_dayRank{année,mois,jour}
function fun.do_dayRank(arguments)
function fun.do_dayRank(arguments)
    local yr = tonumber(arguments.year or arguments[1]) or 1
local yr = tonumber(arguments.year or arguments[1]) or 1
    local mt = tonumber(arguments.month or arguments[2]) or 1
local mt = tonumber(arguments.month or arguments[2]) or 1
    local dy = tonumber(arguments.day or arguments[3]) or 1
local dy = tonumber(arguments.day or arguments[3]) or 1
    -- Rangs des premiers des mois
-- Rangs des premiers des mois
    local ranks = {0,31,59,90,120,151,181,212,243,273,304,334}
local ranks = {0,31,59,90,120,151,181,212,243,273,304,334}
   
    local rank = (ranks[mt] or 0) + dy - 1
local rank = (ranks[mt] or 0) + dy - 1
    if(fun.isLeapYear(yr) and (mt >= 3)) then
if(fun.isLeapYear(yr) and (mt >= 3)) then
        rank = rank+1
rank = rank+1
    end
end
    return rank
return rank
end
end


Ligne 501 : Ligne 903 :
-- Suit le calendrier grégorien
-- Suit le calendrier grégorien
function fun.do_daysBetween(arguments)
function fun.do_daysBetween(arguments)
    local yr1 = tonumber(arguments[1]) or 0
local yr1 = tonumber(arguments[1]) or 0
    local yr2 = tonumber(arguments[2]) or 0
local yr2 = tonumber(arguments[2]) or 0
   
    return fun.daysSinceOrigin(yr2) - fun.daysSinceOrigin(yr1)
return fun.daysSinceOrigin(yr2) - fun.daysSinceOrigin(yr1)
end
end


-- Nombre de jours depuis l'année 1 (du 1er janvier au 1er janvier)
-- Nombre de jours depuis l'année 1 (du 1er janvier au 1er janvier)
function fun.daysSinceOrigin(year)
function fun.daysSinceOrigin(year)
    local yr = year-1
local yr = year-1
    return 365*yr + math.floor(yr/4) - math.floor(yr/100) + math.floor(yr/400)
return 365*yr + math.floor(yr/4) - math.floor(yr/100) + math.floor(yr/400)
end
end


-- Test d'année bissextile (Suit le calendrier grégorien)
-- Test d'année bissextile (Suit le calendrier grégorien)
function fun.isLeapYear(year)
function fun.isLeapYear(year)
    local yr = tonumber(year) or 1
local yr = tonumber(year) or 1
    return (yr%4 == 0) and ((yr%100 ~= 0) or (yr%400 == 0))
return (yr%4 == 0) and ((yr%100 ~= 0) or (yr%400 == 0))
end
end


-- Conversion d'un nombre en chiffres romains
-- Conversion d'un nombre en chiffres romains
function fun.toRoman(number)
function fun.toRoman(number)
    local n = math.floor(number)
local n = math.floor(number)
    local letters = {"I","V","X","L","C","D","M","",""}
local letters = {"I","V","X","L","C","D","M","",""}
    local pattern = {"","0","00","000","01","1","10","100","1000","02"}
local pattern = {"","0","00","000","01","1","10","100","1000","02"}
    local result = ""
local result = ""
    if(n<=0 or n>=4000) then
if(n<=0 or n>=4000) then
        result = "---"
result = "---"
    else
else
        for i=1,7,2 do
for i=1,7,2 do
            p = pattern[n%10 + 1]
local p = pattern[n%10 + 1]
            for j=0,2 do
for j=0,2 do
                p = string.gsub(p,tostring(j),letters[i+j])
p = string.gsub(p,tostring(j),letters[i+j])
            end
end
            result = p .. result
result = p .. result
            n = math.floor(n/10)
n = math.floor(n/10)
        end
end
    end
end
    return result
return result
end
end


-- Conversion et affichage d'une date dans le calendrier républicain
-- Conversion et affichage d'une date dans le calendrier républicain
function fun.dateRepublicain(frame)
function fun.dateRepublicain(frame)
    local pframe = frame:getParent()
local pframe = frame:getParent()
    local arguments = pframe.args
local arguments = pframe.args
    return fun.formatRepCal(fun.do_toRepCal(arguments))
return fun.formatRepCal(fun.do_toRepCal(arguments))
end
end


Ligne 551 : Ligne 953 :
-- On suppose que les années 4n+3 sont sextiles (3, 7, 11...)
-- On suppose que les années 4n+3 sont sextiles (3, 7, 11...)
function fun.do_toRepCal(arguments)
function fun.do_toRepCal(arguments)
    local yr = tonumber(arguments.year or arguments[1]) or 2000
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)
-- 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 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 repYear = math.floor((repDays+731)/365.25) - 1
    local repDayRank = repDays - 365*(repYear-1) - math.floor(repYear/4)
local repDayRank = repDays - 365*(repYear-1) - math.floor(repYear/4)
    local repMonth, repDay = math.floor(repDayRank/30)+1, (repDayRank%30)+1
local repMonth, repDay = math.floor(repDayRank/30)+1, (repDayRank%30)+1
    return {repYear, repMonth, repDay}
return {repYear, repMonth, repDay}
end
end


Ligne 564 : Ligne 966 :
-- Usage : fun.formatRepCal{année,mois,jour}
-- Usage : fun.formatRepCal{année,mois,jour}
function fun.formatRepCal(arguments)
function fun.formatRepCal(arguments)
    local months = {"Vendémiaire","Brumaire","Frimaire","Nivôse","Pluviôse","Ventôse","Germinal","Floréal","Prairial","Messidor","Thermidor","Fructidor"}
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 extras = {"de la vertu","du génie","du travail","des récompenses","de l'opinion","de la révolution"}
    local result = ""
local result = ""
    if(arguments[2] < 13) then
if(arguments[2] < 13) then
        result = result .. tostring(arguments[3]) .. "&nbsp;" .. months[arguments[2]]
result = result .. tostring(arguments[3]) .. "&nbsp;" .. months[arguments[2]]
    else
else
        result = result .. "jour " .. extras[arguments[3]]
result = result .. "jour " .. extras[arguments[3]]
    end
end
    result = result .. " de l'an " .. fun.toRoman(arguments[1])
result = result .. " de l'an " .. fun.toRoman(arguments[1])
    return result
return result
end
end


Ligne 583 : Ligne 985 :
-- 4, 5, 6 : année, mois, joue du calcul (facultatif, par défaut la date UTC courante).
-- 4, 5, 6 : année, mois, joue du calcul (facultatif, par défaut la date UTC courante).
function fun.age( an, mn, jn, ac, mc, jc )
function fun.age( an, mn, jn, ac, mc, jc )
    local an = tonumber( an )  
if ac == nil then
    if an == nil then  
local today = os.date( '!*t' )
        -- pas de message d'erreur qui risque de faire planter la fonction appelante
ac = today.year
        -- à elle de gérer ce retour.
mc = today.month
        return  
jc = today.day
    end
else
    -- les jours et mois sont par défaut égal à 1, pour pouvoir calculer un age même si la date est incompète.
ac = tonumber( ac )
    local mn = tonumber( mn ) or 1
mc = tonumber( mc )
    local jn = tonumber( jn ) or 1
jc = tonumber( jc )
   
end
    local today = os.date( '!*t' )
 
    local ac = tonumber( ac ) or today.year
local an = tonumber( an )
    local mc = tonumber( mc ) or today.month
local mn = tonumber( mn )
    local jc = tonumber( jc ) or today.day
local jn = tonumber( jn )
   
 
    local age = ac - an
if an == nil or ac == nil or mn == nil or mc == nil then
    if mc < mn or ( mc == mn and jc < jn ) then
-- pas de message d'erreur qui risque de faire planter la fonction appelante
        age = age - 1
-- à elle de gérer ce retour.
    end
return
    return age
end
local age = ac - an
if mc == mn then
if jc == nil or jn == nil then
return
end
return age-tonumber( jc < jn and 1 or 0 )
else
return age-tonumber( mc < mn and 1 or 0 )
end
end
end


function fun.modeleAge( frame )
function fun.modeleAge( frame )
    args = frame.getParent().args
local args = frame.getParent().args
    local annee = args[1] or args['année']
local age = fun.age (
    if annee == nil then
args[1] or args['année'],
        return Outils.erreur( "Il faut au minimum l'année pour calculer un âge" )
args[2] or args['mois'],
    end       
args[3] or args['jour'],
    local age = fun.age (
args[4],
        args[1] or args['année'],
args[5],
        args[2] or args['mois'],
args[6]
        args[3] or args['jour'],
)
        args[4],
if age then
        args[5],
return age
        args[6]
else
    )
return Outils.erreur("Paramètres incorrects ou insuffisants ou pour calculer l'âge précis" )
    if age then
end
        return age
    else  
        return Outils.erreur("les paramètres doivent être des chiffres" )
    end
end
end


Ligne 629 : Ligne 1 037 :
-- calcul du jour julien à partir d'une date du calendrier grégorien
-- calcul du jour julien à partir d'une date du calendrier grégorien
function fun.julianDay( year, month, day, hour, min, sec )
function fun.julianDay( year, month, day, hour, min, sec )
    local julian  
local julian
    julian = math.floor( math.floor( ( year * 12 + month + 57609 ) / 12 - 1 ) * 1461 / 4 )
julian = math.floor( math.floor( ( year * 12 + month + 57609 ) / 12 - 1 ) * 1461 / 4 )
          - math.floor( math.floor( ( year * 12 + month + 57609 ) / 12 - 1 ) / 100 )
- math.floor( math.floor( ( year * 12 + month + 57609 ) / 12 - 1 ) / 100 )
          + math.floor( math.floor( ( year * 12 + month + 57609 ) / 12 - 1 ) / 400 )
+ math.floor( math.floor( ( year * 12 + month + 57609 ) / 12 - 1 ) / 400 )
          + math.floor( ( math.fmod( month + 57609, 12 ) + 4 ) * 153 / 5 )
+ math.floor( ( math.fmod( month + 57609, 12 ) + 4 ) * 153 / 5 )
          + day + ( hour or 12 ) / 24 + ( min or 0 ) / 1440 + ( sec or 0 ) / 86400
+ day + ( hour or 12 ) / 24 + ( min or 0 ) / 1440 + ( sec or 0 ) / 86400
          - 32167.5
- 32167.5
    return julian
return julian
end
end


---
---
-- calcul du jour julien à partir d'une date du calendrier julier
-- calcul du jour julien à partir d'une date du calendrier julien
function fun.julianDayJulian( year, month, day, hour, min, sec )
function fun.julianDayJulian( year, month, day, hour, min, sec )
    local julian  
local julian
    julian = math.floor( math.floor( ( year * 12 + month + 57609 ) / 12 - 1 ) * 1461 / 4 )
julian = math.floor( math.floor( ( year * 12 + month + 57609 ) / 12 - 1 ) * 1461 / 4 )
          + math.floor( ( math.fmod( month + 57609, 12 ) + 4 ) * 153 / 5 )
+ math.floor( ( math.fmod( month + 57609, 12 ) + 4 ) * 153 / 5 )
          + day + ( hour or 12 ) / 24 + ( min or 0 ) / 1440 + ( sec or 0 ) / 86400
+ day + ( hour or 12 ) / 24 + ( min or 0 ) / 1440 + ( sec or 0 ) / 86400
          - 32205.5
- 32205.5
    return julian
return julian
end
end


Ligne 653 : Ligne 1 061 :
-- calcul d'une date dans le calendrier grégorien à partir du jour julien
-- calcul d'une date dans le calendrier grégorien à partir du jour julien
function fun.julianDayToGregorian( julianDay )
function fun.julianDayToGregorian( julianDay )
    local base = math.floor( julianDay + 32044.5 )  -- 1 March -4800 (proleptic Gregorian date)
local base = math.floor( julianDay + 32044.5 )  -- 1 March -4800 (proleptic Gregorian date)
    local nCentury = math.floor( ( base * 4 + 3 ) / 146097 )
local nCentury = math.floor( ( base * 4 + 3 ) / 146097 )
    local sinceCentury = base - math.floor( nCentury * 146097 / 4 )
local sinceCentury = base - math.floor( nCentury * 146097 / 4 )
    local nYear = math.floor( ( sinceCentury * 4 + 3 ) / 1461 )
local nYear = math.floor( ( sinceCentury * 4 + 3 ) / 1461 )
    local sinceYear = sinceCentury - math.floor( nYear * 1461 / 4 )
local sinceYear = sinceCentury - math.floor( nYear * 1461 / 4 )
    local nMonth = math.floor( ( sinceYear * 5 + 2 ) / 153 )
local nMonth = math.floor( ( sinceYear * 5 + 2 ) / 153 )
   
    local day = sinceYear - math.floor( (  nMonth  * 153 + 2 ) / 5 ) + 1
local day = sinceYear - math.floor( (  nMonth  * 153 + 2 ) / 5 ) + 1
    local month = nMonth  - math.floor(  nMonth  / 10 ) * 12 + 3
local month = nMonth  - math.floor(  nMonth  / 10 ) * 12 + 3
    local year = math.floor( sinceYear / 306 ) + nYear + 100 * nCentury - 4800
local year = math.floor( sinceYear / 306 ) + nYear + 100 * nCentury - 4800
   
    return year, month, day
return year, month, day
end
end


Ligne 672 : Ligne 1 080 :
function fun.julianDayToJulian( julianDay )
function fun.julianDayToJulian( julianDay )
local year = math.modf( ( julianDay * 4 - 6884469 ) / 1461 )
local year = math.modf( ( julianDay * 4 - 6884469 ) / 1461 )
local r2 = julianDay - math.modf( ( 1461 * year + 6884472 ) / 4 )  
local r2 = julianDay - math.modf( ( 1461 * year + 6884472 ) / 4 )
local month = math.modf( ( 5 * r2 + 461 ) / 153 )
local month = math.modf( ( 5 * r2 + 461 ) / 153 )
local day = r2 - math.modf( ( 153 * month - 457 ) / 5 ) + 1
local day = r2 - math.modf( ( 153 * month - 457 ) / 5 ) + 1
Ligne 685 : Ligne 1 093 :
-- calcul d'une date dans le calendrier grégorien à partir d'une date dans le calendrier julien
-- calcul d'une date dans le calendrier grégorien à partir d'une date dans le calendrier julien
function fun.julianToGregorian( year, month, day )
function fun.julianToGregorian( year, month, day )
    return fun.julianDayToGregorian( fun.julianDayJulian( year, month, day ) )
return fun.julianDayToGregorian( fun.julianDayJulian( year, month, day ) )
end
end


Ligne 694 : Ligne 1 102 :
if month then month = tonumber(month) else month = 6 end --prend une valeur centrale pour donner un best "guess"
if month then month = tonumber(month) else month = 6 end --prend une valeur centrale pour donner un best "guess"
if day then day = tonumber(day) else day = 15 end
if day then day = tonumber(day) else day = 15 end
    return fun.julianDayToJulian( fun.julianDay( year, month, day ) )
return fun.julianDayToJulian( fun.julianDay( year, month, day ) )
end
end


Ligne 703 : Ligne 1 111 :
-- pour la page de discussion de la base de donnée et ceux qui veulent surveiller cette page.
-- pour la page de discussion de la base de donnée et ceux qui veulent surveiller cette page.
function fun.erreurModuleData()
function fun.erreurModuleData()
    local success, resultat = pcall ( mw.loadData, 'Module:Date/Data' )
local success, resultat = pcall ( mw.loadData, 'Module:Date/Data' )
    if success == false then  
if success == false then
        local message = [[<strong class="error">Le chargement du module Date/Data génère une erreur : </strong><br />%s<br />
local message = [[<strong class="error">Le chargement du module Date/Data génère une erreur : </strong><br />%s<br />


<span class="error">Cette erreur doit être corrigée au plus vite car des milliers de page ne s'affichent pas correctement</span>
<span class="error">Cette erreur doit être corrigée au plus vite car des milliers de page ne s'affichent pas correctement</span>
]]
]]
        return string.format( message, resultat )
return string.format( message, resultat )
    end
end
end
end


Ligne 716 : Ligne 1 124 :
-- checkDataCat génère des liens vers les pages annuelles, mensuelles et d'éphémérides liè aux
-- checkDataCat génère des liens vers les pages annuelles, mensuelles et d'éphémérides liè aux
-- catégories du Module:Date/Data. La date la plus ancienne dépend de 'aucun' et 'seul[1]'
-- catégories du Module:Date/Data. La date la plus ancienne dépend de 'aucun' et 'seul[1]'
-- Paramètres :  
-- Paramètres :
-- 1 : la catégorie. Il y aura une section par qualificatif de cette catégorie.
-- 1 : la catégorie. Il y aura une section par qualificatif de cette catégorie.
-- mois : oui pour avoir les liens vers les pages mensuelles et éphémérides (4 jours dans l'année)
-- mois : oui pour avoir les liens vers les pages mensuelles et éphémérides (4 jours dans l'année)
-- alias : pour avoir des lien pour les alias en plus des qualificatif
-- alias : pour avoir des lien pour les alias en plus des qualificatif
function fun.checkDataCat( frame )
function fun.checkDataCat( frame )
    local category = trim(frame.args[1])
local category = trim(frame.args[1])
    local monthLinks = frame .args.mois == 'oui'
local monthLinks = frame .args.mois == 'oui'
    local alias = frame.args.alias == 'oui'
local alias = frame.args.alias == 'oui'
    local dataLink = mw.loadData( 'Module:Date/Data' )
local dataLink = mw.loadData( 'Module:Date/Data' )
    local wikiList =  TableBuilder.new()
local wikiList =  TableBuilder.new()
    local currentYear = tonumber( os.date( '%Y' ) )
local currentYear = tonumber( os.date( '%Y' ) )
    local columns = '<div style="-moz-column-width:5em;-webkit-column-width:5em;column-width:5em;-moz-column-gap:1em;-webkit-column-gap:1em;column-gap:1em;text-align:left;">'
local columns = '<div style="-moz-column-width:5em;-webkit-column-width:5em;column-width:5em;-moz-column-gap:1em;-webkit-column-gap:1em;column-gap:1em;text-align:left;">'
    local newSection  
local newSection
    if monthLinks then  
if monthLinks then
        newSection = '\n\n== %s ==\n\n=== Années ===\n' .. columns
newSection = '\n\n== %s ==\n\n=== Années ===\n' .. columns
    else
else
        newSection ='\n\n== %s ==\n' .. columns
newSection ='\n\n== %s ==\n' .. columns
    end
end
    for field, dataField in pairs( dataLink ) do
for field, dataField in pairs( dataLink ) do
        -- boucle sur tous les qualificatif ayant pour catégorie le premier paramère
-- boucle sur tous les qualificatif ayant pour catégorie le premier paramère
        if dataField.cat == category or ( category == 'cat' and dataField.cat == field ) then
if dataField.cat == category or ( category == 'cat' and dataField.cat == field ) then
            local monthInitialYear, initialYear
local monthInitialYear, initialYear
            -- définition de l'année à partir de laquelle on va tester toutes les année / mois
-- définition de l'année à partir de laquelle on va tester toutes les année / mois
            if dataField.qualificatif == field or ( category == 'cat' and dataField.cat == field ) then
if dataField.qualificatif == field or ( category == 'cat' and dataField.cat == field ) then
                if dataField.annee and dataField.annee.aucun and dataField.annee.aucun < currentYear then
if dataField.annee and dataField.annee.aucun and dataField.annee.aucun < currentYear then
                    local aucun = ( dataField.annee.seul and dataField.annee.seul[1] ) or dataField.annee.aucun
local aucun = ( dataField.annee.seul and dataField.annee.seul[1] ) or dataField.annee.aucun
                    initialYear = math.min( aucun - math.ceil( (currentYear - aucun) / 4 ), currentYear - 50 )
initialYear = math.min( aucun - math.ceil( (currentYear - aucun) / 4 ), currentYear - 50 )
                else  
else
                    initialYear = currentYear - 50
initialYear = currentYear - 50
                end
end
                if dataField.mois and tonumber( dataField.mois.aucun ) and ( tonumber( dataField.mois.aucun ) < currentYear ) then
if dataField.mois and tonumber( dataField.mois.aucun ) and ( tonumber( dataField.mois.aucun ) < currentYear ) then
                    local aucun = dataField.mois.aucun
local aucun = dataField.mois.aucun
                    monthInitialYear = math.min( aucun - math.ceil( (currentYear - aucun) / 4 ), currentYear - 8 )
monthInitialYear = math.min( aucun - math.ceil( (currentYear - aucun) / 4 ), currentYear - 8 )
                else  
else
                    monthInitialYear = currentYear - 8
monthInitialYear = currentYear - 8
                end
end
            elseif alias then
elseif alias then
                -- si le paramètre alias est défini on teste aussi tous les alias, sinon ils sont ignorés
-- si le paramètre alias est défini on teste aussi tous les alias, sinon ils sont ignorés
                initialYear = currentYear - 50
initialYear = currentYear - 50
                monthInitialYear = currentYear - 8
monthInitialYear = currentYear - 8
            end
end
           
            -- création de l'ensembles des liens
-- création de l'ensembles des liens
            if initialYear then
if initialYear then
                -- ajout de lien vers les pages annuelles de l'année en court + 5 jusqu'à initialYear
-- ajout de lien vers les pages annuelles de l'année en court + 5 jusqu'à initialYear
                wikiList.insert( string.format( newSection, field ) )
wikiList.insert( string.format( newSection, field ) )
                local fieldLink = ' ' .. field
local fieldLink = ' ' .. field
                if category == 'cat' then  
if category == 'cat' then
                    fieldLink = ' ' .. dataField.qualificatif
fieldLink = ' ' .. dataField.qualificatif
                end
end
                for year = ( currentYear + 5 ), initialYear, -1  do
for year = ( currentYear + 5 ), initialYear, -1  do
                    wikiList.insert( '\n* [[' .. year .. fieldLink ..'|' .. year .. ']]' )
wikiList.insert( '\n* [[' .. year .. fieldLink ..'|' .. year .. ']]' )
                end
end
                wikiList.insert( '\n</div>' )
wikiList.insert( '\n</div>' )
               
                if monthLinks then
if monthLinks then
                    -- insertstion de liens vers les mois de l'année en court + 1 jusqu'à monthInitialYear
-- insertstion de liens vers les mois de l'année en court + 1 jusqu'à monthInitialYear
                    wikiList.insert( '\n\n=== Mois ==='  )
wikiList.insert( '\n\n=== Mois ==='  )
                    local month, sep
local month, sep
                    for year = ( currentYear + 1 ), monthInitialYear, -1  do
for year = ( currentYear + 1 ), monthInitialYear, -1  do
                        wikiList.insert( '\n* ' .. year .. ' : ' )
wikiList.insert( '\n* ' .. year .. ' : ' )
                        sep = ' • '
sep = ' • '
                        for j = 1, 12 do  
for j = 1, 12 do
                            month = ucfirst( liste_mois[j][1] ) .. ' '
month = ucfirst( liste_mois[j][1] ) .. ' '
                            if j == 12 then sep = ''
if j == 12 then sep = ''
                            end
end
                            wikiList.insert( '[[' .. month .. year .. ' ' .. fieldLink .. '|' .. month .. ']]' .. sep )
wikiList.insert( '[[' .. month .. year .. ' ' .. fieldLink .. '|' .. month .. ']]' .. sep )
                        end
end
                    end
end
                   
                    -- insertion de quelques date pour tester les éphémérides
-- insertion de quelques date pour tester les éphémérides
                    wikiList.insert( '\n\n=== Jours ==='  )
wikiList.insert( '\n\n=== Jours ==='  )
                    wikiList.insert( '\n* [[1er janvier ' .. fieldLink .. ']]' )
wikiList.insert( '\n* [[1er janvier ' .. fieldLink .. ']]' )
                    wikiList.insert( '\n* [[14 mars ' .. fieldLink .. ']]' )
wikiList.insert( '\n* [[14 mars ' .. fieldLink .. ']]' )
                    wikiList.insert( '\n* [[22 juin ' .. fieldLink .. ']]' )
wikiList.insert( '\n* [[22 juin ' .. fieldLink .. ']]' )
                    wikiList.insert( '\n* [[3 septembre ' .. fieldLink .. ']]' )
wikiList.insert( '\n* [[3 septembre ' .. fieldLink .. ']]' )
                end
end
            end
end
        end
end
    end
end
   
    return table.concat( wikiList )
return table.concat( wikiList )
end
 
--[[
  Cette fonction retourne "CET" ou "CEST" selon que dans la pseudo-timezone en cours
    c'est l'heure d'été ou l'heure d'hiver.
  Cette fonction n'a de sens a priori que pour des modèles utilisés en Europe
 
  Paramètre optionnel non nommé : "sans lien" : retourne le texte CET/CEST. sinon
    retourne ce même texte avec un wikilien vers les articles correspondant
--]]
function fun.CEST(frame)
-- option : ne pas créer de wikilien
local opt = trim(frame.args[1] or frame:getParent().args[1])
-- on récupère l'information dans la zone courante
local t = mw.getContentLanguage():formatDate("I", nil, true)
if (t == "1") then  -- heure d'été
if (opt == "sans lien") then
return "CEST"
elseif (opt == "décalage") then
return "2"
else
return "[[Heure d'été d'Europe centrale|CEST]]"
end
else  -- heure d'hiver (ou autre zone où ça ne s'applique pas)
if (opt == "sans lien") then
return "CET"
elseif (opt == "décalage") then
return "1"
else
return "[[Heure normale d'Europe centrale|CET]]"
end
end
end
end


return fun
return fun

Dernière version du 23 septembre 2017 à 19:33

local fun = {}

local TableBuilder = require( 'Module:TableBuilder' ) local Outils = require( 'Module:Outils' ) -- chargement de la base de donnée répertoriant certaines pages existant ou n'existant pas pour éviter les "ifexist". local dataLiens local success, resultat = pcall ( mw.loadData, 'Module:Date/Data' ) if success then dataLiens = resultat else -- protection au cas ou le sous module serait mal modifié dataLiens = { [] = { mois = { aucun = 1000, tous = { 1773, 2014 } }, } } end

-- nettoie un paramètre non nommé (vire les espaces au début et à la fin) -- retourne nil si le texte est vide ou n'est pas du texte. Attention c'est important pour les fonction qui l'utilise. local trim = Outils.trim

-- Fonction destiné à mettre la première lettre du mois en majuscule du mois : -- utilisation de string car aucun mois ne commance par une lettre non ascii en français ou anglais. local function ucfirst( str ) return str:sub( 1, 1 ):upper() .. str:sub( 2 ) end

local modelePremier = '1er'


-- liste des mois, écriture exacte et simplifiée, en minuscule local liste_mois = { { "janvier", "jan.", "janv.", "jan", "janv", "january", nJour = 31 }, { "février", "fevrier", "fev.", "fev", "fév.", "fév", "february", nJour = 29 }, { "mars", "mar.", "mar", "march", nJour = 31 }, { "avril", "avr.", "avr", "apr", "april", nJour = 30 }, { "mai", "may", nJour = 31 }, { "juin", "jun", "june", nJour = 30 }, { "juillet", "juil.", "juil", "juill.", "juill", "jul", "july", nJour = 31 }, { "août", "aout", "aou", "aug", "august", nJour = 31 }, { "septembre", "sept.", "sept", "sep.", "sep", "september", nJour = 30 }, { "octobre", "oct.", "oct", "october", nJour = 31 }, { "novembre", "nov.", "nov", "november", nJour = 30 }, { "décembre", "decembre", "déc.", "dec.", "dec", "déc", "december", nJour = 31 }, } fun.liste_mois = liste_mois

local liste_saison = { { 'printemps', 'spring', }, { 'été', 'summer', }, { 'automne', 'autumn', }, { 'hiver', 'winter', }, }

-- nom du mois à partir du numéro function fun.nomDuMois( num ) if type( num ) ~= "number" or num < 1 or num > 12 then return nil end return liste_mois[num][1] 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 = trim( mois ) if m then m = mw.ustring.lower( m ) for i = 1, 12 do local j = 1 while liste_mois[i][j] do if liste_mois[i][j] == m then return liste_mois[i][1], i end j = j + 1 end end end -- pas trouvé = return nil 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.valideSaison( saison ) if type( saison ) ~= "string" then return nil end

local m = mw.ustring.lower( trim( saison ) )

for i = 1, 4 do local j = 1 while liste_saison[i][j] ~= nil do if liste_saison[i][j] == m then return liste_saison[i][1] end j = j + 1 end end -- pas trouvé = return nil end

--- -- determinationMois trouve le numéro du mois et son nom, -- à partir de son nom, de son numéro ou d'une expression mathématique. -- Si le deuxième paramètre est vrai, les nombres supérieur à 12 ou non entiers sont acceptés. function fun.determinationMois( mois, mod, boucle ) local num, nom if tonumber( mois ) then num = math.floor( tonumber( mois ) ) if mod then -- si le nombre du mois est calculé par une exression, le résultat peut être supérieur à 12, ou inférieur à 1 num = math.fmod( num + 239, 12 ) + 1 -- +239 car fmod(-1) = -1 et non 11 elseif num < 1 or num > 12 then num = nil end elseif trim( mois ) then nom, num = fun.valideMois( mois ) if nom == nil and boucle == nil then -- essai de détermination d'un nombre avec le parser #expr de Mediawiki. -- le paramètre boucle évite de tourner en boucle. nom, num = fun.determinationMois( mw.getCurrentFrame():callParserFunction( '#expr', mois ), true, true ) end end if num and not nom then nom = liste_mois[num][1] end return nom, num end


-- fonction interne à modeleDate, pour déterminer si on peut se passer de faire un ifexit local function existDate( dataQualificatif, annee, mois ) local data if mois then data = dataQualificatif.mois else data = dataQualificatif.annee end if type( data ) ~= 'table' then -- si data n'existe pas c'est que l'on considère qu'il n'y a pas de lien. return end -- le qualificatif est remplacer par celui de la base de donnée, ce qui permet des alias. local lien = annee .. ' ' .. ( dataQualificatif.qualificatif or ) local seul = annee if mois then lien = mois .. ' ' .. lien seul = ucfirst( mois ) .. ' ' .. annee end local aucun = tonumber( data.aucun ) if aucun and annee <= aucun then -- si la l'année est dans la partie 'aucun' on teste s'il y a malgré tout un lien isolé if type( data.seul ) == 'table' then for i, v in ipairs( data.seul ) do if seul == v or seul == tonumber( v ) then return lien end end end -- partie aucun et pas de lien => nil return nil elseif type( data.tous ) == 'table' then local tous1, tous2 = tonumber( data.tous[1] ), tonumber( data.tous[2] ) if tous1 and tous2 and annee >= tous1 and annee <= tous2 then -- l'année est dans la partie 'tous' donc on retourne le lien return lien end end -- l'annee n'est ni dans la partie aucun, ni dans la partie tous donc il faut tester si la page existe. local cibleLien = mw.title.new( lien ) if cibleLien and cibleLien.exists then return lien end end

--- -- Supprime le jour de la semaine, et "le" avant une date function fun.nettoyageJour( jour ) if type( jour ) == 'string' then local nomJour = { '[Ll]undi', '[Mm]ardi', '[Mm]ercredi', '[Jj]eudi', '[Vv]endredi', '[Ss]amedi', '[Dd]imanche', '^ *[Ll]e' } local premier = { '1er', '1er', '1er' } for i, v in ipairs( nomJour ) do jour = jour:gsub( v, ) end for i, v in ipairs( premier ) do jour = jour:gsub( v, '1' ) end jour = trim( jour ) end return jour end

--- -- Sépare une chaine date en un table contenant les champs jour, mois et annee. -- la date doit contenir le mois. function fun.separationJourMoisAnnee( date ) date = trim( date ) if date then local function erreur( periode, valeur ) return false, Outils.erreur( periode .. ' invalide (' .. valeur .. ')' ) end local jour, mois, annee, masquerMois, masquerAnnee, separateur -- variable pour construire les regex local j = '([0-3]?%d)' -- jour local m = '([01]?%d)' -- mois numérique local mmm = '([^%s%p%d]+[.]?)' -- mois en toute lettre local aj = '(%-?%d+)' -- année ou jour local s = '[ ./-]+' -- séparateur simple local sep = '([ ./-]+)' -- séparateur avec capture, pour le détecter deux fois local moins = '(%-?)' -- signe moins pour signifier qu'il ne faut pas afficher cette donnée local regexb = { jmmm = '^'..j..s..mmm..moins..'$', mmmjva = '^'..mmm..s..j..', ?'..aj..'$', }

date = fun.nettoyageJour( date ) -- suppression catégorie, liens, balises date = mw.ustring.gsub( date, '%[%[[Cc]at[ée]gor[yi]e?:.-%]%]', ) date = date :gsub( '%b<>', ) :gsub( '%[%[([^%[%]|]*)|?([^%[%]]*)%]%]', function ( l, t ) return trim( t ) or l end ) -- suppression des espaces insécables :gsub( '\194\160', ' ' ) :gsub( ' ', ' ' ) :gsub( '\226\128\175', ' ' ) :gsub( '&nnbsp;', ' ' ) :gsub( '\226\128\137', ' ' ) :gsub( ' ', ' ' ) :gsub( ' ', ' ' ) :gsub( ' +', ' ' ) -- réduction av. J-C pour simplifier un peu les regex : :gsub( '(%d+) ?[Aa][Vv]%.? ?[Jj][ .-]*[Cc]%.?', '-%1' ) -- supression de l'heure dans les date ISO :gsub( '^+?([%d-]*%d%d%-%d%d)T%d%d[%d:,.+-]*Z?$' , '%1')

-- test année seule if date:match( '^'..aj..'$' ) then annee = date:match( '^'..aj..'$' ) elseif date:match( '^'..aj..s..aj..moins..'$' ) then -- jj/mm, mm/aaaa ou aaaa/mm local a, separateur, b, sb = date:match( '^'..aj..sep..aj..moins..'$' ) a, b = tonumber( a ), tonumber( b ) if separateur:match( '^.+%-$' ) then -- probablement mm/-aaaa, année av.JC b = 0 - b end if a > 12 and ( b < 1 or b > 31 ) or b > 12 and ( a < 1 or a > 31 ) then return erreur( 'Date', date ) elseif b < 1 or b > 31 then mois, annee, masquerAnnee = a, b, sb elseif a < 1 or a > 31 then annee, mois = a, b elseif b > 12 then return erreur( 'Mois', b ) else jour, mois, masquerMois = a, b, sb end elseif date:match( '^'..aj..sep..m..moins..'%2'..aj..moins..'$' ) then -- jj/mm/aaaa ou aaaa/mm/jj jour, separateur, mois, masquerMois, annee, masquerAnnee = date:match( '^'..aj..sep..m..moins..'%2'..aj..moins..'$' ) if separateur == '-' and masquerMois == '-' and masquerAnnee == and tonumber( annee ) > 0 then -- date au format jj-mm--aaaa type 17-06--44 pour 17 juin 44 av. JC masquerMois = nil annee = 0 - annee end elseif date:match( '^'..j..sep..mmm..moins..'%2'..aj..moins..'$' ) then -- jj mmm aaaa jour, separateur, mois, masquerMois, annee, masquerAnnee = date:match( '^'..j..sep..mmm..moins..'%2'..aj..moins..'$' ) elseif date:match( '^'..mmm..s..aj..moins..'$' ) then -- mmm aaaa mois, separateur, annee, masquerAnnee = date:match( '^'..mmm..sep..aj..moins..'$' ) if separateur:match( '^.+%-$' ) then annee = '-' .. annee end elseif date:match( '^'..j..s..mmm..moins..'$' ) then -- jj mmmm jour, mois, masquerMois = date:match( '^'..j..s..mmm..moins..'$' ) elseif date:match( '^'..mmm..s..j..', ?'..aj..'$') then -- mmm jj, aaaa (format anglo-saxon) mois, jour, annee = date:match( '^'..mmm..s..j..', ?'..aj..'$') elseif date:match( '^'..mmm..'$' ) then mois = date else return erreur( 'Date', date ) end local jn, an = tonumber( jour ), tonumber( annee ) if jn and an and ( jn > 31 or jn < 0 or #jour >= 3 ) and an <= 31 then -- cas notamment des date ISO 2015-06-17, -0044-06-17 et -0002-06-17 -- inversion du jour et de l'année local temp = annee annee = jour jour = temp end

return fun.validationJourMoisAnnee{ jour, mois, annee, masquerAnnee = trim( masquerAnnee ) and true or nil, masquerMois = ( trim( masquerAnnee ) or not annee ) and trim( masquerMois ) and true or nil, -- or nil sert juste à éviter de trainer une valeur false dans tous les tests unitaires. } else return true, {} end end


--- -- separationJourMoisAnnee prend jusqu'a cinq paramètre et essaie de les séparer en jour, mois, annee et qualificatif -- la date peut être dans le premier paramètre ou séparée dans les paramètre 1 à 3 ou 2 à 4. -- Le qualificatif est cherché dans le paramètre suivant. -- La fonction retourne true suivit d'une table avec la date en paramètres nommé (sans accent sur année) -- ou false suivit d'un message d'erreur. function fun.validationJourMoisAnnee( frame, ... ) local args = Outils.extractArgs( frame, ... ) local jour, mois, numMois, annee, erreur local bjour = args[1] or args['jour'] or local bmois = tostring( args[2] or args['mois'] or ) local bannee = args[3] or args['annee'] or args['année'] or

local function erreur( periode, valeur ) return false, Outils.erreur( periode .. ' invalide (' .. valeur .. ')' ) end

-- on traite l'année if Outils.notEmpty( bannee ) then annee = tonumber( bannee ) if annee == nil and type( bannee ) == 'string' then -- test si l'année contient av. J.-C. annee = string.match( string.upper( bannee ), '^(%d+) ?[Aa][Vv]%.? ?[Jj][ .-]*[Cc]%.?' ) annee = tonumber( annee ) if annee then annee = 0 - annee else return erreur( 'Année', bannee ) end end else annee = nil end

-- on traite le mois if Outils.notEmpty( bmois ) then mois, numMois = fun.determinationMois( bmois ) if mois == nil then mois = fun.valideSaison( bmois ) if mois == nil then return erreur( 'Mois', bmois ) end else -- on traite le jour si présent if Outils.notEmpty( bjour ) then jour = tonumber( bjour ) if jour == nil then jour = tonumber( fun.nettoyageJour( bjour ) ) end if jour == nil then return erreur( 'Jour', bjour ) end -- on valide que le jour est correct if jour < 1 or jour > 31 then return erreur( 'Jour', bjour ) elseif jour > liste_mois[numMois].nJour then return erreur( 'Jour', bjour .. ' ' .. mois ) elseif jour == 29 and numMois == 2 and annee and ( math.fmod( annee, 4 ) ~= 0 ) then -- l'année bisextile sur les siècles est toujours acceptée pour être compatible avec les dates juliennes. return erreur( 'Jour', '29 février ' .. annee ) end else -- S'il n'y a pas de jour on regarde si la première lettre du mois est en majuscule if bmois:match( '^%u' ) then -- oui, on passe la première lettre en majuscule mois = ucfirst( mois ) end -- s'il n'y a pas d'année non plus on retourne le mois simple end end else -- on teste le jour si présent if Outils.notEmpty( bjour ) then if annee then return erreur( 'Mois', 'absent' ) else bjour = fun.nettoyageJour( bjour ) jour = tonumber( bjour ) if jour then if jour > 31 or jour < 1 then annee = jour jour = nil else return erreur( 'Date', 'jour seul : ' .. bjour ) end else return erreur( 'Jour', bjour ) end end end end

-- vérification de l'absence d'un décalage if annee and annee < 13 and annee > 0 and not jour and ( tonumber( bmois ) or (not mois and tonumber( args[4] ) ) ) then return false, Outils.erreur( 'année improbable (' .. annee .. ')' ) end

local resultat = { jour = jour, mois = mois, numMois = numMois, annee = annee, masquerAnnee = args.masquerAnnee, masquerMois = args.masquerMois, } return true, resultat end

function fun.modeleDateAnalyseJMA( args ) local function masquerParam( p ) -- sépare le signe moins final éventuel signifiant que le paramètre ne soit pas être affiché. local s if trim( p ) then p, s = p:match( '^(.-)(%-?)%s*$' ) end return p, ( s == '-' or nil ) end

local test, resultat local arg1, arg2, arg3 = fun.nettoyageJour( args[1] ), trim( args[2] ), trim( args[3] ) if type( arg1 ) == 'string' and arg3 == nil and ( arg1:match( '[^ ./-][ ./-]+[^ ./-]' ) or arg2 == nil or dataLiens[arg2] or mw.ustring.match( arg2, '%a %a' ) ) then -- la date est dans le premier paramètre test, resultat = fun.separationJourMoisAnnee( arg1 ) if test then resultat.qualificatif = arg2 end else local param, masquerM, masquerA param = { args[1] or args.jour } param[2], masquerM = masquerParam( args[2] or args.mois ) param[3], masquerA = masquerParam( args[3] or args.annee or args['annee'] ) param[4] = masquerParam( args[4] ) test, resultat = fun.validationJourMoisAnnee( param ) if test then resultat.masquerAnnee = masquerA resultat.masquerMois = masquerM resultat.qualificatif = trim( args[4] ) end end

return test, resultat end

--- -- émule le modèle {{Date}}. -- 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 function fun.modeleDate( frame ) local args = Outils.extractArgs( frame ) local test, params = fun.modeleDateAnalyseJMA( args ) local cat, resultat = if test then local listeParam = { qualificatif = 'qualificatif', age = 'âge', ['âge'] = 'âge', naissance = 'naissance', mort = 'mort', ['décès'] = 'mort', julien = 'julien', avJC = 'avJC', nolinks = 'nolinks', } for n, v in pairs( listeParam ) do params[v] = params[v] or args[n] end resultat = fun._modeleDate( params )

else local namespaceCategorisation = { [0] = true, [4] = true, [10] = true, [14] = true, [100] = true } if namespaceCategorisation[ mw.title.getCurrentTitle().namespace ] and not Outils.notEmpty( args.nocat ) then cat = end resultat = params .. cat end return resultat or end

function fun._modeleDate( args ) local annee, mois, numMois, jour = args.annee, args.mois, args.numMois, args.jour local qualificatif = args.qualificatif

if ( annee or mois or jour ) == nil then return end

-- on traite l'age, naissance et mort local age = trim( args['âge'] or args['age'] ) age = age and fun.age( annee, numMois, jour ) local naissance = trim( args.naissance ) local mort = trim( args.mort )

-- on traite le calendrier local gannee, gmois, gjour = annee, numMois, jour -- date suivant le calendrier grégorien pour


-- on génère le résultat

-- Déclarations des variables local wikiListe = TableBuilder.new() -- reçois le texte affiché pour chaque paramètre local iso = TableBuilder.new() -- reçois le format date ISO de ce paramètre

local dataQualificatif, dataCat if not args.nolinks then dataQualificatif = dataLiens[qualificatif or ] if type( dataQualificatif ) ~= 'table' then -- si le qualifiquatif n'est pas dans la base de donnée, on crée une table minimum, -- qui imposera un test sur l'annee, mais considère qu'il n'y a pas de lien sur le jour ou le mois dataQualificatif = { qualificatif = ' ' .. qualificatif, annee = { } } end dataCat = dataLiens[dataQualificatif.cat] if type( dataCat ) ~= 'table' or dataCat == dataQualificatif then dataCat = { qualificatif = } end end local function wikiLien( lien, texte ) if lien == texte then return texte else return texte end end

-- Date julienne if jjour ~= jour then if jjour == 1 then jjour = '1er' end if jannee ~= annee then julien3 = '(' .. jjour .. ' ' .. jmois .. ' ' .. jannee .. ')' else julien2 = '(' .. jjour .. ' ' .. jmois .. ')' end end


-- le jour si présent local qualifJour = if jour then local texteJour = jour if args.nolinks then if jour == 1 then jour = modelePremier end wikiListe.insert( jour ) else qualifJour = dataQualificatif.jour and dataQualificatif.qualificatif or dataCat.jour and dataCat.qualificatif or local lien = jour .. ' ' .. mois .. ' ' .. qualifJour if jour == 1 then jour = '1er' lien = '1er ' .. mois .. ' ' .. qualifJour end -- s'il n'y a pas de lien sur le mois, il sera affiché avec le jour. wikiListe.insert( wikiLien( lien, jour ) ) wikiListe.insert( wikiLien( lien, jour .. ' '.. mois ) ) end iso.insert( 1, string.sub( '0' .. gjour, -2 ) ) end

-- le mois if mois then if #wikiListe == 0 and annee == nil then return mois end if args.nolinks then if not args.masquerMois then wikiListe.insert( mois ) end else local lien if annee then lien = existDate( dataQualificatif, annee, mois ) or existDate( dataCat, annee, mois ) if lien == nil and qualificatif and qualifJour == then -- test nouveau test sans le qualificatif uniquement s'il n'y a pas d'éphémérides pour ce qualificatif. lien = existDate( dataLiens[], annee, mois ) end end if lien or args.masquerMois then -- s'il y a un lien on retire le lien affichant 'jour mois' pour ajouter 'mois' wikiListe.remove() if not args.masquerMois then wikiListe.insert( wikiLien( lien, mois ) ) end elseif #wikiListe > 0 then -- sinon on retire le lien affichant 'jour' pour ne garder que le lien 'jour mois' wikiListe.remove( #wikiListe - 1 ) elseif args.masquerAnnee then -- s'il n'y a pas de jour et que l'année n'est pas affichée, on insère le mois seul. wikiListe.insert( mois ) end end if gmois then iso.insert( 1, string.sub( '0' .. gmois, -2 ) ) end end if( julien2 ) then wikiListe.insert( julien2 ) end

-- l'année if annee then if not args.masquerAnnee then local texteAnnee = annee local lien if annee < 0 then local annneeAvJc = 0 - annee lien = lien or ( annneeAvJc .. ' av. J.-C.' ) local avJC = trim( string.lower( args.avJC or ) ) if args.avJC == 'non' then texteAnnee = annneeAvJc else texteAnnee = annneeAvJc .. ' av. J.-C.' end end if args.nolinks then -- seulement si on doit l'affichée wikiListe.insert( texteAnnee ) else lien = existDate( dataQualificatif, annee ) or existDate( dataCat, annee ) or lien or annee if mois and #wikiListe == 0 then -- si le mois n'a pas de lien et n'est pas affiché avec le jour, il est affiché avec l'année. texteAnnee = mois .. ' ' .. texteAnnee end wikiListe.insert( wikiLien( lien, texteAnnee ) ) end end if gannee > 999 then iso.insert( 1, gannee ) elseif gannee > -1 then iso.insert( 1, string.sub( '000' .. gannee , -4 ) ) elseif gannee > -999 then -- calendrier grégorien proleptique avec année 0. iso.insert( 1, 'U-' .. string.sub( '000' .. ( 0 - gannee ), -4 ) ) else iso.insert( 1, 'U' .. gannee ) end end if( julien3 ) then wikiListe.insert( julien3 ) end


-- l'age if type( age ) == 'number' and age >= 0 and ( not naissance or age < 120 ) then if age == 0 then age = '(moins d’un an)' elseif age == 1 then age = '(1 an)' else age = '(' .. age .. ' ans)' end else age = false end


-- compilation du résultat local wikiTexte = wikiListe.concat( ' ' ) local isoTexte = iso.concat( '-' )

-- On ajoute un peu de sémantique. local wikiHtml = mw.html.create( )

local dateHtml = wikiHtml:tag( 'time' ) :wikitext( wikiTexte ) if wikiTexte:match( ' ' ) then dateHtml:addClass( 'nowrap' ) end if isoTexte ~= wikiTexte then dateHtml:attr( 'datetime', isoTexte ) end if not args.nolinks then dateHtml:addClass( 'date-lien' ) end if naissance then dateHtml:addClass( 'bday' ) elseif mort then dateHtml:addClass( 'dday' ) end if age then wikiHtml:wikitext( ' ' ) :tag( 'span' ) :addClass( 'noprint') :wikitext( age ) :done() end

return tostring( wikiHtml ) end


--- -- fonction destinée aux infobox, notamment pour afficher les dates de naissance et de mort -- les liens présent dans les dates fournies sont automatiquement supprimées pour gérer les cas ou -- le paramètre contient déjà un modèle date. -- Paramètres : -- 1 : type de date à afficher (naissance / n, mort / m, ou date / d) -- 1 : Date ou date de naissance -- 2 : Date de mort si type n ou m -- qualificatif = suffixe des page de date à lier (exemple : en musique) -- nolinks : n'affiche pas de lien function fun.dateInfobox( frame ) local args = frame.args if type( args ) ~= 'table' or not ( args[1] and args[2] ) then return end

local function analyseDate( d ) if trim( d ) then -- supprime les liens local analyse = d:match( ' ou ') or d:match( 'entre ' ) or d:match( 'vers ' ) or d:match( 'après ' ) or d:match( 'avant ' ) if analyse then return d end analyse = d:match( 'datetime="([%d-]+)"' ) or d local debut, fin = analyse:match( '(.-%d%d%d%]*%-?)([\127 ].+)' ) if not debut then debut, fin = analyse:match( '(.-%d%d%d%]*%-?)(
.+)' ) end analyse = debut or analyse analyse = analyse:gsub( '%[%[([^%[%]|]*)|?([^%[%]]*)%]%]', function ( l, t ) return trim( t ) or l end ) local t, r = fun.separationJourMoisAnnee( analyse ) if t then return r, fin else return d, fin end end end

local naissance = args[1]:match( '^n' ) local mort = args[1]:match( '^m' ) or args[1]:match( 'décès' ) local affichageDate, qualificatif = args[2], args[4] local affichageDateTab, resultatDate, complementDate local dateNaissance, dateMort if mort then affichageDate = args[3] end if not trim( affichageDate ) then return end if affichageDate:match( '' ) then -- S'il y a des liens il y a probablement déjà un modèle date, évitons de l'exècuter une 2e fois if ( naissance or mort ) and ( affichageDate:match( 'wikidata%-linkback' )) then dateNaissance = analyseDate( args[2] ) dateMort = analyseDate( args[3] ) resultatDate = affichageDate else return affichageDate end else affichageDateTab, complementDate = analyseDate( affichageDate ) if type( affichageDateTab ) ~= 'table' then return affichageDateTab else if naissance then dateNaissance = affichageDateTab dateMort = analyseDate( args[3] ) elseif mort then dateNaissance = analyseDate( args[2] ) dateMort = affichageDateTab else qualificatif = args[3] end affichageDateTab.naissance = naissance affichageDateTab.mort = mort affichageDateTab.qualificatif = args.qualificatif or qualificatif affichageDateTab.nolinks = args.nolinks affichageDateTab.nocat = args.nocat affichageDateTab.julien = args.julien end end resultatDate = resultatDate or fun.modeleDate( affichageDateTab )

local age, prefixAge, suffixAge, calculAge = , ' (', ')', nil if naissance and dateNaissance and not dateMort and type( dateNaissance ) == 'table' then calculAge = fun.age( dateNaissance.annee, dateNaissance.numMois, dateNaissance.jour ) if calculAge and calculAge > 120 then calculAge = nil end elseif mort and dateNaissance and dateMort and type( dateNaissance ) == 'table' and type( dateMort ) == 'table' then calculAge = fun.age( dateNaissance.annee, dateNaissance.numMois, dateNaissance.jour, dateMort.annee, dateMort.numMois, dateMort.jour ) prefixAge = ' (à ' suffixAge = ')' end if tonumber( calculAge ) then if calculAge > 1 then age = prefixAge .. calculAge .. ' ans' .. suffixAge elseif calculAge == 1 then age = prefixAge .. 'un an' .. suffixAge elseif calculAge == 0 then age = prefixAge .. 'moins d’un an' .. suffixAge end if complementDate and complementDate:match( 'ans?%)' ) then complementDate = end end

return resultatDate .. ( complementDate or ) .. age 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 -- 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 args = Outils.extractArgs( frame ) local annee = Outils.notEmpty( args['année'], args.annee, args.year, args.date ) -- extraction de l'année if type( annee ) == 'string' then annee = ( tonumber( annee ) -- match '2013' or string.match ( annee, '%D(%d%d%d%d)%D' ) -- match '2013' or string.match ( annee, '%D(%d%d%d%d)$' ) -- match '17 septembre 2013' or string.match ( annee, '^(%d%d%d%d)%D' ) -- match '2013-09-17' ) end annee = tonumber( annee )

-- le format de date iso est défini suivant le calendrier grégorien. -- Avant l'année 1583 la date est calendrier est probablement du calendrier julien, -- donc autant s'abstenir. if annee and annee > 1582 then local mois = Outils.notEmpty( args.mois, args.month ) -- num mois trouve le numéro du mois, qu'il soit numérique ou texte, complet ou abrégé. local nomMois, numMois = fun.determinationMois( mois ) if numMois then mois = '-' .. string.sub( '0' .. numMois, -2 )

local jour = Outils.notEmpty( args.jour, args.day, args['quantième'] ) if type( jour ) == 'string' then jour = tonumber( jour ) or tonumber( string.match ( jour, '%d+') ) end jour = tonumber( jour ) if jour and jour <= liste_mois[numMois].nJour then jour = '-' .. string.sub( '0' .. jour, -2 ) return annee .. mois .. jour else return annee .. mois end else return tostring( annee ) end 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 (Suit le calendrier grégorien) 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 local 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

--- -- Voir Modèle:Âge -- retourne l'age en fonction de la ou les dates fournies. La valeur retounée est de type 'number' -- Parammètres : -- 1, 2, 3 : année, mois jour de naissance (supposé dans le calendrier grégorien) -- 4, 5, 6 : année, mois, joue du calcul (facultatif, par défaut la date UTC courante). function fun.age( an, mn, jn, ac, mc, jc ) if ac == nil then local today = os.date( '!*t' ) ac = today.year mc = today.month jc = today.day else ac = tonumber( ac ) mc = tonumber( mc ) jc = tonumber( jc ) end

local an = tonumber( an ) local mn = tonumber( mn ) local jn = tonumber( jn )

if an == nil or ac == nil or mn == nil or mc == nil then -- pas de message d'erreur qui risque de faire planter la fonction appelante -- à elle de gérer ce retour. return end

local age = ac - an if mc == mn then if jc == nil or jn == nil then return end return age-tonumber( jc < jn and 1 or 0 ) else return age-tonumber( mc < mn and 1 or 0 ) end end

function fun.modeleAge( frame ) local args = frame.getParent().args local age = fun.age ( args[1] or args['année'], args[2] or args['mois'], args[3] or args['jour'], args[4], args[5], args[6] ) if age then return age else return Outils.erreur("Paramètres incorrects ou insuffisants ou pour calculer l'âge précis" ) end end

--- -- calcul du jour julien à partir d'une date du calendrier grégorien function fun.julianDay( year, month, day, hour, min, sec ) local julian julian = math.floor( math.floor( ( year * 12 + month + 57609 ) / 12 - 1 ) * 1461 / 4 ) - math.floor( math.floor( ( year * 12 + month + 57609 ) / 12 - 1 ) / 100 ) + math.floor( math.floor( ( year * 12 + month + 57609 ) / 12 - 1 ) / 400 ) + math.floor( ( math.fmod( month + 57609, 12 ) + 4 ) * 153 / 5 ) + day + ( hour or 12 ) / 24 + ( min or 0 ) / 1440 + ( sec or 0 ) / 86400 - 32167.5 return julian end

--- -- calcul du jour julien à partir d'une date du calendrier julien function fun.julianDayJulian( year, month, day, hour, min, sec ) local julian julian = math.floor( math.floor( ( year * 12 + month + 57609 ) / 12 - 1 ) * 1461 / 4 ) + math.floor( ( math.fmod( month + 57609, 12 ) + 4 ) * 153 / 5 ) + day + ( hour or 12 ) / 24 + ( min or 0 ) / 1440 + ( sec or 0 ) / 86400 - 32205.5 return julian end

--- -- calcul d'une date dans le calendrier grégorien à partir du jour julien function fun.julianDayToGregorian( julianDay ) local base = math.floor( julianDay + 32044.5 ) -- 1 March -4800 (proleptic Gregorian date) local nCentury = math.floor( ( base * 4 + 3 ) / 146097 ) local sinceCentury = base - math.floor( nCentury * 146097 / 4 ) local nYear = math.floor( ( sinceCentury * 4 + 3 ) / 1461 ) local sinceYear = sinceCentury - math.floor( nYear * 1461 / 4 ) local nMonth = math.floor( ( sinceYear * 5 + 2 ) / 153 )

local day = sinceYear - math.floor( ( nMonth * 153 + 2 ) / 5 ) + 1 local month = nMonth - math.floor( nMonth / 10 ) * 12 + 3 local year = math.floor( sinceYear / 306 ) + nYear + 100 * nCentury - 4800

return year, month, day end

--- -- calcul d'une date dans le calendrier julien à partir du jour julien -- calcul basé sur l'algorythme de la page fr.wikipedia.org/wiki/Jour_julien (1/10/2013) function fun.julianDayToJulian( julianDay ) local year = math.modf( ( julianDay * 4 - 6884469 ) / 1461 ) local r2 = julianDay - math.modf( ( 1461 * year + 6884472 ) / 4 ) local month = math.modf( ( 5 * r2 + 461 ) / 153 ) local day = r2 - math.modf( ( 153 * month - 457 ) / 5 ) + 1 if month > 12 then year = year + 1 month = month - 12 end return year, month, day end

--- -- calcul d'une date dans le calendrier grégorien à partir d'une date dans le calendrier julien function fun.julianToGregorian( year, month, day ) return fun.julianDayToGregorian( fun.julianDayJulian( year, month, day ) ) end

--- -- calcul d'une date dans le calendrier julien à partir d'une date dans le calendrier grégorien function fun.gregorianToJulian( year, month, day ) year = tonumber(year) if month then month = tonumber(month) else month = 6 end --prend une valeur centrale pour donner un best "guess" if day then day = tonumber(day) else day = 15 end return fun.julianDayToJulian( fun.julianDay( year, month, day ) ) end


--- -- erreurModuleData affiche d'un message d'erreur si le Module:Langue/Data n'a pas été chargé correctement, -- pour la page de discussion de la base de donnée et ceux qui veulent surveiller cette page. function fun.erreurModuleData() local success, resultat = pcall ( mw.loadData, 'Module:Date/Data' ) if success == false then local message = [[Le chargement du module Date/Data génère une erreur :
%s

Cette erreur doit être corrigée au plus vite car des milliers de page ne s'affichent pas correctement ]] return string.format( message, resultat ) end end

--- -- checkDataCat génère des liens vers les pages annuelles, mensuelles et d'éphémérides liè aux -- catégories du Module:Date/Data. La date la plus ancienne dépend de 'aucun' et 'seul[1]' -- Paramètres : -- 1 : la catégorie. Il y aura une section par qualificatif de cette catégorie. -- mois : oui pour avoir les liens vers les pages mensuelles et éphémérides (4 jours dans l'année) -- alias : pour avoir des lien pour les alias en plus des qualificatif function fun.checkDataCat( frame ) local category = trim(frame.args[1]) local monthLinks = frame .args.mois == 'oui' local alias = frame.args.alias == 'oui' local dataLink = mw.loadData( 'Module:Date/Data' ) local wikiList = TableBuilder.new() local currentYear = tonumber( os.date( '%Y' ) )

local columns = '

'

local newSection if monthLinks then newSection = '\n\n== %s ==\n\n=== Années ===\n' .. columns else newSection ='\n\n== %s ==\n' .. columns end for field, dataField in pairs( dataLink ) do -- boucle sur tous les qualificatif ayant pour catégorie le premier paramère if dataField.cat == category or ( category == 'cat' and dataField.cat == field ) then local monthInitialYear, initialYear -- définition de l'année à partir de laquelle on va tester toutes les année / mois if dataField.qualificatif == field or ( category == 'cat' and dataField.cat == field ) then if dataField.annee and dataField.annee.aucun and dataField.annee.aucun < currentYear then local aucun = ( dataField.annee.seul and dataField.annee.seul[1] ) or dataField.annee.aucun initialYear = math.min( aucun - math.ceil( (currentYear - aucun) / 4 ), currentYear - 50 ) else initialYear = currentYear - 50 end if dataField.mois and tonumber( dataField.mois.aucun ) and ( tonumber( dataField.mois.aucun ) < currentYear ) then local aucun = dataField.mois.aucun monthInitialYear = math.min( aucun - math.ceil( (currentYear - aucun) / 4 ), currentYear - 8 ) else monthInitialYear = currentYear - 8 end elseif alias then -- si le paramètre alias est défini on teste aussi tous les alias, sinon ils sont ignorés initialYear = currentYear - 50 monthInitialYear = currentYear - 8 end

-- création de l'ensembles des liens if initialYear then -- ajout de lien vers les pages annuelles de l'année en court + 5 jusqu'à initialYear wikiList.insert( string.format( newSection, field ) ) local fieldLink = ' ' .. field if category == 'cat' then fieldLink = ' ' .. dataField.qualificatif end for year = ( currentYear + 5 ), initialYear, -1 do wikiList.insert( '\n* ' .. year .. '' ) end

wikiList.insert( '\n

' )

if monthLinks then -- insertstion de liens vers les mois de l'année en court + 1 jusqu'à monthInitialYear wikiList.insert( '\n\n=== Mois ===' ) local month, sep for year = ( currentYear + 1 ), monthInitialYear, -1 do wikiList.insert( '\n* ' .. year .. ' : ' ) sep = ' • ' for j = 1, 12 do month = ucfirst( liste_mois[j][1] ) .. ' ' if j == 12 then sep = end wikiList.insert( '' .. month .. '' .. sep ) end end

-- insertion de quelques date pour tester les éphémérides wikiList.insert( '\n\n=== Jours ===' ) wikiList.insert( '\n* 1er janvier ' .. fieldLink .. '' ) wikiList.insert( '\n* 14 mars ' .. fieldLink .. '' ) wikiList.insert( '\n* 22 juin ' .. fieldLink .. '' ) wikiList.insert( '\n* 3 septembre ' .. fieldLink .. '' ) end end end end

return table.concat( wikiList ) end

--[[

 Cette fonction retourne "CET" ou "CEST" selon que dans la pseudo-timezone en cours
   c'est l'heure d'été ou l'heure d'hiver.
 Cette fonction n'a de sens a priori que pour des modèles utilisés en Europe
 
 Paramètre optionnel non nommé : "sans lien" : retourne le texte CET/CEST. sinon
   retourne ce même texte avec un wikilien vers les articles correspondant

--]] function fun.CEST(frame) -- option : ne pas créer de wikilien local opt = trim(frame.args[1] or frame:getParent().args[1]) -- on récupère l'information dans la zone courante local t = mw.getContentLanguage():formatDate("I", nil, true)

if (t == "1") then -- heure d'été if (opt == "sans lien") then return "CEST" elseif (opt == "décalage") then return "2" else return "CEST" end else -- heure d'hiver (ou autre zone où ça ne s'applique pas) if (opt == "sans lien") then return "CET" elseif (opt == "décalage") then return "1" else return "CET" end end end

return fun