« Module:Date » : différence entre les versions
Apparence
Modèle:Infobox>Zebulon84 m retouche de la modification précédente |
m 275 versions importées |
||
| (239 versions intermédiaires par 22 utilisateurs non affichées) | |||
| Ligne 1 : | Ligne 1 : | ||
-- luacheck: globals mw, no max line length | |||
local fun = {} | local fun = {} | ||
local | local Outils = require 'Module:Outils' | ||
-- chargement de la base de données répertoriant certaines pages existant ou n'existant pas pour éviter les "ifexist". | |||
-- | local dataLiens | ||
local | local success, resultat = pcall ( mw.loadData, 'Module:Date/Data' ) | ||
if success then | |||
dataLiens = resultat | |||
else | |||
-- protection au cas où le sous-module serait mal modifié | |||
dataLiens = { [''] = { mois = { aucun = 1000, tous = { 1773, 2014 } }, } } | |||
end | 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) | ||
-- retourne | -- retourne nil si le texte est vide ou n'est pas du texte. Attention c'est important pour les fonctions qui l'utilisent. | ||
local | local trim = Outils.trim | ||
-- Fonction destinée à mettre la première lettre du mois en majuscule : | |||
-- utilisation de string car aucun mois ne commence 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 | |||
local | -- liste des mois, écriture exacte et alias, en minuscule | ||
local listeMois = { | |||
{ num = 1, nJour = 31, abrev = 'janv.', nom = 'janvier', alias = { 'jan.', 'janv.', 'jan', 'janv', 'january' } }, | |||
{ num = 2, nJour = 29, abrev = 'fév.', nom = 'février', alias = { 'fevrier', 'fev.', 'fev', 'fév.', 'fév', 'févr', 'févr.', 'february', 'feb', 'feb.' } }, | |||
{ num = 3, nJour = 31, abrev = 'mars', nom = 'mars', alias = { 'mar.', 'mar', 'march' } }, | |||
{ num = 4, nJour = 30, abrev = 'avr.', nom = 'avril', alias = { 'avr.', 'avr', 'apr', 'april'} }, | |||
{ num = 5, nJour = 31, abrev = 'mai', nom = 'mai', alias = { 'may' } }, | |||
{ num = 6, nJour = 30, abrev = 'juin', nom = 'juin', alias = { 'jun', 'june' } }, | |||
{ num = 7, nJour = 31, abrev = 'juill.', nom = 'juillet', alias = { 'juil.', 'juil', 'juill.', 'juill', 'jul', 'july' } }, | |||
{ num = 8, nJour = 31, abrev = 'août', nom = 'août', alias = { 'aoû', 'aug', 'august' } }, | |||
{ num = 9, nJour = 30, abrev = 'sept.', nom = 'septembre', alias = { 'sept.', 'sept', 'sep.', 'sep', 'september' } }, | |||
{ num = 10, nJour = 31, abrev = 'oct.', nom = 'octobre', alias = { 'oct.', 'oct', 'october' } }, | |||
{ num = 11, nJour = 30, abrev = 'nov.', nom = 'novembre', alias = { 'nov.', 'nov', 'november' } }, | |||
{ num = 12, nJour = 31, abrev = 'déc.', nom = 'décembre', alias = { 'decembre', 'déc.', 'dec.', 'dec', 'déc', 'december' } }, | |||
aout = { num = 8, nJour = 31, abrev = 'aout', nom = 'aout', alias = { 'aou' } }, | |||
} | } | ||
-- | -- ajoute les noms, abréviations et alias en tant que clés de listeMois | ||
for i = 1, 12 do | |||
local mois = listeMois[i] | |||
listeMois[tostring( i )] = mois | |||
if i < 10 then | |||
listeMois['0' .. i] = mois | |||
end | |||
listeMois[mois.nom] = mois | |||
listeMois[mois.abrev] = mois | |||
for j = 1, #mois.alias do | |||
listeMois[mois.alias[j]] = mois | |||
end | |||
end | |||
for i = 1, #listeMois.aout.alias do | |||
listeMois[listeMois.aout.alias[i]] = listeMois.aout | |||
end | end | ||
local liste_saisons = { | |||
{ 'printemps', 'spring', }, | |||
{ 'été', 'summer', }, | |||
{ 'automne', 'autumn', }, | |||
{ 'hiver', 'winter', }, | |||
} | |||
-- à partir d'un nom de saison (en français ou en anglais), | |||
-- retourne son nom canonique (exemple : "été") | |||
-- si non reconnu, retourne nil | |||
function fun.determinationSaison( saison ) | |||
local s = trim( saison ) | |||
if s then | |||
s = s:gsub( 'É', 'é' ):lower() | |||
for i = 1, 4 do | |||
for j = 1, #liste_saisons[i] do | |||
if s == liste_saisons[i][j] then | |||
return liste_saisons[i][1] | |||
end | |||
end | |||
end | |||
end | |||
end | end | ||
-- | --- | ||
-- à partir de | -- à partir d'un nom de mois (en français ou en anglais), de son numéro ou d'une abréviation, | ||
-- | -- retourne son nom canonique (exemple : "juin") et son numéro (exemple : 6) | ||
function fun.determinationMois( mois | -- si non reconnu, retourne nil, nil | ||
function fun.determinationMois( mois ) | |||
local result | |||
local num = tonumber( mois ) | |||
if num then | |||
result = listeMois[num] | |||
else | |||
local str = trim( mois ) | |||
if str then | |||
result = listeMois[str] | |||
if not result then | |||
result = listeMois[str:gsub( 'É', 'é' ):gsub( 'Û', 'û' ):lower()] | |||
end | |||
end | |||
end | |||
if result then | |||
return result.nom, result.num | |||
else | |||
return nil, nil | |||
end | |||
end | end | ||
-- | -- fonction interne à modeleDate, pour déterminer si on peut se passer de faire un ifexist | ||
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 remplacé par celui de la base de données, ce qui permet des alias. | |||
local lien = annee | |||
if dataQualificatif.qualificatif ~= '' then | |||
lien = lien .. ' ' .. dataQualificatif.qualificatif | |||
end | |||
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 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'année 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 | 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="[Pp]remier" *>1<sup>er</sup></abbr>', '1<sup>er</sup>', '1er' } | |||
for i = 1, #nomJour do | |||
jour = jour:gsub( nomJour[i], '' ) | |||
end | |||
for i = 1, #premier do | |||
jour = jour:gsub( premier[i], '1' ) | |||
end | |||
jour = trim( jour ) | |||
end | |||
return jour | |||
end | |||
--- | |||
-- Sépare une chaine date en une 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, '<span class="error">' .. periode .. ' invalide (' .. valeur .. ')</span>' | |||
end | |||
local dateAvantCleanup = date | |||
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 mmm2 = '([^%s%p%d]+[.]?[-/][^%s%p%d]+[.]?)' -- mois-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 | |||
date = fun.nettoyageJour( date ) | |||
if date == nil then | |||
return erreur( 'Date', dateAvantCleanup ) | |||
end | |||
if date:find( '[[', nil, true ) then | |||
date = date | |||
-- suppression catégories (doit être exécuté avant le code de suppression des liens) | |||
:gsub( '%[%[[Cc]atégorie:.-%]%]', '' ) | |||
:gsub( '%[%[[Cc]ategory:.-%]%]', '' ) | |||
-- suppression liens | |||
:gsub( '%[%[([^%[%]|]*)|?([^%[%]]*)%]%]', function ( l, t ) return trim( t ) or l end ) | |||
end | |||
date = date | |||
-- suppression balises | |||
:gsub( '%b<>', '' ) | |||
-- suppression des espaces insécables | |||
-- nbsp | |||
:gsub( '\194\160', ' ' ) | |||
:gsub( ' ', ' ' ) | |||
:gsub( ' ', ' ' ) | |||
-- narrow nbsp | |||
:gsub( '\226\128\175', ' ' ) | |||
:gsub( ' ', ' ' ) | |||
-- thin space | |||
:gsub( '\226\128\137', ' ' ) | |||
:gsub( ' ', ' ' ) | |||
:gsub( ' ', ' ' ) | |||
-- simple space | |||
:gsub( ' ', ' ' ) | |||
-- plusieurs espaces (doit être exécuté après les autres remplacements) | |||
:gsub( ' +', ' ' ) | |||
-- réduction av. J-C pour simplifier un peu les regex | |||
:gsub( '(%d+) ?[Aa][Vv]%.? ?[Jj][ .-]*[Cc]%.?', '-%1' ) | |||
-- suppression de l'heure dans les dates 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', dateAvantCleanup ) | |||
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( '^'..mmm2..s..aj..moins..'$' ) then | |||
-- mmm-mmm aaaa | |||
mois, separateur, annee, masquerAnnee = date:match( '^'..mmm2..sep..aj..moins..'$' ) | |||
if separateur:match( '^.+%-$' ) then | |||
annee = '-' .. annee | |||
end | |||
elseif date:match( '^'..j..s..mmm..moins..'$' ) then | |||
-- jj mmm | |||
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', dateAvantCleanup ) | |||
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 | |||
--- | |||
-- validationJourMoisAnnee vérifie que les paramètres correspondent à une date valide. | |||
-- la date peut être dans les paramètres 1 à 3, ou dans des paramètres jour, mois et annee. | |||
-- La fonction retourne true suivi d'une table avec la date en paramètres nommés (sans accent sur année) | |||
-- ou false suivi d'un message d'erreur. | |||
function fun.validationJourMoisAnnee( frame ) | |||
local args = Outils.extractArgs( frame ) | |||
local jour, mois, numMois, annee | |||
local bjour = args['jour'] or args[1] or '' | |||
local bmois = tostring( args['mois'] or args[2] or '' ) | |||
local bannee = args['annee'] or args['année'] or args[3] or '' | |||
local function erreur( periode, valeur ) | |||
return false, '<span class="error">' .. periode .. ' invalide (' .. valeur .. ')</span>' | |||
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 = bannee:match( '^(%d+) ?[Aa][Vv]%.? ?[Jj][ .-]*[Cc]%.?' ) | |||
annee = tonumber( annee ) | |||
if annee then | |||
annee = 0 - annee | |||
else | |||
return erreur( 'Année', bannee ) | |||
end | |||
elseif annee == 0 then | |||
return erreur( 'Année', 0 ) | |||
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.determinationSaison( bmois ) | |||
if mois == nil then | |||
local mois1, sep, mois2 = bmois:match( '^([^%s%p%d]+[.]?)([-/])([^%s%p%d]+[.]?)$' ) | |||
if mois1 then | |||
mois1 = fun.determinationMois( mois1 ) | |||
mois2 = fun.determinationMois( mois2 ) | |||
if mois1 == nil or mois2 == nil then | |||
return erreur( 'Mois', bmois ) | |||
end | |||
mois = mois1 .. sep .. mois2 | |||
else | |||
return erreur( 'Mois', bmois ) | |||
end | |||
end | |||
end | |||
-- on traite le jour si présent | |||
if Outils.notEmpty( bjour ) then | |||
if not numMois then | |||
erreur( 'Date', 'jour avec saison ou plusieurs mois' ) | |||
end | |||
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 > listeMois[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 | |||
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, '<span class="error">année improbable (' .. annee .. ')</span>' | |||
end | |||
local resultat = { | |||
jour = jour, | |||
mois = mois, | |||
numMois = numMois, | |||
annee = annee, | |||
masquerAnnee = args.masquerAnnee, | |||
masquerMois = args.masquerMois, | |||
} | |||
return true, resultat | |||
end | |||
--- | |||
-- émule le modèle {{m|Date}}. | -- émule le modèle {{m|Date}}. | ||
-- Paramètres : | -- Paramètres : | ||
-- | -- 1 : jour (numéro ou "1er") ou la date complète | ||
-- | -- 2 : mois (en toutes lettres) ou spécialité de l'année | ||
-- | -- 3 : année (nombre) | ||
-- | -- 4 : spécialité de l'année | ||
-- | -- julien : date dans le calendrier julien | ||
-- | -- compact : affiche le mois sous forme d'abréviation | ||
-- | -- avJC : non pour désactiver l'affichage de « av. J.-C. » pour les dates négatives | ||
-- âge : ajoute la durée depuis cette date | |||
-- agePrefix : préfixe pour l'age, 'à ' par défaut pour les décès | |||
-- liens : active les liens par défaut | |||
-- nolinks : ne met pas de lien sur la date (a précédence sur le paramètre "liens") | |||
-- afficherErreurs : en cas d'erreur, si défini à "non" ne retourne pas un message d'erreur, mais le 1er argument inchangé | |||
-- categoriserErreurs : en cas d'erreur, si défini à "non" ne catégorise pas ; peut aussi être défini avec une catégorie à utiliser à la place de celle par défaut | |||
-- naissance : ajoute la class "bday" | |||
-- mort : ajoute la class "dday" | |||
function fun.modeleDate( frame ) | function fun.modeleDate( frame ) | ||
local Yesno = require 'Module:Yesno' | |||
local args | |||
if frame. args and frame.args.nogetparent then args = frame.args else args = Outils.extractArgs( frame ) end | |||
-- l'import des paramètres passés au modèle appelant et non au #invoke est désactivable par nogetparent | |||
for i,j in ipairs(args) do args[i] = tostring(j) end | |||
local resultat | |||
local dateNaissanceMort | |||
local cherchedeuxdates = args.mort or args['événement'] or args.evenement | |||
-- analyse des paramètres non nommés (ou paramètres de la date jour, mois, annee) | |||
local test, params | |||
local arg1, arg2, arg3, arg4 = fun.nettoyageJour( args[1] ), trim( args[2] ), trim( args[3] ), trim( args[4] ) | |||
if cherchedeuxdates then args2 = fun.nettoyageJour( args2 ) end | |||
local slashesinarg1 = arg1 and arg1:match( '[^ ./-][ ./-]+[^ ./-]' ) | |||
local slashesinarg2 = cherchedeuxdates and arg2 and arg2:match( '[^ ./-][ ./-]+[^ ./-]' ) | |||
if arg1 and not arg3 and ((slashesinarg1 and not cherchedeuxdates) or arg2 == nil or dataLiens[arg2] or mw.ustring.match( arg2, '%a %a' ) ) then | |||
-- une date dans le premier paramètre | |||
test, params = fun.separationJourMoisAnnee( arg1 ) | |||
if test then | |||
if dataLiens[trim( arg2 )] then | |||
params.qualificatif = trim( arg2 ) | |||
end | |||
end | |||
elseif cherchedeuxdates and (not arg4) and ( slashesinarg1 or slashesinarg2 or dataLiens[arg3] or (arg3 and mw.ustring.match( arg3, '%a %a' ) ) ) then | |||
-- deux dates dans les deux premiers paramètres | |||
test, params = fun.separationJourMoisAnnee( arg1 ) | |||
if test then | |||
dateNaissanceMort = trim( arg2 ) | |||
if dataLiens[trim( arg3 )] then | |||
params.qualificatif = trim( arg3 ) | |||
end | |||
end | |||
else | |||
local cleanArgs = {jour = args.jour, mois = args.mois, annee = args.annee or args['année']} | |||
if arg1 and listeMois[arg1] and not tonumber(arg1) then --le premier argument est un mois donc le deuxième est présumé année | |||
cleanArgs.mois = (cleanArgs.mois or arg1) | |||
cleanArgs.annee = cleanArgs.annee or arg2 | |||
cleanArgs.qualificatif = arg3 | |||
else | |||
cleanArgs.jour = cleanArgs.jour or arg1 | |||
cleanArgs.mois = cleanArgs.mois or arg2 | |||
cleanArgs.annee = cleanArgs.annee or arg3 | |||
cleanArgs.qualificatif = arg4 | |||
end | |||
local function masquerParam( p ) | |||
-- sépare le signe moins final éventuel signifiant que le paramètre ne doit pas être affiché. | |||
if type( p ) ~= 'string' then | |||
return p, nil | |||
end | |||
local value, mask = p:match( '^%s*(.-)(%-?)%s*$' ) | |||
return value, ( mask == '-' or nil ) | |||
end | |||
cleanArgs.mois, cleanArgs.masquerMois = masquerParam( cleanArgs.mois ) | |||
cleanArgs.annee, cleanArgs.masquerAnnee = masquerParam( cleanArgs.annee ) | |||
-- Si les paramètres ont été envoyés directement, ils ont précédence | |||
if args.masquerMois then cleanArgs.masquerMois = args.masquerMois end | |||
if args.masquerAnnee then cleanArgs.masquerAnnee = args.masquerAnnee end | |||
test, params = fun.validationJourMoisAnnee( cleanArgs ) | |||
if test and dataLiens[trim( cleanArgs.qualificatif )] then | |||
params.qualificatif = trim( cleanArgs.qualificatif ) | |||
end | |||
end | |||
-- analyse des paramètres nommés | |||
if test then | |||
params.agePrefix = args.agePrefix | |||
if args.qualificatif and dataLiens[args.qualificatif] then | |||
params.qualificatif = args.qualificatif | |||
end | |||
-- julien peut avoir trois valeurs : inactif, format standard (true), format court | |||
params.julien = Yesno( args.julien, 'court', false ) | |||
params.avJC = Yesno( args.avJC ) | |||
if args['républicain'] and args['républicain'] ~= '' then | |||
if args['républicain'] == 'liens' then | |||
params.republicain = 'liens' | |||
else | |||
params.republicain = Yesno( args['républicain'], false ) | |||
end | |||
else | |||
params.republicain = false | |||
end | |||
if args.dateNaissanceMort and args.dateNaissanceMort ~= '' then | |||
dateNaissanceMort = args.dateNaissanceMort | |||
elseif args['dateNaissanceÉvénement'] and args['dateNaissanceÉvénement'] ~= '' then | |||
dateNaissanceMort = args['dateNaissanceÉvénement'] | |||
end | |||
if dateNaissanceMort then | |||
local testNaissanceMort, paramsNaissanceMort = fun.separationJourMoisAnnee( dateNaissanceMort ) | |||
if testNaissanceMort then | |||
params.anneeNaissanceMort, params.moisNaissanceMort, params.numMoisNaissanceMort, params.jourNaissanceMort = paramsNaissanceMort.annee, paramsNaissanceMort.mois, paramsNaissanceMort.numMois, paramsNaissanceMort.jour | |||
end | |||
end | |||
local listeParam = { | |||
age = 'âge', | |||
['âge'] = 'âge', | |||
naissance = 'naissance', | |||
mort = 'mort', | |||
['événement'] = 'événement', | |||
evenement = 'evenement', | |||
['décès'] = 'mort', | |||
apJC = 'apJC', | |||
nolinks = 'nolinks', | |||
compact = 'compact', | |||
compacte = 'compact', | |||
} | |||
for n, v in pairs( listeParam ) do | |||
params[v] = params[v] or Yesno( args[n], true, false ) or nil | |||
end | |||
if not params.nolinks then | |||
local liens = Yesno( args.liens ) | |||
if liens == nil then | |||
-- liens actifs par défaut si qualificatif | |||
liens = params.qualificatif and params.qualificatif ~= "" and true or false | |||
end | |||
params.nolinks = not liens | |||
end | |||
-- sortie pour les tests unitaire, ou pour débugger | |||
if args.debug then | |||
return params | |||
end | |||
resultat = fun._modeleDate( params ) | |||
else | |||
local yn_afficherErreurs = Yesno( args.afficherErreurs ) | |||
if yn_afficherErreurs == nil or yn_afficherErreurs == true then | |||
resultat = params | |||
else | |||
resultat = args[1] | |||
end | |||
local currentTitle = mw.title.getCurrentTitle() | |||
if currentTitle:inNamespaces( 0, 4, 10, 14, 100 ) | |||
and not Outils.notEmpty( args.nocat ) | |||
and not currentTitle.prefixedText:match( '^Modèle:.+/Test$' ) then | |||
local categorie | |||
local yn_categoriserErreurs = Yesno( args.categoriserErreurs, 'custom', true ) | |||
if yn_categoriserErreurs == nil or yn_categoriserErreurs == true then | |||
categorie = '[[Catégorie:Page utilisant le modèle date avec une syntaxe erronée]]' | |||
elseif yn_categoriserErreurs == false then | |||
categorie = '' | |||
else | |||
local nomCategorie = args.categoriserErreurs | |||
:gsub( '^%[%[', '' ) | |||
:gsub( '%]%]$', '' ) | |||
:gsub( '^:?[Cc]atégorie:', '' ) | |||
:gsub( '^:?[Cc]atégory:', '' ) | |||
categorie = '[[Catégorie:' .. nomCategorie .. ']]' | |||
end | |||
resultat = resultat .. categorie | |||
end | |||
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'âge, naissance et mort | |||
local agePrefix = args.agePrefix | |||
local age = args['âge'] and fun.age( annee, numMois, jour ) | |||
local naissance = args.naissance | |||
local mort = args.mort | |||
local evenement = args['événement'] or args.evenement | |||
if mort and args.anneeNaissanceMort then | |||
age = fun.age( args.anneeNaissanceMort, args.numMoisNaissanceMort, args.jourNaissanceMort, annee, numMois, jour ) | |||
agePrefix = agePrefix or 'à ' -- faut-il mettre \194\160 ? | |||
elseif evenement and args.anneeNaissanceMort then | |||
if naissance then | |||
age = fun.age( annee, numMois, jour, args.anneeNaissanceMort, args.numMoisNaissanceMort, args.jourNaissanceMort ) | |||
else | |||
age = fun.age(args.anneeNaissanceMort, args.numMoisNaissanceMort, args.jourNaissanceMort, annee, numMois, jour ) | |||
end | |||
end | |||
agePrefix = agePrefix or '' | |||
-- 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 -- date suivant le calendrier julien si necessaire | |||
local julienDate, julienSup, julienSep -- servira éventuellement à afficher la date selon le calendrier julien | |||
local gregAprMois, gregAprAn, gregFin -- message de calendrier grégorien lorsque la date est selon le calendrier julien | |||
local dateRepublicaine | |||
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 | |||
args.julien = false | |||
elseif args.julien then | |||
gannee, gmois, gjour = fun.julianToGregorian( annee, numMois, jour ) | |||
annee, mois, jour = gannee, listeMois[gmois].nom, gjour | |||
if jjour == 1 then | |||
jjour = modelePremier | |||
end | |||
if args.compact then | |||
jmois = listeMois[jmois].abrev | |||
end | |||
if args.julien == 'court' then | |||
julienDate = jjour .. ' ' .. jmois .. ' ' | |||
julienSup = '<sup>[[calendrier julien|jul.]]</sup>' | |||
if jannee == annee then | |||
gregAprMois = '<sup>[[calendrier grégorien|grég.]]</sup>' | |||
else | |||
julienDate = julienDate .. jannee .. ' ' | |||
gregAprAn = '<sup>[[calendrier grégorien|grég.]]</sup>' | |||
end | |||
julienSep = ' / ' | |||
else | |||
julienDate = jjour .. ' ' .. jmois .. ' ' .. jannee | |||
julienSep = ' (' | |||
gregFin = ' [[Passage du calendrier julien au calendrier grégorien|dans le calendrier grégorien]])' | |||
end | |||
elseif args.republicain then | |||
local DateRep = require 'Module:Date républicaine' | |||
local RepSansLiens | |||
if args.republicain == 'liens' then | |||
RepSansLiens = false | |||
else | |||
RepSansLiens = true | |||
end | |||
dateRepublicaine = DateRep._date_republicaine( | |||
RepSansLiens, | |||
{ fun.formatRepCal( fun.do_toRepCal{gannee, gmois, gjour} ) } | |||
) | |||
end | |||
else | |||
if annee and annee < 0 then | |||
gannee = gannee + 1 | |||
end | |||
args.julien = false | |||
args.republicain = false | |||
end | |||
-- on génère le résultat | |||
-- Déclarations des variables | |||
local wikiListe = {} -- reçoit le texte affiché pour chaque paramètre | |||
local iso = {} -- reçoit le format date ISO de ce paramètre | |||
local texteMois = mois -- texte du mois qui sera affiché (éventuellement l'abréviation) | |||
if args.compact then | |||
if not numMois then | |||
-- mois est autre chose qu'un simple mois : saison, mois-mois... auquel cas, pas d'abréviation (provoquait erreur Lua) | |||
-- (les abréviations pour le cas "mois[-/]mois" seraient théoriquement possibles, mais ça reste à implémenter) | |||
else | |||
if args.nolinks then | |||
texteMois = '<abbr class="abbr" title="' .. mois .. '">' .. listeMois[mois].abrev .. '</abbr>' | |||
else | |||
texteMois = listeMois[mois].abrev | |||
end | |||
end | |||
end | |||
mois = mois and mois:gsub( 'aout', 'août' ) | |||
local dataQualificatif, dataCat | |||
if not args.nolinks then | |||
dataQualificatif = dataLiens[qualificatif or ''] | |||
if type( dataQualificatif ) ~= 'table' then | |||
-- si le qualificatif n'est pas dans la base de données, on crée une table minimum, | |||
-- qui imposera un test sur l'année, 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 '[[' .. lien .. '|' .. texte .. ']]' | |||
end | |||
end | |||
-- le jour si présent | |||
local qualifJour = '' | |||
if jour then | |||
if args.nolinks then | |||
if jour == 1 then | |||
jour = modelePremier | |||
end | |||
table.insert( wikiListe, jour ) | |||
else | |||
qualifJour = dataQualificatif.jour and dataQualificatif.qualificatif | |||
or dataCat.jour and dataCat.qualificatif | |||
or '' | |||
local texteJour, lien | |||
if jour == 1 then | |||
texteJour = '1<sup>er</sup>' | |||
lien = '1er ' .. mois | |||
else | |||
texteJour = jour | |||
lien = jour .. ' ' .. mois | |||
end | |||
if qualifJour ~= '' then | |||
lien = lien .. ' ' .. qualifJour | |||
end | |||
-- s'il n'y a pas de lien sur le mois, il sera affiché avec le jour. | |||
table.insert( wikiListe, wikiLien( lien, texteJour ) ) | |||
table.insert( wikiListe, wikiLien( lien, texteJour .. ' '.. texteMois ) ) | |||
end | |||
table.insert( iso, 1, string.sub( '0' .. gjour, -2 ) ) | |||
end | |||
-- le mois | |||
if mois then | |||
if #wikiListe == 0 and annee == nil then | |||
return texteMois | |||
end | |||
if args.nolinks then | |||
if not args.masquerMois then | |||
table.insert( wikiListe, texteMois ) | |||
end | |||
else | |||
local lien | |||
if annee then | |||
if not numMois then | |||
-- mois est autre chose qu'un simple mois : saison, mois-mois... auquel cas, pas de lien | |||
else | |||
lien = existDate( dataQualificatif, annee, mois ) or existDate( dataCat, annee, mois ) | |||
if lien == nil and qualificatif and qualifJour == '' then | |||
-- 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 | |||
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]]' | |||
table.remove( wikiListe ) | |||
if not args.masquerMois then | |||
table.insert( wikiListe, wikiLien( lien, texteMois ) ) | |||
end | |||
elseif #wikiListe > 0 then | |||
-- sinon on retire le lien affichant 'jour' pour ne garder que le lien 'jour mois' | |||
table.remove( wikiListe, #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. | |||
table.insert( wikiListe, texteMois ) | |||
end | |||
end | |||
if gmois then | |||
table.insert( iso, 1, string.sub( '0' .. gmois, -2 ) ) | |||
end | |||
table.insert( wikiListe, gregAprMois ) | |||
end | |||
-- l'année | |||
if annee and not (args.julien == true and args.nolinks and jannee == annee ) then | |||
if not args.masquerAnnee then | |||
local texteAnnee = annee | |||
if annee < 0 then | |||
local anneeAvJc = 0 - annee | |||
if args.avJC == false then | |||
texteAnnee = anneeAvJc | |||
else | |||
texteAnnee = anneeAvJc .. ' <abbr class="abbr" title="' | |||
.. 'avant Jésus-Christ">av. J.-C.</abbr>' | |||
end | |||
elseif args.apJC then | |||
texteAnnee = texteAnnee .. ' <abbr class="abbr" title="' | |||
.. 'après Jésus-Christ">apr. J.-C.</abbr>' | |||
end | |||
if args.nolinks then -- seulement si on doit l'afficher | |||
table.insert( wikiListe, texteAnnee ) | |||
else | |||
local lien = existDate( dataQualificatif, annee ) or existDate( dataCat, annee ) | |||
if not lien then | |||
if annee < 0 then | |||
local anneeAvJc = 0 - annee | |||
lien = anneeAvJc .. ' av. J.-C.' | |||
else | |||
lien = annee | |||
end | |||
end | |||
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 = texteMois .. ' ' .. texteAnnee | |||
end | |||
table.insert( wikiListe, wikiLien( lien, texteAnnee ) ) | |||
end | |||
end | |||
end | |||
if annee then | |||
if gannee > 999 then | |||
table.insert( iso, 1, gannee ) | |||
elseif gannee > -1 then | |||
table.insert( iso, 1, string.sub( '000' .. gannee , -4 ) ) | |||
elseif gannee > -999 then | |||
-- calendrier grégorien proleptique avec année 0. | |||
table.insert( iso, 1, 'U-' .. string.sub( '000' .. ( 0 - gannee ), -4 ) ) | |||
else | |||
table.insert( iso, 1, 'U' .. gannee ) | |||
end | |||
end | |||
table.insert( wikiListe, gregAprAn ) | |||
-- l'age | |||
if type( age ) == 'number' and age >= 0 and ( not naissance or age < 120 ) then | |||
if age == 0 then | |||
age = '(' .. agePrefix .. 'moins d’un\194\160an)' | |||
elseif age == 1 then | |||
age = '(' .. agePrefix .. '1\194\160an)' | |||
else | |||
age = '('.. agePrefix .. age .. '\194\160ans)' | |||
end | |||
else | |||
age = false | |||
end | |||
-- compilation du résultat | |||
local wikiTexte = table.concat( wikiListe, ' ' ) | |||
local isoTexte = table.concat( iso, '-' ) | |||
-- On ajoute un peu de sémantique. | |||
local wikiHtml = mw.html.create( '' ) | |||
if julienDate then | |||
wikiHtml:tag( 'span') | |||
:addClass( 'nowrap' ) | |||
:attr( 'data-sort-value', isoTexte ) | |||
:wikitext( julienDate ) | |||
:node( julienSup ) | |||
:done() | |||
:wikitext( julienSep ) | |||
end | |||
local dateHtml = wikiHtml:tag( 'time' ) | |||
:wikitext( wikiTexte ) | |||
if wikiTexte:match( ' ' ) then | |||
dateHtml:addClass( 'nowrap' ) | |||
end | |||
if isoTexte ~= wikiTexte then | |||
dateHtml:attr( 'datetime', isoTexte ) | |||
:attr( 'data-sort-value', 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 | |||
wikiHtml:wikitext( gregFin ) | |||
if dateRepublicaine then | |||
wikiHtml:wikitext( ' (', dateRepublicaine, ')' ) | |||
end | |||
if age then | |||
wikiHtml:wikitext( ' ' ) | |||
:tag( 'span' ) | |||
:addClass( 'noprint') | |||
:wikitext( age ) | |||
:done() | |||
end | |||
return tostring( wikiHtml ) | |||
end | end | ||
-- | |||
-- isoJourMoisAnnee transforme une date iso en un tableau équivalent à celui retourné par separationJourMoisAnnee | |||
local function isoJourMoisAnnee( dateiso ) | |||
if dateiso and dateiso:sub( 1, 2 ) == 'U-' then | |||
dateiso = dateiso:sub( 2 ) | |||
end | |||
local annee, mois, jour = dateiso:match( '^(%-?%d%d%d%d+)%-(%d+)%-(%d+)$' ) | |||
if not annee then | |||
annee, mois = dateiso:match( '^(%-?%d%d%d%d+)%-(%d+)$' ) | |||
end | |||
if not annee then | |||
annee = dateiso:match( '^(%-?%d%d%d%d+)$' ) | |||
end | |||
if annee and tonumber( annee ) <= 0 then | |||
-- la date iso utilise une année 0 | |||
annee = tonumber( annee ) - 1 | |||
end | |||
if not annee then | |||
mois, jour = dateiso:match( '^(%d+)%-(%d+)$' ) | |||
end | |||
return fun.validationJourMoisAnnee{ jour, mois, annee } | |||
end | end | ||
-- analyseDate sépare la date du contenu qui précède et suit, supprime les liens, et retourne si possible une table avec jour mois année | |||
local function analyseDate( d ) | |||
if trim( d ) then | |||
local datesMultiples = d:match( ' ou ' ) or d:match( '^[Ee]ntre ' ) or d:match( '<time.->.-<time.->' ) | |||
if datesMultiples then | |||
return d | |||
end | |||
local approx = d:match( '^[Vv]ers ' ) or d:match( '^[Aa]près ' ) or d:match( '^[Aa]vant ' ) | |||
-- booléen qui indique que la date est approximative, empêchant l'affichage de l'âge ou de la durée | |||
approx = approx and true or false | |||
local analyse = d | |||
-- s'il s'agit d'une date formattée avec {{date}}, on utilisera la valeur du datetime pour reconstruire la date | |||
local dateiso = d:match( 'datetime="([U%d-]+)"' ) or d:match( '<time>(.-)</time>' ) | |||
local debut, strDate, fin | |||
if dateiso then | |||
-- supprime le formatage créé par {{date}} | |||
debut, strDate, fin = analyse:match( '(.-)<time.->(.-)</time>(.*)' ) | |||
end | |||
if not strDate then | |||
-- sépare une date av. J.-C. du contenu qui suit | |||
strDate, fin = analyse:match( '(.-%d av%. J%.%-C%.]*%-?)(.*)' ) | |||
end | |||
if not strDate then | |||
-- sépare la date (avec ses liens) d'une référence ou contenu commençant par un espace | |||
strDate, fin = analyse:match( '(.-%d%d%d%]*%-?)([\127 ].+)' ) | |||
end | |||
if not strDate then | |||
-- sépare la date du contenu commençant par <br> | |||
strDate, fin = analyse:match( '(.-%d%d%d%]*%-?)(<br ?/?>.+)' ) | |||
end | |||
analyse = strDate or analyse | |||
-- supprime les liens | |||
analyse = analyse:gsub( | |||
'%[%[([^%[%]|]*)|?([^%[%]]*)%]%]', | |||
function ( l, t ) | |||
return trim( t ) or l | |||
end | |||
) | |||
local t, r | |||
if dateiso then | |||
-- Si la date était formatée avec {{date}}, on la reconstruit à partir de la valeur de datetime | |||
t, r = isoJourMoisAnnee( dateiso ) | |||
end | |||
if t then | |||
local tTexte, rTexte = fun.separationJourMoisAnnee( analyse ) | |||
if r.annee and r.jour then | |||
local amj = r.annee * 10000 + r.numMois * 100 + r.jour | |||
-- Les dates avant le 14 octobre 1582 sont dans le calendrier julien mais utilisent un datetime grégorien | |||
local gregToJul = amj < 15821014 | |||
if not gregToJul and amj < 15821024 then | |||
-- Entre le 14 et le 23 octobre, on ne peut pas différencier entre julien et grégorien sans comparer avec le texte | |||
gregToJul = tTexte and rTexte.jour ~= r.jour | |||
end | |||
if gregToJul then | |||
local jannee, jmois, jjour = fun.gregorianToJulian( r.annee, r.numMois, r.jour ) | |||
r = { | |||
annee = jannee, | |||
numMois = jmois, | |||
mois = listeMois[jmois].nom, | |||
jour = jjour | |||
} | |||
end | |||
end | |||
if tTexte then | |||
-- On analyse le texte de la date pour repérer les dates partiellement masquées | |||
-- Si seul le jour est affiché, separationJourMoisAnnee l'interprète comme une année | |||
if not rTexte.jour and not rTexte.mois and rTexte.annee == r.jour then | |||
r.masquerMois = true | |||
r.masquerAnnee = true | |||
elseif rTexte.jour == r.jour and rTexte.mois == r.mois and not rTexte.annee then | |||
r.masquerAnnee = true | |||
end | |||
end | |||
else | |||
t, r = fun.separationJourMoisAnnee( analyse ) | |||
end | |||
if t then | |||
return r, fin, debut, approx | |||
else | |||
return d, fin, debut, approx | |||
end | |||
end | |||
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és pour gérer les cas où | |||
-- le paramètre contient déjà un modèle date. | |||
-- Paramètres : | |||
-- 1 : type de date à afficher (naissance / n, mort / m, ou date / d) | |||
-- 2 : Date ou date de naissance | |||
-- 3 : Date de mort si type n ou m | |||
-- qualificatif = suffixe des page de date à lier (exemple : en musique) | |||
-- nolinks : n'affiche pas de lien | |||
-- préfixe : préfixe à afficher s'il y a un jour (par défaut '') | |||
-- préfixe sans jour : préfixe à afficher s'il n'y a pas de jour (par défaut : '') | |||
function fun.dateInfobox( frame ) | |||
local args = frame.args | |||
if type( args ) ~= 'table' or not ( args[1] and args[2] ) then | |||
return | |||
end | |||
-- prefix ajoute un préfixe en fonction de la présence ou non du jour si le paramètre "préfixe sans jour" est défini | |||
local function prefix( dateString ) | |||
if dateString then | |||
local datetime = dateString:match( 'datetime="([U%d%-]+)"' ) | |||
if datetime and datetime:match('%-%d%d%-%d%d') and trim( args['préfixe'] ) then | |||
return args['préfixe'] .. ' ' .. dateString | |||
end | |||
if trim( args['préfixe sans jour'] ) then | |||
return args['préfixe sans jour'] .. ' ' .. dateString | |||
end | |||
end | |||
return dateString | |||
end | |||
local naissance = args[1]:match( '^n' ) == 'n' | |||
local mort = args[1]:match( '^m' ) or args[1]:match( 'décès' ) | |||
local evenement = args[1]:match( '^é' ) | |||
local affichageDate, qualificatif = args[2], args[4] | |||
local affichageDateTab, resultatDate, complementDate, prefixeDate, approxDate | |||
local dateNaissance, dateMort, approxNaissance, approxMort | |||
if mort or evenement then | |||
affichageDate = args[3] | |||
end | |||
if not trim( affichageDate ) then | |||
return | |||
end | |||
if affichageDate:match( ']]</time>' ) or 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 or evenement ) and ( affichageDate:match( 'wikidata%-linkback' )) then | |||
local _ | |||
dateNaissance, _, _, approxNaissance = analyseDate( args[2] ) | |||
dateMort, _, _, approxMort = analyseDate( args[3] ) | |||
resultatDate = affichageDate | |||
else | |||
return prefix( affichageDate ) | |||
end | |||
else | |||
affichageDateTab, complementDate, prefixeDate, approxDate = analyseDate( affichageDate ) | |||
if type( affichageDateTab ) ~= 'table' then | |||
return affichageDateTab | |||
else | |||
if naissance then | |||
local _ | |||
dateNaissance, approxNaissance = affichageDateTab, approxDate | |||
dateMort, _, _, approxMort = analyseDate( args[3] ) | |||
elseif mort then | |||
local _ | |||
dateNaissance, _, _, approxNaissance = analyseDate( args[2] ) | |||
dateMort, approxMort = affichageDateTab, approxDate | |||
else | |||
qualificatif = args[3] | |||
end | |||
affichageDateTab.naissance = not approxNaissance and naissance | |||
affichageDateTab.mort = not approxMort and mort | |||
affichageDateTab.evenement = evenement | |||
affichageDateTab.qualificatif = args.qualificatif or qualificatif | |||
affichageDateTab.liens = true -- Dans les infobox, liens activés par défaut | |||
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 approxNaissance 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 or evenement ) and | |||
dateNaissance and | |||
dateMort and | |||
not approxNaissance and | |||
not approxMort 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 .. '\194\160ans' .. suffixAge | |||
elseif calculAge == 1 then | |||
age = prefixAge .. 'un\194\160an' .. suffixAge | |||
elseif calculAge == 0 then | |||
age = prefixAge .. 'moins d’un\194\160an' .. suffixAge | |||
end | |||
if complementDate and complementDate:match( 'ans?%)' ) then | |||
complementDate = '' | |||
end | |||
end | |||
return ( prefixeDate or '' ) .. prefix( resultatDate ) .. ( complementDate or '' ) .. age | |||
end | |||
function fun.dureeInfobox( frame ) | |||
local args = frame.args | |||
if type( args ) ~= 'table' or not args[1] then | |||
return | |||
end | |||
-- vérifie si une chaîne semble contenir une durée | |||
local function contientDuree( chaine ) | |||
return chaine and ( | |||
mw.ustring.match( chaine, '%f[%w]ans?%f[^%w]' ) or | |||
mw.ustring.match( chaine, '%f[%w]mois%f[^%w]' ) or | |||
mw.ustring.match( chaine, '%f[%w]jours?%f[^%w]' ) | |||
) | |||
end | |||
local jour1, mois1, annee1, jour2, mois2, annee2 = '', '', '', '', '', '' | |||
local t1, fin1, _, approx1 = analyseDate( args[1] ) | |||
if approx1 or type( t1 ) ~= 'table' then | |||
return | |||
end | |||
jour1 = t1.jour or '' | |||
mois1 = t1.numMois or '' | |||
annee1 = t1.annee or '' | |||
if args[2] and args[2] ~= "" then | |||
local t2, fin2, _, approx2 = analyseDate( args[2] ) | |||
if approx2 or type( t2 ) ~= 'table' then | |||
return | |||
end | |||
if contientDuree( fin2 ) then | |||
-- La durée semble déjà renseignée manuellement | |||
return | |||
end | |||
jour2 = t2.jour or '' | |||
mois2 = t2.numMois or '' | |||
annee2 = t2.annee or '' | |||
if annee1 == '' or annee2 == '' then | |||
-- Mieux vaut ne pas extrapoler l'année | |||
return | |||
end | |||
if ( jour1 ~= '' and jour2 == '' ) or | |||
( mois1 ~= '' and mois2 == '' ) then | |||
-- Si la deuxième date est moins précise que la première, mieux vaut ne rien afficher | |||
return | |||
end | |||
elseif annee1 == '' or contientDuree( fin1 ) then | |||
-- L'année n'est pas spécifiée ou la durée semble déjà renseignée | |||
return | |||
end | |||
local duree = (require 'Module:Durée')._duree({ jour1, mois1, annee1, jour2, mois2, annee2, noerror = true }) | |||
if duree then | |||
return '<br /><small>(' .. duree .. ')</small>' | |||
end | |||
end | |||
--- | |||
-- la fonction dateISO renvoie un date au format aaaa-mm-jj (sans liens) | -- 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]] | -- l'année peut être sous la forme 2013 ou [[2013 en litérature|2013]] | ||
-- le mois peut être en | -- le mois peut être en lettres ou en chiffres | ||
-- le jour peut être sous la forme '05', '{{1er}}' ou 'vendredi 13' | -- le jour peut être sous la forme '05', '{{1er}}' ou 'vendredi 13' | ||
function fun.dateISO( frame ) | 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 <= listeMois[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 | end | ||
--- | |||
-- Rang du jour dans l'année | -- Rang du jour dans l'année | ||
-- 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 mt = tonumber(arguments.month or arguments[2]) or 1 | ||
local dy = tonumber(arguments.day or arguments[3]) or 1 | local dy = tonumber(arguments.day or arguments[3]) or 1 | ||
-- Rangs des premiers des mois | -- Rangs des premiers des mois | ||
local ranks = {0,31,59,90,120,151,181,212,243,273,304,334} | local ranks = {0,31,59,90,120,151,181,212,243,273,304,334} | ||
local rank = (ranks[mt] or 0) + dy - 1 | local rank = (ranks[mt] or 0) + dy - 1 | ||
if(fun.isLeapYear(yr) and (mt >= 3)) then | if(fun.isLeapYear(yr) and (mt >= 3)) then | ||
| Ligne 488 : | Ligne 1 303 : | ||
local yr1 = tonumber(arguments[1]) or 0 | local yr1 = tonumber(arguments[1]) or 0 | ||
local yr2 = tonumber(arguments[2]) or 0 | local yr2 = tonumber(arguments[2]) or 0 | ||
return fun.daysSinceOrigin(yr2) - fun.daysSinceOrigin(yr1) | return fun.daysSinceOrigin(yr2) - fun.daysSinceOrigin(yr1) | ||
end | end | ||
| Ligne 498 : | Ligne 1 313 : | ||
end | end | ||
-- Test d'année bissextile | -- Test d'année bissextile (Suit le calendrier grégorien) | ||
function fun.isLeapYear(year) | function fun.isLeapYear(year) | ||
local yr = tonumber(year) or 1 | local yr = tonumber(year) or 1 | ||
| Ligne 514 : | Ligne 1 329 : | ||
else | else | ||
for i=1,7,2 do | for i=1,7,2 do | ||
p = pattern[n%10 + 1] | local p = pattern[n%10 + 1] | ||
for j=0,2 do | for j=0,2 do | ||
p = string.gsub(p,tostring(j),letters[i+j]) | p = string.gsub(p,tostring(j),letters[i+j]) | ||
| Ligne 528 : | Ligne 1 343 : | ||
function fun.dateRepublicain(frame) | function fun.dateRepublicain(frame) | ||
local pframe = frame:getParent() | local pframe = frame:getParent() | ||
local arguments = pframe.args | |||
return fun.formatRepCal(fun.do_toRepCal(arguments)) | |||
end | end | ||
--- | |||
-- Calcul d'une date dans le calendrier républicain | -- Calcul d'une date dans le calendrier républicain | ||
-- 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...) | ||
| Ligne 544 : | Ligne 1 360 : | ||
end | end | ||
--- | |||
-- Formatage d'une date selon le calendrier républicain | -- Formatage d'une date selon le calendrier républicain | ||
-- Usage : fun.formatRepCal{année,mois,jour} | -- Usage : fun.formatRepCal{année,mois,jour} | ||
function fun.formatRepCal(arguments) | function fun.formatRepCal(arguments) | ||
local months = {"Vendémiaire","Brumaire","Frimaire","Nivôse","Pluviôse","Ventôse","Germinal","Floréal","Prairial","Messidor","Thermidor","Fructidor"} | local months = {"Vendémiaire","Brumaire","Frimaire","Nivôse","Pluviôse","Ventôse","Germinal","Floréal","Prairial","Messidor","Thermidor","Fructidor"} | ||
local extras = {"de la vertu","du génie","du travail","des récompenses","de l'opinion","de la | local extras = {"de la vertu","du génie","du travail","des récompenses","de l'opinion","de la Révolution"} | ||
local result = "" | local result = "" | ||
if(arguments[2] < 13) then | if(arguments[2] < 13) then | ||
result = result .. tostring(arguments[3]) .. " | result = result .. tostring(arguments[3]) .. "\194\160" .. months[arguments[2]] | ||
else | else | ||
result = result .. "jour " .. extras[arguments[3]] | result = result .. "jour " .. extras[arguments[3]] | ||
| Ligne 559 : | Ligne 1 376 : | ||
end | end | ||
--- | |||
-- Voir Modèle:Âge | -- Voir Modèle:Âge | ||
-- retourne l' | -- retourne l'âge en fonction de la ou les dates fournies. La valeur retournée est de type 'number' | ||
-- | -- Paramètres : | ||
-- 1, 2, 3 : année, mois jour de naissance (supposé dans le calendrier grégorien) | -- 1, 2, 3 : année, mois jour de naissance (supposé dans le calendrier grégorien) | ||
-- 4, 5, 6 : année, mois, | -- 4, 5, 6 : année, mois, jour 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 | |||
an = tonumber( an ) | |||
mn = tonumber( mn ) | |||
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 | |||
-- si l'intervalle traverse l'année zéro, il faut soustraire une année | |||
-- parce que cette année n'existe pas dans les calendriers chrétiens | |||
if an < 0 and ac > 0 then | |||
age = age - 1 | |||
end | |||
if mc == mn then | |||
if jc == nil or jn == nil then | |||
return | |||
end | |||
return age - ( jc < jn and 1 or 0 ) | |||
else | |||
return age - ( mc < mn and 1 or 0 ) | |||
end | |||
end | end | ||
function fun.modeleAge( frame ) | function fun.modeleAge( frame ) | ||
local args = Outils.extractArgs( frame ) | |||
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 '<span class="error">Paramètres incorrects ou insuffisants pour calculer l\'âge précis</span>' | |||
end | |||
end | end | ||
--- | |||
-- 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, | 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 | --- | ||
function fun.julianDayJulian( year, month, day, hour, | -- 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 | end | ||
-- calcul d'une date dans le calendrier | --- | ||
function fun. | -- 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 | end | ||
function fun. | --- | ||
-- calcul d'une date dans le calendrier julien à partir du jour julien | |||
-- calcul basé sur l'algorithme de la page https://en.wikipedia.org/wiki/Julian_day#Julian_or_Gregorian_calendar_from_Julian_day_number | |||
function fun.julianDayToJulian( julianDay ) | |||
local y = 4716 | |||
local v = 3 | |||
local j = 1401 | |||
local u = 5 | |||
local m = 2 | |||
local s = 153 | |||
local n = 12 | |||
local w = 2 | |||
local r = 4 | |||
local B = 274277 | |||
local p = 1461 | |||
local C = -38 | |||
local f = julianDay + j | |||
local e = r * f + v | |||
local g = math.modf( math.fmod( e, p ) / r ) | |||
local h = u * g + w | |||
local D = math.modf( math.fmod( h, s ) / u ) + 1 | |||
local M = math.fmod( math.modf( h / s ) + m, n ) + 1 | |||
local Y = math.modf( e / p ) - y + math.modf( ( n + m - M ) / n ) | |||
return Y, M, D | |||
end | end | ||
-- | --- | ||
-- calcul d'une date dans le calendrier grégorien à partir d'une date dans le calendrier julien | |||
function fun. | 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 | 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 correspondants | |||
--]] | |||
function fun.CEST(frame) | |||
-- option : ne pas créer de wikilien | |||
local opt = trim(frame.args[1] or frame:getParent().args[1]) | |||
-- on récupère l'information dans la zone courante | |||
local t = mw.getContentLanguage():formatDate("I", nil, true) | |||
if (t == "1") then -- heure d'été | |||
if (opt == "sans lien") then | |||
return "CEST" | |||
elseif (opt == "décalage") then | |||
return "2" | |||
else | |||
return "[[Heure d'été d'Europe centrale|CEST]]" | |||
end | |||
else -- heure d'hiver (ou autre zone où ça ne s'applique pas) | |||
if (opt == "sans lien") then | |||
return "CET" | |||
elseif (opt == "décalage") then | |||
return "1" | |||
else | |||
return "[[Heure normale d'Europe centrale|CET]]" | |||
end | |||
end | |||
end | end | ||
return fun | return fun | ||
Dernière version du 22 février 2026 à 00:16
La documentation pour ce module peut être créée à Module:Date/doc
-- luacheck: globals mw, no max line length
local fun = {}
local Outils = require 'Module:Outils'
-- chargement de la base de données 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 où 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 fonctions qui l'utilisent.
local trim = Outils.trim
-- Fonction destinée à mettre la première lettre du mois en majuscule :
-- utilisation de string car aucun mois ne commence 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 alias, en minuscule
local listeMois = {
{ num = 1, nJour = 31, abrev = 'janv.', nom = 'janvier', alias = { 'jan.', 'janv.', 'jan', 'janv', 'january' } },
{ num = 2, nJour = 29, abrev = 'fév.', nom = 'février', alias = { 'fevrier', 'fev.', 'fev', 'fév.', 'fév', 'févr', 'févr.', 'february', 'feb', 'feb.' } },
{ num = 3, nJour = 31, abrev = 'mars', nom = 'mars', alias = { 'mar.', 'mar', 'march' } },
{ num = 4, nJour = 30, abrev = 'avr.', nom = 'avril', alias = { 'avr.', 'avr', 'apr', 'april'} },
{ num = 5, nJour = 31, abrev = 'mai', nom = 'mai', alias = { 'may' } },
{ num = 6, nJour = 30, abrev = 'juin', nom = 'juin', alias = { 'jun', 'june' } },
{ num = 7, nJour = 31, abrev = 'juill.', nom = 'juillet', alias = { 'juil.', 'juil', 'juill.', 'juill', 'jul', 'july' } },
{ num = 8, nJour = 31, abrev = 'août', nom = 'août', alias = { 'aoû', 'aug', 'august' } },
{ num = 9, nJour = 30, abrev = 'sept.', nom = 'septembre', alias = { 'sept.', 'sept', 'sep.', 'sep', 'september' } },
{ num = 10, nJour = 31, abrev = 'oct.', nom = 'octobre', alias = { 'oct.', 'oct', 'october' } },
{ num = 11, nJour = 30, abrev = 'nov.', nom = 'novembre', alias = { 'nov.', 'nov', 'november' } },
{ num = 12, nJour = 31, abrev = 'déc.', nom = 'décembre', alias = { 'decembre', 'déc.', 'dec.', 'dec', 'déc', 'december' } },
aout = { num = 8, nJour = 31, abrev = 'aout', nom = 'aout', alias = { 'aou' } },
}
-- ajoute les noms, abréviations et alias en tant que clés de listeMois
for i = 1, 12 do
local mois = listeMois[i]
listeMois[tostring( i )] = mois
if i < 10 then
listeMois['0' .. i] = mois
end
listeMois[mois.nom] = mois
listeMois[mois.abrev] = mois
for j = 1, #mois.alias do
listeMois[mois.alias[j]] = mois
end
end
for i = 1, #listeMois.aout.alias do
listeMois[listeMois.aout.alias[i]] = listeMois.aout
end
local liste_saisons = {
{ 'printemps', 'spring', },
{ 'été', 'summer', },
{ 'automne', 'autumn', },
{ 'hiver', 'winter', },
}
-- à partir d'un nom de saison (en français ou en anglais),
-- retourne son nom canonique (exemple : "été")
-- si non reconnu, retourne nil
function fun.determinationSaison( saison )
local s = trim( saison )
if s then
s = s:gsub( 'É', 'é' ):lower()
for i = 1, 4 do
for j = 1, #liste_saisons[i] do
if s == liste_saisons[i][j] then
return liste_saisons[i][1]
end
end
end
end
end
---
-- à partir d'un nom de mois (en français ou en anglais), de son numéro ou d'une abréviation,
-- retourne son nom canonique (exemple : "juin") et son numéro (exemple : 6)
-- si non reconnu, retourne nil, nil
function fun.determinationMois( mois )
local result
local num = tonumber( mois )
if num then
result = listeMois[num]
else
local str = trim( mois )
if str then
result = listeMois[str]
if not result then
result = listeMois[str:gsub( 'É', 'é' ):gsub( 'Û', 'û' ):lower()]
end
end
end
if result then
return result.nom, result.num
else
return nil, nil
end
end
-- fonction interne à modeleDate, pour déterminer si on peut se passer de faire un ifexist
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 remplacé par celui de la base de données, ce qui permet des alias.
local lien = annee
if dataQualificatif.qualificatif ~= '' then
lien = lien .. ' ' .. dataQualificatif.qualificatif
end
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 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'année 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="[Pp]remier" *>1<sup>er</sup></abbr>', '1<sup>er</sup>', '1er' }
for i = 1, #nomJour do
jour = jour:gsub( nomJour[i], '' )
end
for i = 1, #premier do
jour = jour:gsub( premier[i], '1' )
end
jour = trim( jour )
end
return jour
end
---
-- Sépare une chaine date en une 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, '<span class="error">' .. periode .. ' invalide (' .. valeur .. ')</span>'
end
local dateAvantCleanup = date
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 mmm2 = '([^%s%p%d]+[.]?[-/][^%s%p%d]+[.]?)' -- mois-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
date = fun.nettoyageJour( date )
if date == nil then
return erreur( 'Date', dateAvantCleanup )
end
if date:find( '[[', nil, true ) then
date = date
-- suppression catégories (doit être exécuté avant le code de suppression des liens)
:gsub( '%[%[[Cc]atégorie:.-%]%]', '' )
:gsub( '%[%[[Cc]ategory:.-%]%]', '' )
-- suppression liens
:gsub( '%[%[([^%[%]|]*)|?([^%[%]]*)%]%]', function ( l, t ) return trim( t ) or l end )
end
date = date
-- suppression balises
:gsub( '%b<>', '' )
-- suppression des espaces insécables
-- nbsp
:gsub( '\194\160', ' ' )
:gsub( ' ', ' ' )
:gsub( ' ', ' ' )
-- narrow nbsp
:gsub( '\226\128\175', ' ' )
:gsub( ' ', ' ' )
-- thin space
:gsub( '\226\128\137', ' ' )
:gsub( ' ', ' ' )
:gsub( ' ', ' ' )
-- simple space
:gsub( ' ', ' ' )
-- plusieurs espaces (doit être exécuté après les autres remplacements)
:gsub( ' +', ' ' )
-- réduction av. J-C pour simplifier un peu les regex
:gsub( '(%d+) ?[Aa][Vv]%.? ?[Jj][ .-]*[Cc]%.?', '-%1' )
-- suppression de l'heure dans les dates 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', dateAvantCleanup )
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( '^'..mmm2..s..aj..moins..'$' ) then
-- mmm-mmm aaaa
mois, separateur, annee, masquerAnnee = date:match( '^'..mmm2..sep..aj..moins..'$' )
if separateur:match( '^.+%-$' ) then
annee = '-' .. annee
end
elseif date:match( '^'..j..s..mmm..moins..'$' ) then
-- jj mmm
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', dateAvantCleanup )
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
---
-- validationJourMoisAnnee vérifie que les paramètres correspondent à une date valide.
-- la date peut être dans les paramètres 1 à 3, ou dans des paramètres jour, mois et annee.
-- La fonction retourne true suivi d'une table avec la date en paramètres nommés (sans accent sur année)
-- ou false suivi d'un message d'erreur.
function fun.validationJourMoisAnnee( frame )
local args = Outils.extractArgs( frame )
local jour, mois, numMois, annee
local bjour = args['jour'] or args[1] or ''
local bmois = tostring( args['mois'] or args[2] or '' )
local bannee = args['annee'] or args['année'] or args[3] or ''
local function erreur( periode, valeur )
return false, '<span class="error">' .. periode .. ' invalide (' .. valeur .. ')</span>'
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 = bannee:match( '^(%d+) ?[Aa][Vv]%.? ?[Jj][ .-]*[Cc]%.?' )
annee = tonumber( annee )
if annee then
annee = 0 - annee
else
return erreur( 'Année', bannee )
end
elseif annee == 0 then
return erreur( 'Année', 0 )
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.determinationSaison( bmois )
if mois == nil then
local mois1, sep, mois2 = bmois:match( '^([^%s%p%d]+[.]?)([-/])([^%s%p%d]+[.]?)$' )
if mois1 then
mois1 = fun.determinationMois( mois1 )
mois2 = fun.determinationMois( mois2 )
if mois1 == nil or mois2 == nil then
return erreur( 'Mois', bmois )
end
mois = mois1 .. sep .. mois2
else
return erreur( 'Mois', bmois )
end
end
end
-- on traite le jour si présent
if Outils.notEmpty( bjour ) then
if not numMois then
erreur( 'Date', 'jour avec saison ou plusieurs mois' )
end
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 > listeMois[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
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, '<span class="error">année improbable (' .. annee .. ')</span>'
end
local resultat = {
jour = jour,
mois = mois,
numMois = numMois,
annee = annee,
masquerAnnee = args.masquerAnnee,
masquerMois = args.masquerMois,
}
return true, resultat
end
---
-- émule le modèle {{m|Date}}.
-- Paramètres :
-- 1 : jour (numéro ou "1er") ou la date complète
-- 2 : mois (en toutes lettres) ou spécialité de l'année
-- 3 : année (nombre)
-- 4 : spécialité de l'année
-- julien : date dans le calendrier julien
-- compact : affiche le mois sous forme d'abréviation
-- avJC : non pour désactiver l'affichage de « av. J.-C. » pour les dates négatives
-- âge : ajoute la durée depuis cette date
-- agePrefix : préfixe pour l'age, 'à ' par défaut pour les décès
-- liens : active les liens par défaut
-- nolinks : ne met pas de lien sur la date (a précédence sur le paramètre "liens")
-- afficherErreurs : en cas d'erreur, si défini à "non" ne retourne pas un message d'erreur, mais le 1er argument inchangé
-- categoriserErreurs : en cas d'erreur, si défini à "non" ne catégorise pas ; peut aussi être défini avec une catégorie à utiliser à la place de celle par défaut
-- naissance : ajoute la class "bday"
-- mort : ajoute la class "dday"
function fun.modeleDate( frame )
local Yesno = require 'Module:Yesno'
local args
if frame. args and frame.args.nogetparent then args = frame.args else args = Outils.extractArgs( frame ) end
-- l'import des paramètres passés au modèle appelant et non au #invoke est désactivable par nogetparent
for i,j in ipairs(args) do args[i] = tostring(j) end
local resultat
local dateNaissanceMort
local cherchedeuxdates = args.mort or args['événement'] or args.evenement
-- analyse des paramètres non nommés (ou paramètres de la date jour, mois, annee)
local test, params
local arg1, arg2, arg3, arg4 = fun.nettoyageJour( args[1] ), trim( args[2] ), trim( args[3] ), trim( args[4] )
if cherchedeuxdates then args2 = fun.nettoyageJour( args2 ) end
local slashesinarg1 = arg1 and arg1:match( '[^ ./-][ ./-]+[^ ./-]' )
local slashesinarg2 = cherchedeuxdates and arg2 and arg2:match( '[^ ./-][ ./-]+[^ ./-]' )
if arg1 and not arg3 and ((slashesinarg1 and not cherchedeuxdates) or arg2 == nil or dataLiens[arg2] or mw.ustring.match( arg2, '%a %a' ) ) then
-- une date dans le premier paramètre
test, params = fun.separationJourMoisAnnee( arg1 )
if test then
if dataLiens[trim( arg2 )] then
params.qualificatif = trim( arg2 )
end
end
elseif cherchedeuxdates and (not arg4) and ( slashesinarg1 or slashesinarg2 or dataLiens[arg3] or (arg3 and mw.ustring.match( arg3, '%a %a' ) ) ) then
-- deux dates dans les deux premiers paramètres
test, params = fun.separationJourMoisAnnee( arg1 )
if test then
dateNaissanceMort = trim( arg2 )
if dataLiens[trim( arg3 )] then
params.qualificatif = trim( arg3 )
end
end
else
local cleanArgs = {jour = args.jour, mois = args.mois, annee = args.annee or args['année']}
if arg1 and listeMois[arg1] and not tonumber(arg1) then --le premier argument est un mois donc le deuxième est présumé année
cleanArgs.mois = (cleanArgs.mois or arg1)
cleanArgs.annee = cleanArgs.annee or arg2
cleanArgs.qualificatif = arg3
else
cleanArgs.jour = cleanArgs.jour or arg1
cleanArgs.mois = cleanArgs.mois or arg2
cleanArgs.annee = cleanArgs.annee or arg3
cleanArgs.qualificatif = arg4
end
local function masquerParam( p )
-- sépare le signe moins final éventuel signifiant que le paramètre ne doit pas être affiché.
if type( p ) ~= 'string' then
return p, nil
end
local value, mask = p:match( '^%s*(.-)(%-?)%s*$' )
return value, ( mask == '-' or nil )
end
cleanArgs.mois, cleanArgs.masquerMois = masquerParam( cleanArgs.mois )
cleanArgs.annee, cleanArgs.masquerAnnee = masquerParam( cleanArgs.annee )
-- Si les paramètres ont été envoyés directement, ils ont précédence
if args.masquerMois then cleanArgs.masquerMois = args.masquerMois end
if args.masquerAnnee then cleanArgs.masquerAnnee = args.masquerAnnee end
test, params = fun.validationJourMoisAnnee( cleanArgs )
if test and dataLiens[trim( cleanArgs.qualificatif )] then
params.qualificatif = trim( cleanArgs.qualificatif )
end
end
-- analyse des paramètres nommés
if test then
params.agePrefix = args.agePrefix
if args.qualificatif and dataLiens[args.qualificatif] then
params.qualificatif = args.qualificatif
end
-- julien peut avoir trois valeurs : inactif, format standard (true), format court
params.julien = Yesno( args.julien, 'court', false )
params.avJC = Yesno( args.avJC )
if args['républicain'] and args['républicain'] ~= '' then
if args['républicain'] == 'liens' then
params.republicain = 'liens'
else
params.republicain = Yesno( args['républicain'], false )
end
else
params.republicain = false
end
if args.dateNaissanceMort and args.dateNaissanceMort ~= '' then
dateNaissanceMort = args.dateNaissanceMort
elseif args['dateNaissanceÉvénement'] and args['dateNaissanceÉvénement'] ~= '' then
dateNaissanceMort = args['dateNaissanceÉvénement']
end
if dateNaissanceMort then
local testNaissanceMort, paramsNaissanceMort = fun.separationJourMoisAnnee( dateNaissanceMort )
if testNaissanceMort then
params.anneeNaissanceMort, params.moisNaissanceMort, params.numMoisNaissanceMort, params.jourNaissanceMort = paramsNaissanceMort.annee, paramsNaissanceMort.mois, paramsNaissanceMort.numMois, paramsNaissanceMort.jour
end
end
local listeParam = {
age = 'âge',
['âge'] = 'âge',
naissance = 'naissance',
mort = 'mort',
['événement'] = 'événement',
evenement = 'evenement',
['décès'] = 'mort',
apJC = 'apJC',
nolinks = 'nolinks',
compact = 'compact',
compacte = 'compact',
}
for n, v in pairs( listeParam ) do
params[v] = params[v] or Yesno( args[n], true, false ) or nil
end
if not params.nolinks then
local liens = Yesno( args.liens )
if liens == nil then
-- liens actifs par défaut si qualificatif
liens = params.qualificatif and params.qualificatif ~= "" and true or false
end
params.nolinks = not liens
end
-- sortie pour les tests unitaire, ou pour débugger
if args.debug then
return params
end
resultat = fun._modeleDate( params )
else
local yn_afficherErreurs = Yesno( args.afficherErreurs )
if yn_afficherErreurs == nil or yn_afficherErreurs == true then
resultat = params
else
resultat = args[1]
end
local currentTitle = mw.title.getCurrentTitle()
if currentTitle:inNamespaces( 0, 4, 10, 14, 100 )
and not Outils.notEmpty( args.nocat )
and not currentTitle.prefixedText:match( '^Modèle:.+/Test$' ) then
local categorie
local yn_categoriserErreurs = Yesno( args.categoriserErreurs, 'custom', true )
if yn_categoriserErreurs == nil or yn_categoriserErreurs == true then
categorie = '[[Catégorie:Page utilisant le modèle date avec une syntaxe erronée]]'
elseif yn_categoriserErreurs == false then
categorie = ''
else
local nomCategorie = args.categoriserErreurs
:gsub( '^%[%[', '' )
:gsub( '%]%]$', '' )
:gsub( '^:?[Cc]atégorie:', '' )
:gsub( '^:?[Cc]atégory:', '' )
categorie = '[[Catégorie:' .. nomCategorie .. ']]'
end
resultat = resultat .. categorie
end
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'âge, naissance et mort
local agePrefix = args.agePrefix
local age = args['âge'] and fun.age( annee, numMois, jour )
local naissance = args.naissance
local mort = args.mort
local evenement = args['événement'] or args.evenement
if mort and args.anneeNaissanceMort then
age = fun.age( args.anneeNaissanceMort, args.numMoisNaissanceMort, args.jourNaissanceMort, annee, numMois, jour )
agePrefix = agePrefix or 'à ' -- faut-il mettre \194\160 ?
elseif evenement and args.anneeNaissanceMort then
if naissance then
age = fun.age( annee, numMois, jour, args.anneeNaissanceMort, args.numMoisNaissanceMort, args.jourNaissanceMort )
else
age = fun.age(args.anneeNaissanceMort, args.numMoisNaissanceMort, args.jourNaissanceMort, annee, numMois, jour )
end
end
agePrefix = agePrefix or ''
-- 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 -- date suivant le calendrier julien si necessaire
local julienDate, julienSup, julienSep -- servira éventuellement à afficher la date selon le calendrier julien
local gregAprMois, gregAprAn, gregFin -- message de calendrier grégorien lorsque la date est selon le calendrier julien
local dateRepublicaine
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
args.julien = false
elseif args.julien then
gannee, gmois, gjour = fun.julianToGregorian( annee, numMois, jour )
annee, mois, jour = gannee, listeMois[gmois].nom, gjour
if jjour == 1 then
jjour = modelePremier
end
if args.compact then
jmois = listeMois[jmois].abrev
end
if args.julien == 'court' then
julienDate = jjour .. ' ' .. jmois .. ' '
julienSup = '<sup>[[calendrier julien|jul.]]</sup>'
if jannee == annee then
gregAprMois = '<sup>[[calendrier grégorien|grég.]]</sup>'
else
julienDate = julienDate .. jannee .. ' '
gregAprAn = '<sup>[[calendrier grégorien|grég.]]</sup>'
end
julienSep = ' / '
else
julienDate = jjour .. ' ' .. jmois .. ' ' .. jannee
julienSep = ' ('
gregFin = ' [[Passage du calendrier julien au calendrier grégorien|dans le calendrier grégorien]])'
end
elseif args.republicain then
local DateRep = require 'Module:Date républicaine'
local RepSansLiens
if args.republicain == 'liens' then
RepSansLiens = false
else
RepSansLiens = true
end
dateRepublicaine = DateRep._date_republicaine(
RepSansLiens,
{ fun.formatRepCal( fun.do_toRepCal{gannee, gmois, gjour} ) }
)
end
else
if annee and annee < 0 then
gannee = gannee + 1
end
args.julien = false
args.republicain = false
end
-- on génère le résultat
-- Déclarations des variables
local wikiListe = {} -- reçoit le texte affiché pour chaque paramètre
local iso = {} -- reçoit le format date ISO de ce paramètre
local texteMois = mois -- texte du mois qui sera affiché (éventuellement l'abréviation)
if args.compact then
if not numMois then
-- mois est autre chose qu'un simple mois : saison, mois-mois... auquel cas, pas d'abréviation (provoquait erreur Lua)
-- (les abréviations pour le cas "mois[-/]mois" seraient théoriquement possibles, mais ça reste à implémenter)
else
if args.nolinks then
texteMois = '<abbr class="abbr" title="' .. mois .. '">' .. listeMois[mois].abrev .. '</abbr>'
else
texteMois = listeMois[mois].abrev
end
end
end
mois = mois and mois:gsub( 'aout', 'août' )
local dataQualificatif, dataCat
if not args.nolinks then
dataQualificatif = dataLiens[qualificatif or '']
if type( dataQualificatif ) ~= 'table' then
-- si le qualificatif n'est pas dans la base de données, on crée une table minimum,
-- qui imposera un test sur l'année, 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 '[[' .. lien .. '|' .. texte .. ']]'
end
end
-- le jour si présent
local qualifJour = ''
if jour then
if args.nolinks then
if jour == 1 then
jour = modelePremier
end
table.insert( wikiListe, jour )
else
qualifJour = dataQualificatif.jour and dataQualificatif.qualificatif
or dataCat.jour and dataCat.qualificatif
or ''
local texteJour, lien
if jour == 1 then
texteJour = '1<sup>er</sup>'
lien = '1er ' .. mois
else
texteJour = jour
lien = jour .. ' ' .. mois
end
if qualifJour ~= '' then
lien = lien .. ' ' .. qualifJour
end
-- s'il n'y a pas de lien sur le mois, il sera affiché avec le jour.
table.insert( wikiListe, wikiLien( lien, texteJour ) )
table.insert( wikiListe, wikiLien( lien, texteJour .. ' '.. texteMois ) )
end
table.insert( iso, 1, string.sub( '0' .. gjour, -2 ) )
end
-- le mois
if mois then
if #wikiListe == 0 and annee == nil then
return texteMois
end
if args.nolinks then
if not args.masquerMois then
table.insert( wikiListe, texteMois )
end
else
local lien
if annee then
if not numMois then
-- mois est autre chose qu'un simple mois : saison, mois-mois... auquel cas, pas de lien
else
lien = existDate( dataQualificatif, annee, mois ) or existDate( dataCat, annee, mois )
if lien == nil and qualificatif and qualifJour == '' then
-- 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
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]]'
table.remove( wikiListe )
if not args.masquerMois then
table.insert( wikiListe, wikiLien( lien, texteMois ) )
end
elseif #wikiListe > 0 then
-- sinon on retire le lien affichant 'jour' pour ne garder que le lien 'jour mois'
table.remove( wikiListe, #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.
table.insert( wikiListe, texteMois )
end
end
if gmois then
table.insert( iso, 1, string.sub( '0' .. gmois, -2 ) )
end
table.insert( wikiListe, gregAprMois )
end
-- l'année
if annee and not (args.julien == true and args.nolinks and jannee == annee ) then
if not args.masquerAnnee then
local texteAnnee = annee
if annee < 0 then
local anneeAvJc = 0 - annee
if args.avJC == false then
texteAnnee = anneeAvJc
else
texteAnnee = anneeAvJc .. ' <abbr class="abbr" title="'
.. 'avant Jésus-Christ">av. J.-C.</abbr>'
end
elseif args.apJC then
texteAnnee = texteAnnee .. ' <abbr class="abbr" title="'
.. 'après Jésus-Christ">apr. J.-C.</abbr>'
end
if args.nolinks then -- seulement si on doit l'afficher
table.insert( wikiListe, texteAnnee )
else
local lien = existDate( dataQualificatif, annee ) or existDate( dataCat, annee )
if not lien then
if annee < 0 then
local anneeAvJc = 0 - annee
lien = anneeAvJc .. ' av. J.-C.'
else
lien = annee
end
end
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 = texteMois .. ' ' .. texteAnnee
end
table.insert( wikiListe, wikiLien( lien, texteAnnee ) )
end
end
end
if annee then
if gannee > 999 then
table.insert( iso, 1, gannee )
elseif gannee > -1 then
table.insert( iso, 1, string.sub( '000' .. gannee , -4 ) )
elseif gannee > -999 then
-- calendrier grégorien proleptique avec année 0.
table.insert( iso, 1, 'U-' .. string.sub( '000' .. ( 0 - gannee ), -4 ) )
else
table.insert( iso, 1, 'U' .. gannee )
end
end
table.insert( wikiListe, gregAprAn )
-- l'age
if type( age ) == 'number' and age >= 0 and ( not naissance or age < 120 ) then
if age == 0 then
age = '(' .. agePrefix .. 'moins d’un\194\160an)'
elseif age == 1 then
age = '(' .. agePrefix .. '1\194\160an)'
else
age = '('.. agePrefix .. age .. '\194\160ans)'
end
else
age = false
end
-- compilation du résultat
local wikiTexte = table.concat( wikiListe, ' ' )
local isoTexte = table.concat( iso, '-' )
-- On ajoute un peu de sémantique.
local wikiHtml = mw.html.create( '' )
if julienDate then
wikiHtml:tag( 'span')
:addClass( 'nowrap' )
:attr( 'data-sort-value', isoTexte )
:wikitext( julienDate )
:node( julienSup )
:done()
:wikitext( julienSep )
end
local dateHtml = wikiHtml:tag( 'time' )
:wikitext( wikiTexte )
if wikiTexte:match( ' ' ) then
dateHtml:addClass( 'nowrap' )
end
if isoTexte ~= wikiTexte then
dateHtml:attr( 'datetime', isoTexte )
:attr( 'data-sort-value', 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
wikiHtml:wikitext( gregFin )
if dateRepublicaine then
wikiHtml:wikitext( ' (', dateRepublicaine, ')' )
end
if age then
wikiHtml:wikitext( ' ' )
:tag( 'span' )
:addClass( 'noprint')
:wikitext( age )
:done()
end
return tostring( wikiHtml )
end
-- isoJourMoisAnnee transforme une date iso en un tableau équivalent à celui retourné par separationJourMoisAnnee
local function isoJourMoisAnnee( dateiso )
if dateiso and dateiso:sub( 1, 2 ) == 'U-' then
dateiso = dateiso:sub( 2 )
end
local annee, mois, jour = dateiso:match( '^(%-?%d%d%d%d+)%-(%d+)%-(%d+)$' )
if not annee then
annee, mois = dateiso:match( '^(%-?%d%d%d%d+)%-(%d+)$' )
end
if not annee then
annee = dateiso:match( '^(%-?%d%d%d%d+)$' )
end
if annee and tonumber( annee ) <= 0 then
-- la date iso utilise une année 0
annee = tonumber( annee ) - 1
end
if not annee then
mois, jour = dateiso:match( '^(%d+)%-(%d+)$' )
end
return fun.validationJourMoisAnnee{ jour, mois, annee }
end
-- analyseDate sépare la date du contenu qui précède et suit, supprime les liens, et retourne si possible une table avec jour mois année
local function analyseDate( d )
if trim( d ) then
local datesMultiples = d:match( ' ou ' ) or d:match( '^[Ee]ntre ' ) or d:match( '<time.->.-<time.->' )
if datesMultiples then
return d
end
local approx = d:match( '^[Vv]ers ' ) or d:match( '^[Aa]près ' ) or d:match( '^[Aa]vant ' )
-- booléen qui indique que la date est approximative, empêchant l'affichage de l'âge ou de la durée
approx = approx and true or false
local analyse = d
-- s'il s'agit d'une date formattée avec {{date}}, on utilisera la valeur du datetime pour reconstruire la date
local dateiso = d:match( 'datetime="([U%d-]+)"' ) or d:match( '<time>(.-)</time>' )
local debut, strDate, fin
if dateiso then
-- supprime le formatage créé par {{date}}
debut, strDate, fin = analyse:match( '(.-)<time.->(.-)</time>(.*)' )
end
if not strDate then
-- sépare une date av. J.-C. du contenu qui suit
strDate, fin = analyse:match( '(.-%d av%. J%.%-C%.]*%-?)(.*)' )
end
if not strDate then
-- sépare la date (avec ses liens) d'une référence ou contenu commençant par un espace
strDate, fin = analyse:match( '(.-%d%d%d%]*%-?)([\127 ].+)' )
end
if not strDate then
-- sépare la date du contenu commençant par <br>
strDate, fin = analyse:match( '(.-%d%d%d%]*%-?)(<br ?/?>.+)' )
end
analyse = strDate or analyse
-- supprime les liens
analyse = analyse:gsub(
'%[%[([^%[%]|]*)|?([^%[%]]*)%]%]',
function ( l, t )
return trim( t ) or l
end
)
local t, r
if dateiso then
-- Si la date était formatée avec {{date}}, on la reconstruit à partir de la valeur de datetime
t, r = isoJourMoisAnnee( dateiso )
end
if t then
local tTexte, rTexte = fun.separationJourMoisAnnee( analyse )
if r.annee and r.jour then
local amj = r.annee * 10000 + r.numMois * 100 + r.jour
-- Les dates avant le 14 octobre 1582 sont dans le calendrier julien mais utilisent un datetime grégorien
local gregToJul = amj < 15821014
if not gregToJul and amj < 15821024 then
-- Entre le 14 et le 23 octobre, on ne peut pas différencier entre julien et grégorien sans comparer avec le texte
gregToJul = tTexte and rTexte.jour ~= r.jour
end
if gregToJul then
local jannee, jmois, jjour = fun.gregorianToJulian( r.annee, r.numMois, r.jour )
r = {
annee = jannee,
numMois = jmois,
mois = listeMois[jmois].nom,
jour = jjour
}
end
end
if tTexte then
-- On analyse le texte de la date pour repérer les dates partiellement masquées
-- Si seul le jour est affiché, separationJourMoisAnnee l'interprète comme une année
if not rTexte.jour and not rTexte.mois and rTexte.annee == r.jour then
r.masquerMois = true
r.masquerAnnee = true
elseif rTexte.jour == r.jour and rTexte.mois == r.mois and not rTexte.annee then
r.masquerAnnee = true
end
end
else
t, r = fun.separationJourMoisAnnee( analyse )
end
if t then
return r, fin, debut, approx
else
return d, fin, debut, approx
end
end
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és pour gérer les cas où
-- le paramètre contient déjà un modèle date.
-- Paramètres :
-- 1 : type de date à afficher (naissance / n, mort / m, ou date / d)
-- 2 : Date ou date de naissance
-- 3 : Date de mort si type n ou m
-- qualificatif = suffixe des page de date à lier (exemple : en musique)
-- nolinks : n'affiche pas de lien
-- préfixe : préfixe à afficher s'il y a un jour (par défaut '')
-- préfixe sans jour : préfixe à afficher s'il n'y a pas de jour (par défaut : '')
function fun.dateInfobox( frame )
local args = frame.args
if type( args ) ~= 'table' or not ( args[1] and args[2] ) then
return
end
-- prefix ajoute un préfixe en fonction de la présence ou non du jour si le paramètre "préfixe sans jour" est défini
local function prefix( dateString )
if dateString then
local datetime = dateString:match( 'datetime="([U%d%-]+)"' )
if datetime and datetime:match('%-%d%d%-%d%d') and trim( args['préfixe'] ) then
return args['préfixe'] .. ' ' .. dateString
end
if trim( args['préfixe sans jour'] ) then
return args['préfixe sans jour'] .. ' ' .. dateString
end
end
return dateString
end
local naissance = args[1]:match( '^n' ) == 'n'
local mort = args[1]:match( '^m' ) or args[1]:match( 'décès' )
local evenement = args[1]:match( '^é' )
local affichageDate, qualificatif = args[2], args[4]
local affichageDateTab, resultatDate, complementDate, prefixeDate, approxDate
local dateNaissance, dateMort, approxNaissance, approxMort
if mort or evenement then
affichageDate = args[3]
end
if not trim( affichageDate ) then
return
end
if affichageDate:match( ']]</time>' ) or 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 or evenement ) and ( affichageDate:match( 'wikidata%-linkback' )) then
local _
dateNaissance, _, _, approxNaissance = analyseDate( args[2] )
dateMort, _, _, approxMort = analyseDate( args[3] )
resultatDate = affichageDate
else
return prefix( affichageDate )
end
else
affichageDateTab, complementDate, prefixeDate, approxDate = analyseDate( affichageDate )
if type( affichageDateTab ) ~= 'table' then
return affichageDateTab
else
if naissance then
local _
dateNaissance, approxNaissance = affichageDateTab, approxDate
dateMort, _, _, approxMort = analyseDate( args[3] )
elseif mort then
local _
dateNaissance, _, _, approxNaissance = analyseDate( args[2] )
dateMort, approxMort = affichageDateTab, approxDate
else
qualificatif = args[3]
end
affichageDateTab.naissance = not approxNaissance and naissance
affichageDateTab.mort = not approxMort and mort
affichageDateTab.evenement = evenement
affichageDateTab.qualificatif = args.qualificatif or qualificatif
affichageDateTab.liens = true -- Dans les infobox, liens activés par défaut
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 approxNaissance 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 or evenement ) and
dateNaissance and
dateMort and
not approxNaissance and
not approxMort 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 .. '\194\160ans' .. suffixAge
elseif calculAge == 1 then
age = prefixAge .. 'un\194\160an' .. suffixAge
elseif calculAge == 0 then
age = prefixAge .. 'moins d’un\194\160an' .. suffixAge
end
if complementDate and complementDate:match( 'ans?%)' ) then
complementDate = ''
end
end
return ( prefixeDate or '' ) .. prefix( resultatDate ) .. ( complementDate or '' ) .. age
end
function fun.dureeInfobox( frame )
local args = frame.args
if type( args ) ~= 'table' or not args[1] then
return
end
-- vérifie si une chaîne semble contenir une durée
local function contientDuree( chaine )
return chaine and (
mw.ustring.match( chaine, '%f[%w]ans?%f[^%w]' ) or
mw.ustring.match( chaine, '%f[%w]mois%f[^%w]' ) or
mw.ustring.match( chaine, '%f[%w]jours?%f[^%w]' )
)
end
local jour1, mois1, annee1, jour2, mois2, annee2 = '', '', '', '', '', ''
local t1, fin1, _, approx1 = analyseDate( args[1] )
if approx1 or type( t1 ) ~= 'table' then
return
end
jour1 = t1.jour or ''
mois1 = t1.numMois or ''
annee1 = t1.annee or ''
if args[2] and args[2] ~= "" then
local t2, fin2, _, approx2 = analyseDate( args[2] )
if approx2 or type( t2 ) ~= 'table' then
return
end
if contientDuree( fin2 ) then
-- La durée semble déjà renseignée manuellement
return
end
jour2 = t2.jour or ''
mois2 = t2.numMois or ''
annee2 = t2.annee or ''
if annee1 == '' or annee2 == '' then
-- Mieux vaut ne pas extrapoler l'année
return
end
if ( jour1 ~= '' and jour2 == '' ) or
( mois1 ~= '' and mois2 == '' ) then
-- Si la deuxième date est moins précise que la première, mieux vaut ne rien afficher
return
end
elseif annee1 == '' or contientDuree( fin1 ) then
-- L'année n'est pas spécifiée ou la durée semble déjà renseignée
return
end
local duree = (require 'Module:Durée')._duree({ jour1, mois1, annee1, jour2, mois2, annee2, noerror = true })
if duree then
return '<br /><small>(' .. duree .. ')</small>'
end
end
---
-- la fonction dateISO renvoie un date au format aaaa-mm-jj (sans liens)
-- l'année peut être sous la forme 2013 ou [[2013 en litérature|2013]]
-- le mois peut être en lettres 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 <= listeMois[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]) .. "\194\160" .. 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'âge en fonction de la ou les dates fournies. La valeur retournée est de type 'number'
-- Paramètres :
-- 1, 2, 3 : année, mois jour de naissance (supposé dans le calendrier grégorien)
-- 4, 5, 6 : année, mois, jour 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
an = tonumber( an )
mn = tonumber( mn )
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
-- si l'intervalle traverse l'année zéro, il faut soustraire une année
-- parce que cette année n'existe pas dans les calendriers chrétiens
if an < 0 and ac > 0 then
age = age - 1
end
if mc == mn then
if jc == nil or jn == nil then
return
end
return age - ( jc < jn and 1 or 0 )
else
return age - ( mc < mn and 1 or 0 )
end
end
function fun.modeleAge( frame )
local args = Outils.extractArgs( frame )
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 '<span class="error">Paramètres incorrects ou insuffisants pour calculer l\'âge précis</span>'
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'algorithme de la page https://en.wikipedia.org/wiki/Julian_day#Julian_or_Gregorian_calendar_from_Julian_day_number
function fun.julianDayToJulian( julianDay )
local y = 4716
local v = 3
local j = 1401
local u = 5
local m = 2
local s = 153
local n = 12
local w = 2
local r = 4
local B = 274277
local p = 1461
local C = -38
local f = julianDay + j
local e = r * f + v
local g = math.modf( math.fmod( e, p ) / r )
local h = u * g + w
local D = math.modf( math.fmod( h, s ) / u ) + 1
local M = math.fmod( math.modf( h / s ) + m, n ) + 1
local Y = math.modf( e / p ) - y + math.modf( ( n + m - M ) / n )
return Y, M, D
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
--[[
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 correspondants
--]]
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