Module:Date : Différence entre versions
(hack quand les jours ou mois juliens ne sont pas renseignés) |
m (Révocation des modifications de Zebulon84 (discussion) vers la dernière version de 0x010C) |
||
(53 révisions intermédiaires par 12 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 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 }, | |
− | + | { "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 | -- 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 | |
− | + | return nil | |
− | + | end | |
− | + | 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 ) | ||
− | + | 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 | 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. | ||
− | -- | + | -- Si le deuxième paramètre est vrai, les nombres supérieur à 12 ou non entiers sont acceptés. |
− | function fun.determinationMois( mois, | + | 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 | 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 | |
− | + | 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 = { '<abbr class="abbr" title="Premier" >1<sup>er</sup></abbr>', '1<sup>er</sup>', '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 | end | ||
Ligne 132 : | Ligne 453 : | ||
-- émule le modèle {{m|Date}}. | -- émule le modèle {{m|Date}}. | ||
-- Paramètres : | -- 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 ) | 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 | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | 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 <time> | |
− | + | 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 '' ) ) | |
− | end | + | 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 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 = '1<sup>er</sup>' | ||
+ | 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 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 ) | ||
+ | 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 .. ' <abbr class="abbr" title="' | ||
+ | .. annneeAvJc .. ' avant Jésus-Christ">av. J.-C.</abbr>' | ||
+ | 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. |
− | function fun. | + | -- Paramètres : |
− | local args = | + | -- 1 : type de date à afficher (naissance / n, mort / m, ou date / d) |
− | + | -- 1 : Date ou date de naissance | |
− | if | + | -- 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 | |
− | local | + | return |
− | if | + | 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 ' ) | |
− | return | + | 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 | + | 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 | + | return affichageDate |
end | end | ||
else | else | ||
− | + | affichageDateTab, complementDate = analyseDate( affichageDate ) | |
− | + | if type( affichageDateTab ) ~= 'table' then | |
− | if | + | 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 = '', ' <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 .. ' 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 | ||
end | end | ||
+ | |||
+ | return resultatDate .. ( complementDate or '' ) .. age | ||
end | end | ||
+ | |||
--- | --- | ||
Ligne 420 : | 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 461 : | 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 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 | end | ||
Ligne 477 : | 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 yr2 = tonumber(arguments[2]) or 0 | |
− | + | ||
− | + | 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 | |
− | + | 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 | |
− | + | 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 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 | 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 arguments = pframe.args | |
− | + | return fun.formatRepCal(fun.do_toRepCal(arguments)) | |
end | end | ||
Ligne 527 : | 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 | |
− | + | -- 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 | end | ||
Ligne 540 : | 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 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 | end | ||
Ligne 559 : | 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 ) | ||
− | + | 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 | end | ||
function fun.modeleAge( frame ) | 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 | end | ||
Ligne 605 : | 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 | |
− | + | 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 | end | ||
--- | --- | ||
− | -- calcul du jour julien à partir d'une date du calendrier | + | -- 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 | |
− | + | 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 | end | ||
Ligne 629 : | 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 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 | end | ||
Ligne 648 : | 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 661 : | 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 ) ) | |
end | end | ||
Ligne 670 : | 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 ) ) | |
end | end | ||
Ligne 679 : | 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' ) | |
− | + | if success == false then | |
− | + | 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 ) | |
− | + | end | |
end | end | ||
Ligne 692 : | 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 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 = '<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 | |
− | + | 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 .. fieldLink ..'|' .. year .. ']]' ) | |
− | + | end | |
− | + | wikiList.insert( '\n</div>' ) | |
− | + | ||
− | + | 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 .. year .. ' ' .. fieldLink .. '|' .. 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 "[[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 |
Version actuelle datée du 23 septembre 2017 à 19:33
La documentation pour ce module peut être créée à Module:Date/doc
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 = '<abbr class="abbr" title="premier">1<sup>er</sup></abbr>' -- 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 = { '<abbr class="abbr" title="Premier" >1<sup>er</sup></abbr>', '1<sup>er</sup>', '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 {{m|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 = '[[Catégorie:Page utilisant le modèle date avec une syntaxe erronée]]' 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 <time> 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 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 = '1<sup>er</sup>' 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 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 ) 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 .. ' <abbr class="abbr" title="' .. annneeAvJc .. ' avant Jésus-Christ">av. J.-C.</abbr>' 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%]*%-?)(<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 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( '</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 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 = '', ' <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 .. ' 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 en litérature|2013]] -- le mois peut être en lettre ou en chiffres -- le jour peut être sous la forme '05', '{{1er}}' ou 'vendredi 13' function fun.dateISO( frame ) local 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 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 '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 = [[<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> ]] 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 = '<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 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 .. fieldLink ..'|' .. year .. ']]' ) end wikiList.insert( '\n</div>' ) 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 .. year .. ' ' .. fieldLink .. '|' .. 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 "[[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 return fun