« Module:Date complexe » : différence entre les versions
Apparence
Modèle:Infobox>Zolo m Zolo a déplacé la page Module:Daterange vers Module:Date complexe sans laisser de redirection |
m 147 versions importées |
||
| (146 versions intermédiaires par 13 utilisateurs non affichées) | |||
| Ligne 1 : | Ligne 1 : | ||
local datemodule = require | -- luacheck: globals mw, no max line length | ||
local linguistic = require | |||
-- TODO: améliorer les synergies avec Module:Date (gestion par module:Date de dates sans lien et de "XIe siècle en astronautique" | |||
local datemodule = require 'Module:Date' | |||
local linguistic -- = require 'Module:Linguistique' -- chargé uniquement si nécessaire | |||
local roman -- = require 'Module:Romain' -- chargé uniquement si nécessaire | |||
local p = {} | local p = {} | ||
| Ligne 13 : | Ligne 18 : | ||
day = 11, | day = 11, | ||
hour = 12, | hour = 12, | ||
minute = | minute = 13, | ||
second = 14, | second = 14, | ||
} | } | ||
local suffixeAvJC = ' <abbr class="abbr nowrap" title="avant Jésus-Christ">av. J.-C.</abbr>' | |||
local function vowelfirst(str) | local function vowelfirst(str) | ||
linguistic = linguistic or require 'Module:Linguistique' | |||
return linguistic.vowelfirst(str) | return linguistic.vowelfirst(str) | ||
end | end | ||
function p.dateObject(orig, params) | |||
--[[ transforme un snak en un nouvel objet utilisable par des fonctions comme p.setprecision | |||
{type = 'dateobject', timestamp = str, era = '+' ou '-', year = number, month = number, day = number, calendar = calendar} | |||
]]-- | |||
if not params then | |||
params = {} | |||
end | |||
local newobj = p.splitDate(orig.time, orig.calendarmodel) | |||
newobj.precision = params.precision or orig.precision | |||
newobj.type = 'dateobject' | |||
return newobj | |||
end | end | ||
function p.rangeObject(begin, ending, params) | |||
--[[ | |||
objet comportant un timestamp pour le classement chronologique et deux dateobject (begin et ending) | |||
]]-- | |||
local timestamp | |||
if begin then | |||
timestamp = begin.timestamp | |||
else | |||
timestamp = ending.timestamp | |||
end | |||
return {begin = begin, ending = ending, timestamp = timestamp, type = 'rangeobject'} | |||
end | end | ||
function p.simplestring(dateobject) -- transforme un object date ponctuel en texte | function p.objectToText(obj, params) | ||
if obj.type == 'dateobject' then | |||
if params and params.withpreposition then | |||
return p.atdate(obj, params) | |||
else | |||
return p.simplestring(obj, params) | |||
end | |||
elseif obj.type == 'rangeobject' then | |||
return p.daterange(obj.begin, obj.ending, params) | |||
end | |||
end | |||
local function setprecision(obj, maxprecision) | |||
local precision | |||
if type(obj) == "string" then | |||
precision = tonumber(obj) | |||
elseif type(obj) == "number" then | |||
precision = obj | |||
elseif type(obj) == "table" then | |||
precision = tonumber(obj.precision) or numericprecision[obj.precision] | |||
end | |||
if not precision then | |||
precision = 0 | |||
end | |||
-- maxprecision, surtout pour données Wikidata quand on veut afficher avec moins de précision que l'input (par exemple afficher seulement l'année) | |||
if maxprecision then | |||
maxprecision = tonumber(maxprecision) or numericprecision[maxprecision] | |||
end | |||
if maxprecision then | |||
return math.min(precision, maxprecision) | |||
end | |||
return precision | |||
end | |||
local function bigDate(year, precision) -- TODO : gestion de la précision | |||
local val, unit = 0, "" | |||
if year > 999999999 then | |||
unit = " [[giga|G]][[Année julienne|a]]" | |||
val = year / 1000000000 | |||
elseif year > 999999 then | |||
unit = " [[méga|M]][[Année julienne|a]]" | |||
val = year / 1000000 | |||
end | |||
val = mw.getContentLanguage():formatNum(val) | |||
return val .. unit | |||
end | |||
local function milleniumString(millenium, era, hideera) | |||
roman = roman or require 'Module:Romain' | |||
local str = roman.toRoman(millenium) .. '<sup>e</sup> millénaire' | |||
if era == '-' and (not hideera) then | |||
str = str .. suffixeAvJC | |||
end | |||
return str | |||
end | |||
local function centuryString(century, era, hideera) | |||
roman = roman or require 'Module:Romain' | |||
local str = roman.toRoman(century) .. '<sup>e</sup> siècle' | |||
if era == '-' and (not hideera) then | |||
str = str .. suffixeAvJC | |||
end | |||
return str | |||
end | |||
local function decadeString(decade, era, hideera, withlink) | |||
local target | |||
local str = 'années ' .. decade | |||
if decade ~= '0' then str = str .. '0' end | |||
if era == '-' and (not hideera) then | |||
if withlink then target = str .. ' av. J.-C.' end | |||
str = str .. suffixeAvJC | |||
end | |||
if withlink then | |||
if target then str = target .. '|' .. str end | |||
str = '[[' .. str .. ']]' | |||
end | |||
return str | |||
end | |||
function p.simplestring(dateobject, displayformat) | |||
-- transforme un object date ponctuel en texte | |||
-- les dates de type ISO devraient passer par Module:Date, mais il faut pouvoir désactiver les liens | |||
if type(dateobject) == 'string' or type(dateobject) == 'nil' then | |||
return dateobject | |||
end | |||
-- si le date object comporte déjà le texte souhaité on le retourne | |||
if dateobject.string then | |||
return dateobject.string | |||
end | |||
if (not dateobject.year) and (not dateobject.month) and dateobject.day then -- si seul le jour est passé, par exemple à cause de removeclutter, le format n'est pas pris en charge par module:Date | |||
if displayformat.precision and numericprecision[displayformat.precision] < 11 then | |||
return '' | |||
else | |||
return tostring(dateobject.day) | |||
end | |||
end | |||
local era = dateobject.era | |||
if not displayformat then | |||
displayformat = {} | |||
end | |||
local linktopic = displayformat.linktopic or displayformat.link | |||
local nolinks | |||
if linktopic == '-' then | |||
nolinks = true | |||
end | |||
local str | local str | ||
local | local precision = setprecision(dateobject, displayformat.precision) | ||
local | local year = tonumber(dateobject.year) | ||
local | |||
-- formats gérés par ce module | |||
if year then | |||
if year > 999999 then -- grosses dates pour l'astronomie, la paléontologie | |||
return bigDate(year, precision) | |||
end | |||
local hideera = displayformat.hideera | |||
if precision == 6 then | |||
local millenium = math.floor((year - 1)/1000) + 1 | |||
str = milleniumString(millenium, era, hideera) | |||
elseif precision == 7 then | |||
if | local century = math.floor((year - 1)/100) + 1 | ||
if year == 0 then century = 1 end | |||
str = centuryString(century, era, hideera) | |||
elseif precision == 8 then | |||
local decade = tostring(math.floor(year/10)) | |||
str = decadeString(decade, era, hideera, not nolinks) | |||
end | |||
if str then | |||
return str | |||
end | |||
end | |||
-- formats gérés par Module:Date | |||
if year and (era == '-') then | |||
year = 0 - year | |||
end | |||
local month, day | |||
if precision > 9 then | |||
month = dateobject.month | |||
if precision > 10 then | |||
day = dateobject.day | |||
end | end | ||
end | end | ||
if | |||
local argAvJC -- équivalent de hideera pour modeleDate | |||
if displayformat.hideera then | |||
argAvJC = 'non' | |||
end | end | ||
return str | str = datemodule.modeleDate{jour = day, mois = month, annee = year, qualificatif = linktopic, nolinks = nolinks, avJC = argAvJC, liens = true} | ||
return str or '' | |||
end | end | ||
local function | local function fromToNow(datestr, precision) -- retourne "depuis" plutôt que "à partir de" quand ce n'est pas terminé | ||
if (precision >= 11) or (precision == 7) or (precision == 6) then -- on dit "depuis le" pour les dates avec jour, les siècles, les millénaires | |||
if vowelfirst(datestr) then -- suppose l'absence de lien interne | |||
return "depuis l'" .. datestr | |||
if vowelfirst( | |||
return " | |||
else | else | ||
return | return "depuis le " .. datestr | ||
end | end | ||
end | end | ||
if (precision == 8) then -- on dit "depuis les" pour les décennies ("années ...") | |||
return "depuis les " .. datestr | |||
end | |||
return "depuis " .. datestr | |||
end | |||
local function fromdate(d, displayformat) -- retourne "à partir de date" en langage naturel | |||
displayformat = displayformat or {} | |||
local precision = setprecision(d, displayformat.precision) | |||
local datestr = p.simplestring(d, displayformat) | |||
if displayformat and displayformat.textformat == 'minimum' then | |||
return datestr -- par exemple pour les classements MH, juste afficher la date de début | |||
end | |||
if displayformat and displayformat.textformat == 'short' then | |||
return datestr .. ' – ' -- pour certaines infobox (footballeur par exemple), afficher date de début et un tiret | |||
end | |||
if p.before(os.date("!%Y-%m-%dT%TZ"), d) and (displayformat.stilltrue ~= "?") and (displayformat.stilltrue ~= false) then | |||
return fromToNow(datestr, precision) | |||
end | |||
if (precision >= 11) or (precision == 7) or (precision == 6) then -- on dit "à partir du" pour les dates avec jour, les siècles, les millénaires | |||
return 'à partir du ' .. datestr | |||
end | |||
if (precision == 10) and (vowelfirst(datemodule.determinationMois(d.month))) then | |||
return "à partir d'" .. datestr | |||
end | |||
if (precision == 8) then -- on dit "à partir des" pour les décennies | |||
return 'à partir des ' .. datestr | |||
end | |||
return 'à partir de ' .. datestr | |||
end | end | ||
function | local function upto(d, displayformat) -- retourne "jusqu'à date' en langage naturel | ||
local datestring = p.simplestring(d) | displayformat = displayformat or {} | ||
local precision = d.precision | local datestring = p.simplestring(d, displayformat) | ||
if (precision >= 11) then | local precision = setprecision(d, displayformat.precision) | ||
return | if displayformat and displayformat.textformat == 'short' then | ||
elseif (precision | return' – ' .. datestring -- pour certaines infobox (footballeur par exemple), afficher date de début et un tiret | ||
end | |||
if (precision >= 11) then --dates avec jour | |||
return "jusqu'au " .. datestring | |||
elseif (precision == 10) then --mois | |||
return "jusqu'à " .. datestring | return "jusqu'à " .. datestring | ||
else | elseif (precision == 9) then --années | ||
return "jusqu | return "jusqu'en " .. datestring | ||
elseif (precision == 8) then --décennies | |||
return "jusqu'aux " .. datestring | |||
elseif (precision >= 6) then --siècles et millénaires | |||
return "jusqu'au " .. datestring | |||
else --million d'années ? | |||
return "jusqu'au " .. datestring | |||
end | |||
end | |||
function p.atdate(d, displayformat) -- retourne "à la date' en langage naturel | |||
displayformat = displayformat or {} | |||
local datestring = p.simplestring(d, displayformat) | |||
local precision = setprecision(d, displayformat.precision) | |||
if (precision >= 11) then --dates avec jour | |||
return "le " .. datestring | |||
elseif (precision >= 9) then --années et mois | |||
return "en " .. datestring | |||
elseif (precision == 8) then --décennies | |||
return "dans les " .. datestring | |||
elseif (precision >= 6) then --siècles et millénaires | |||
return "au " .. datestring | |||
else --million d'années ? | |||
return "dans le " .. datestring | |||
end | end | ||
end | end | ||
local function | local function fromuntillong(startstr, endstr, era, startprecision, endprecision) | ||
-- on dit "du 3 au 14 janvier" mais "de septembre à octobre" | |||
local longstartstr | |||
if startprecision >= 11 then -- >= day | |||
longstartstr = "du " .. startstr | |||
elseif startprecision == 8 then -- == décennie ("années") | |||
-- on dit "du 3 au 14 janvier" mais "de | longstartstr = "des " .. startstr | ||
if | |||
else | else | ||
if vowelfirst(startstr) then | if vowelfirst(startstr) then | ||
longstartstr = "d'" .. startstr | |||
else | |||
longstartstr = "de " .. startstr | |||
end | |||
end | |||
local longendstr | |||
if endprecision >= 11 then -- >= day | |||
longendstr = " au " .. endstr .. era | |||
elseif endprecision == 8 then -- == décennie ("années") | |||
longendstr = " aux " .. endstr .. era | |||
else | |||
longendstr = " à " .. endstr .. era | |||
end | |||
return longstartstr .. longendstr | |||
end | |||
local function removeclutter(startpoint, endpoint, precision, displayformat) -- prépare à rendre la date plus jolie : "juin 445 av-JC-juillet 445 av-JC -> juin-juillet 445-av-JC" | |||
if (type(startpoint) ~= 'table') or (type(endpoint) ~= 'table') then | |||
return startpoint, endpoint, precision, displayformat | |||
end | |||
local era = endpoint.era | |||
local sameera = false | |||
if startpoint.era == endpoint.era then | |||
sameera = true | |||
end | |||
if sameera and (endpoint.year == startpoint.year) then | |||
startpoint.year = nil | |||
if (startpoint.month == endpoint.month) then | |||
startpoint.month = nil | |||
if (startpoint.day == endpoint.day) then | |||
startpoint.day = nil | |||
end | |||
end | |||
end | |||
return startpoint, endpoint, era, displayformat, sameera | |||
end | |||
function p.between(startpoint, endpoint, displayformat) | |||
displayformat = displayformat or {} | |||
local precision = setprecision(endpoint, displayformat.precision) or 9 | |||
startpoint = p.simplestring(startpoint, displayformat) | |||
endpoint = p.simplestring(endpoint, displayformat) | |||
if not (startpoint or endpoint) then | |||
return nil | |||
end | |||
if not endpoint then | |||
if precision <= 10 then | |||
return "après " .. startpoint | |||
else | |||
return "après le " .. startpoint | |||
end | |||
end | |||
if not startpoint then | |||
if precision <= 10 then | |||
return "avant " .. endpoint | |||
else | else | ||
return " | return "avant le " .. endpoint | ||
end | end | ||
end | |||
-- analyse les paramètres pour éviter les redondances | |||
local era, sameera | |||
startpoint, endpoint, era, displayformat, sameera = removeclutter(startpoint, endpoint, precision, displayformat) | |||
local startstr, endstr = p.simplestring(startpoint, displayformat), p.simplestring(endpoint, displayformat) | |||
displayformat.hideera = true | |||
if (startstr == '') or (startstr == endstr) then | |||
if (not sameera) then | |||
displayformat.hideera = false -- sinon c'est incompréhensible | |||
return p.simplestring(endpoint, displayformat) | |||
end | |||
return endstr | |||
end | |||
-- pour éviter les tournures répétitives comme "du 13 septembre 2006 au 18 septembre 2006" | |||
if era == "-" then | |||
era = suffixeAvJC | |||
else | |||
era = "" | |||
end | |||
if precision <= 10 then | |||
return "entre " .. startstr .. " et " .. endstr .. era | |||
else | |||
return "entre le " .. startstr .. " et le " .. endstr .. era | |||
end | end | ||
end | end | ||
function p. | local function fromuntil(startpoint, endpoint, displayformat) | ||
local | displayformat = displayformat or {} | ||
return " | local startprecision = setprecision(startpoint, displayformat.precision) | ||
local endprecision = setprecision(endpoint, displayformat.precision) | |||
-- analyse les paramètres pour éviter les redondances | |||
local era, sameera | |||
startpoint, endpoint, era, displayformat, sameera = removeclutter(startpoint, endpoint, endprecision, displayformat) | |||
local hideera = displayformat.hideera | |||
displayformat.hideera = true -- pour les chaînes intermédiaires | |||
local startstr, endstr = p.simplestring(startpoint, displayformat), p.simplestring(endpoint, displayformat) | |||
if (startstr == '') or (startstr == endstr) then | |||
displayformat.hideera = hideera -- on va faire une chaîne simple, on reprend donc le format initialement demandé | |||
if (not sameera) then | |||
displayformat.hideera = false -- sinon c'est incompréhensible | |||
end | |||
return p.simplestring(endpoint, displayformat) | |||
end | |||
-- pour éviter les tournures répétitives comme "du 13 septembre 2006 au 18 septembre 2006" | |||
local hasStartera = false | |||
if era == '-' then | |||
era = suffixeAvJC | |||
else | |||
era = '' | |||
if not (sameera == nil) and not sameera then | |||
startstr = startstr .. suffixeAvJC | |||
hasStartera = true | |||
end | |||
end | |||
if displayformat.textformat == 'long' then | |||
return fromuntillong(startstr, endstr, era, startprecision, endprecision) | |||
elseif (type(startprecision) == "number") and (startprecision > 9) or (type(endprecision) == "number") and (endprecision > 9) or hasStartera then -- si les date contiennent des mois ou jours, ou si il y a un era avant, il vaut mieux un espace | |||
return startstr .. ' -<wbr> ' .. endstr .. era | |||
else | |||
return startstr .. '-<wbr>' .. endstr .. era | |||
end | |||
end | end | ||
function p.daterange( | function p.daterange(startpoint, endpoint, displayformat) | ||
if | local result | ||
if startpoint and endpoint then | |||
elseif | result = fromuntil(startpoint, endpoint, displayformat) | ||
elseif startpoint then | |||
elseif | result = fromdate(startpoint, displayformat) | ||
elseif endpoint then | |||
result = upto(endpoint, displayformat) | |||
else | else | ||
result = nil | |||
end | |||
if result and displayformat and displayformat.ucfirst and displayformat.ucfirst ~= '-' then | |||
linguistic = linguistic or require 'Module:Linguistique' | |||
result = linguistic.ucfirst(result) | |||
end | |||
return result | |||
end | |||
function p.duration(start, ending) | |||
if (not start) or (not ending) then | |||
return nil -- ? | |||
end | |||
return datemodule.age(start.year, start.month, start.day, ending.year, ending.month, ending.day) | |||
end | |||
local function splitWDdate(str) -- depuis datavalue.value.time de Wikidata, fonctionnerait aussi en utilisant simplement splitISO | |||
local pattern = "(%W)(%d+)%-(%d+)%-(%d+)" | |||
local era, year, month, day = str:match(pattern) | |||
return era, year, month, day | |||
end | |||
local function splitISO(str) | |||
str = mw.text.trim(str) | |||
local era, year, month, day | |||
era = string.sub(str, 1, 1) | |||
if tonumber(era) then | |||
era = '+' | |||
end | |||
local f = string.gmatch(str, '%d+') | |||
year, month, day = f(), f(), f() | |||
return era, year, month, day | |||
end | |||
function p.splitDate(orig, calendar) | |||
if not orig then | |||
return nil | return nil | ||
end | end | ||
if type(orig) == 'table' then | |||
return orig | |||
end | |||
if type(orig) ~= 'string' then | |||
return error("bad datatype for date, string expected, got " .. type(orig)) | |||
end | |||
local era, y, m, d = splitWDdate(orig) | |||
if not era then | |||
era, y, m, d = splitISO(orig) | |||
end | |||
y, m, d = tonumber(y or 1), tonumber(m or 1), tonumber(d or 1) | |||
return {day = d, month = m, year = y, era = era, type = 'dateobject', calendar = calendar} | |||
end | |||
function p.before(a, b) -- return true if b is before a or if at least one of a or b is missing | |||
a = p.splitDate(a) | |||
b = p.splitDate(b) | |||
if (not a) or (not b) then | |||
return true | |||
end | |||
local order = {'year', 'month', 'day'} | |||
if a['era'] == '+' then | |||
if b['era'] == '+' then | |||
for i, j in ipairs(order) do | |||
if b[j] < a[j] then | |||
return true | |||
elseif b[j] > a[j] then | |||
return false | |||
end | |||
end | |||
else -- b - | |||
return true | |||
end | |||
else -- a - | |||
if b['era'] == '+' then | |||
return false | |||
else -- b - | |||
for i, j in ipairs(order) do | |||
if b[j] > a[j] then | |||
return true | |||
elseif b[j] < a[j] then | |||
return false | |||
end | |||
end | |||
end | |||
end | |||
return true | |||
end | |||
function p.equal(a, b, precision) | |||
a = p.splitDate(a) | |||
b = p.splitDate(b) | |||
if type(precision) == "string" then | |||
precision = tonumber(precision) or numericprecision[mw.text.trim(precision)] | |||
end | |||
if not precision then | |||
precision = 11 -- day by default ? | |||
end | |||
if (not a) or (not b) then | |||
return true | |||
end | |||
if a.era and b.era and (b.era ~= a.era) then | |||
return false | |||
end | |||
if (precision >= 11) then | |||
if a.day and b.day and (b.day ~= a.day) then | |||
return false | |||
end | |||
end | |||
if (precision >= 10) then | |||
if a.month and b.month and (b.month ~= a.month) then | |||
return false | |||
end | |||
end | |||
if (precision >= 9) then | |||
if a.year and b.year and (b.year ~= a.year) then | |||
return false | |||
end | |||
end | |||
return true | |||
end | end | ||
return p | return p | ||
Dernière version du 22 février 2026 à 00:16
La documentation pour ce module peut être créée à Module:Date complexe/doc
-- luacheck: globals mw, no max line length
-- TODO: améliorer les synergies avec Module:Date (gestion par module:Date de dates sans lien et de "XIe siècle en astronautique"
local datemodule = require 'Module:Date'
local linguistic -- = require 'Module:Linguistique' -- chargé uniquement si nécessaire
local roman -- = require 'Module:Romain' -- chargé uniquement si nécessaire
local p = {}
local numericprecision = { -- convertir les précisions en valeurs numériques = à celles utilisées par Wikidata
gigayear = 0,
megayear = 3,
millenium = 6,
century = 7,
decade = 8,
year = 9,
month = 10,
day = 11,
hour = 12,
minute = 13,
second = 14,
}
local suffixeAvJC = ' <abbr class="abbr nowrap" title="avant Jésus-Christ">av. J.-C.</abbr>'
local function vowelfirst(str)
linguistic = linguistic or require 'Module:Linguistique'
return linguistic.vowelfirst(str)
end
function p.dateObject(orig, params)
--[[ transforme un snak en un nouvel objet utilisable par des fonctions comme p.setprecision
{type = 'dateobject', timestamp = str, era = '+' ou '-', year = number, month = number, day = number, calendar = calendar}
]]--
if not params then
params = {}
end
local newobj = p.splitDate(orig.time, orig.calendarmodel)
newobj.precision = params.precision or orig.precision
newobj.type = 'dateobject'
return newobj
end
function p.rangeObject(begin, ending, params)
--[[
objet comportant un timestamp pour le classement chronologique et deux dateobject (begin et ending)
]]--
local timestamp
if begin then
timestamp = begin.timestamp
else
timestamp = ending.timestamp
end
return {begin = begin, ending = ending, timestamp = timestamp, type = 'rangeobject'}
end
function p.objectToText(obj, params)
if obj.type == 'dateobject' then
if params and params.withpreposition then
return p.atdate(obj, params)
else
return p.simplestring(obj, params)
end
elseif obj.type == 'rangeobject' then
return p.daterange(obj.begin, obj.ending, params)
end
end
local function setprecision(obj, maxprecision)
local precision
if type(obj) == "string" then
precision = tonumber(obj)
elseif type(obj) == "number" then
precision = obj
elseif type(obj) == "table" then
precision = tonumber(obj.precision) or numericprecision[obj.precision]
end
if not precision then
precision = 0
end
-- maxprecision, surtout pour données Wikidata quand on veut afficher avec moins de précision que l'input (par exemple afficher seulement l'année)
if maxprecision then
maxprecision = tonumber(maxprecision) or numericprecision[maxprecision]
end
if maxprecision then
return math.min(precision, maxprecision)
end
return precision
end
local function bigDate(year, precision) -- TODO : gestion de la précision
local val, unit = 0, ""
if year > 999999999 then
unit = " [[giga|G]][[Année julienne|a]]"
val = year / 1000000000
elseif year > 999999 then
unit = " [[méga|M]][[Année julienne|a]]"
val = year / 1000000
end
val = mw.getContentLanguage():formatNum(val)
return val .. unit
end
local function milleniumString(millenium, era, hideera)
roman = roman or require 'Module:Romain'
local str = roman.toRoman(millenium) .. '<sup>e</sup> millénaire'
if era == '-' and (not hideera) then
str = str .. suffixeAvJC
end
return str
end
local function centuryString(century, era, hideera)
roman = roman or require 'Module:Romain'
local str = roman.toRoman(century) .. '<sup>e</sup> siècle'
if era == '-' and (not hideera) then
str = str .. suffixeAvJC
end
return str
end
local function decadeString(decade, era, hideera, withlink)
local target
local str = 'années ' .. decade
if decade ~= '0' then str = str .. '0' end
if era == '-' and (not hideera) then
if withlink then target = str .. ' av. J.-C.' end
str = str .. suffixeAvJC
end
if withlink then
if target then str = target .. '|' .. str end
str = '[[' .. str .. ']]'
end
return str
end
function p.simplestring(dateobject, displayformat)
-- transforme un object date ponctuel en texte
-- les dates de type ISO devraient passer par Module:Date, mais il faut pouvoir désactiver les liens
if type(dateobject) == 'string' or type(dateobject) == 'nil' then
return dateobject
end
-- si le date object comporte déjà le texte souhaité on le retourne
if dateobject.string then
return dateobject.string
end
if (not dateobject.year) and (not dateobject.month) and dateobject.day then -- si seul le jour est passé, par exemple à cause de removeclutter, le format n'est pas pris en charge par module:Date
if displayformat.precision and numericprecision[displayformat.precision] < 11 then
return ''
else
return tostring(dateobject.day)
end
end
local era = dateobject.era
if not displayformat then
displayformat = {}
end
local linktopic = displayformat.linktopic or displayformat.link
local nolinks
if linktopic == '-' then
nolinks = true
end
local str
local precision = setprecision(dateobject, displayformat.precision)
local year = tonumber(dateobject.year)
-- formats gérés par ce module
if year then
if year > 999999 then -- grosses dates pour l'astronomie, la paléontologie
return bigDate(year, precision)
end
local hideera = displayformat.hideera
if precision == 6 then
local millenium = math.floor((year - 1)/1000) + 1
str = milleniumString(millenium, era, hideera)
elseif precision == 7 then
local century = math.floor((year - 1)/100) + 1
if year == 0 then century = 1 end
str = centuryString(century, era, hideera)
elseif precision == 8 then
local decade = tostring(math.floor(year/10))
str = decadeString(decade, era, hideera, not nolinks)
end
if str then
return str
end
end
-- formats gérés par Module:Date
if year and (era == '-') then
year = 0 - year
end
local month, day
if precision > 9 then
month = dateobject.month
if precision > 10 then
day = dateobject.day
end
end
local argAvJC -- équivalent de hideera pour modeleDate
if displayformat.hideera then
argAvJC = 'non'
end
str = datemodule.modeleDate{jour = day, mois = month, annee = year, qualificatif = linktopic, nolinks = nolinks, avJC = argAvJC, liens = true}
return str or ''
end
local function fromToNow(datestr, precision) -- retourne "depuis" plutôt que "à partir de" quand ce n'est pas terminé
if (precision >= 11) or (precision == 7) or (precision == 6) then -- on dit "depuis le" pour les dates avec jour, les siècles, les millénaires
if vowelfirst(datestr) then -- suppose l'absence de lien interne
return "depuis l'" .. datestr
else
return "depuis le " .. datestr
end
end
if (precision == 8) then -- on dit "depuis les" pour les décennies ("années ...")
return "depuis les " .. datestr
end
return "depuis " .. datestr
end
local function fromdate(d, displayformat) -- retourne "à partir de date" en langage naturel
displayformat = displayformat or {}
local precision = setprecision(d, displayformat.precision)
local datestr = p.simplestring(d, displayformat)
if displayformat and displayformat.textformat == 'minimum' then
return datestr -- par exemple pour les classements MH, juste afficher la date de début
end
if displayformat and displayformat.textformat == 'short' then
return datestr .. ' – ' -- pour certaines infobox (footballeur par exemple), afficher date de début et un tiret
end
if p.before(os.date("!%Y-%m-%dT%TZ"), d) and (displayformat.stilltrue ~= "?") and (displayformat.stilltrue ~= false) then
return fromToNow(datestr, precision)
end
if (precision >= 11) or (precision == 7) or (precision == 6) then -- on dit "à partir du" pour les dates avec jour, les siècles, les millénaires
return 'à partir du ' .. datestr
end
if (precision == 10) and (vowelfirst(datemodule.determinationMois(d.month))) then
return "à partir d'" .. datestr
end
if (precision == 8) then -- on dit "à partir des" pour les décennies
return 'à partir des ' .. datestr
end
return 'à partir de ' .. datestr
end
local function upto(d, displayformat) -- retourne "jusqu'à date' en langage naturel
displayformat = displayformat or {}
local datestring = p.simplestring(d, displayformat)
local precision = setprecision(d, displayformat.precision)
if displayformat and displayformat.textformat == 'short' then
return' – ' .. datestring -- pour certaines infobox (footballeur par exemple), afficher date de début et un tiret
end
if (precision >= 11) then --dates avec jour
return "jusqu'au " .. datestring
elseif (precision == 10) then --mois
return "jusqu'à " .. datestring
elseif (precision == 9) then --années
return "jusqu'en " .. datestring
elseif (precision == 8) then --décennies
return "jusqu'aux " .. datestring
elseif (precision >= 6) then --siècles et millénaires
return "jusqu'au " .. datestring
else --million d'années ?
return "jusqu'au " .. datestring
end
end
function p.atdate(d, displayformat) -- retourne "à la date' en langage naturel
displayformat = displayformat or {}
local datestring = p.simplestring(d, displayformat)
local precision = setprecision(d, displayformat.precision)
if (precision >= 11) then --dates avec jour
return "le " .. datestring
elseif (precision >= 9) then --années et mois
return "en " .. datestring
elseif (precision == 8) then --décennies
return "dans les " .. datestring
elseif (precision >= 6) then --siècles et millénaires
return "au " .. datestring
else --million d'années ?
return "dans le " .. datestring
end
end
local function fromuntillong(startstr, endstr, era, startprecision, endprecision)
-- on dit "du 3 au 14 janvier" mais "de septembre à octobre"
local longstartstr
if startprecision >= 11 then -- >= day
longstartstr = "du " .. startstr
elseif startprecision == 8 then -- == décennie ("années")
longstartstr = "des " .. startstr
else
if vowelfirst(startstr) then
longstartstr = "d'" .. startstr
else
longstartstr = "de " .. startstr
end
end
local longendstr
if endprecision >= 11 then -- >= day
longendstr = " au " .. endstr .. era
elseif endprecision == 8 then -- == décennie ("années")
longendstr = " aux " .. endstr .. era
else
longendstr = " à " .. endstr .. era
end
return longstartstr .. longendstr
end
local function removeclutter(startpoint, endpoint, precision, displayformat) -- prépare à rendre la date plus jolie : "juin 445 av-JC-juillet 445 av-JC -> juin-juillet 445-av-JC"
if (type(startpoint) ~= 'table') or (type(endpoint) ~= 'table') then
return startpoint, endpoint, precision, displayformat
end
local era = endpoint.era
local sameera = false
if startpoint.era == endpoint.era then
sameera = true
end
if sameera and (endpoint.year == startpoint.year) then
startpoint.year = nil
if (startpoint.month == endpoint.month) then
startpoint.month = nil
if (startpoint.day == endpoint.day) then
startpoint.day = nil
end
end
end
return startpoint, endpoint, era, displayformat, sameera
end
function p.between(startpoint, endpoint, displayformat)
displayformat = displayformat or {}
local precision = setprecision(endpoint, displayformat.precision) or 9
startpoint = p.simplestring(startpoint, displayformat)
endpoint = p.simplestring(endpoint, displayformat)
if not (startpoint or endpoint) then
return nil
end
if not endpoint then
if precision <= 10 then
return "après " .. startpoint
else
return "après le " .. startpoint
end
end
if not startpoint then
if precision <= 10 then
return "avant " .. endpoint
else
return "avant le " .. endpoint
end
end
-- analyse les paramètres pour éviter les redondances
local era, sameera
startpoint, endpoint, era, displayformat, sameera = removeclutter(startpoint, endpoint, precision, displayformat)
local startstr, endstr = p.simplestring(startpoint, displayformat), p.simplestring(endpoint, displayformat)
displayformat.hideera = true
if (startstr == '') or (startstr == endstr) then
if (not sameera) then
displayformat.hideera = false -- sinon c'est incompréhensible
return p.simplestring(endpoint, displayformat)
end
return endstr
end
-- pour éviter les tournures répétitives comme "du 13 septembre 2006 au 18 septembre 2006"
if era == "-" then
era = suffixeAvJC
else
era = ""
end
if precision <= 10 then
return "entre " .. startstr .. " et " .. endstr .. era
else
return "entre le " .. startstr .. " et le " .. endstr .. era
end
end
local function fromuntil(startpoint, endpoint, displayformat)
displayformat = displayformat or {}
local startprecision = setprecision(startpoint, displayformat.precision)
local endprecision = setprecision(endpoint, displayformat.precision)
-- analyse les paramètres pour éviter les redondances
local era, sameera
startpoint, endpoint, era, displayformat, sameera = removeclutter(startpoint, endpoint, endprecision, displayformat)
local hideera = displayformat.hideera
displayformat.hideera = true -- pour les chaînes intermédiaires
local startstr, endstr = p.simplestring(startpoint, displayformat), p.simplestring(endpoint, displayformat)
if (startstr == '') or (startstr == endstr) then
displayformat.hideera = hideera -- on va faire une chaîne simple, on reprend donc le format initialement demandé
if (not sameera) then
displayformat.hideera = false -- sinon c'est incompréhensible
end
return p.simplestring(endpoint, displayformat)
end
-- pour éviter les tournures répétitives comme "du 13 septembre 2006 au 18 septembre 2006"
local hasStartera = false
if era == '-' then
era = suffixeAvJC
else
era = ''
if not (sameera == nil) and not sameera then
startstr = startstr .. suffixeAvJC
hasStartera = true
end
end
if displayformat.textformat == 'long' then
return fromuntillong(startstr, endstr, era, startprecision, endprecision)
elseif (type(startprecision) == "number") and (startprecision > 9) or (type(endprecision) == "number") and (endprecision > 9) or hasStartera then -- si les date contiennent des mois ou jours, ou si il y a un era avant, il vaut mieux un espace
return startstr .. ' -<wbr> ' .. endstr .. era
else
return startstr .. '-<wbr>' .. endstr .. era
end
end
function p.daterange(startpoint, endpoint, displayformat)
local result
if startpoint and endpoint then
result = fromuntil(startpoint, endpoint, displayformat)
elseif startpoint then
result = fromdate(startpoint, displayformat)
elseif endpoint then
result = upto(endpoint, displayformat)
else
result = nil
end
if result and displayformat and displayformat.ucfirst and displayformat.ucfirst ~= '-' then
linguistic = linguistic or require 'Module:Linguistique'
result = linguistic.ucfirst(result)
end
return result
end
function p.duration(start, ending)
if (not start) or (not ending) then
return nil -- ?
end
return datemodule.age(start.year, start.month, start.day, ending.year, ending.month, ending.day)
end
local function splitWDdate(str) -- depuis datavalue.value.time de Wikidata, fonctionnerait aussi en utilisant simplement splitISO
local pattern = "(%W)(%d+)%-(%d+)%-(%d+)"
local era, year, month, day = str:match(pattern)
return era, year, month, day
end
local function splitISO(str)
str = mw.text.trim(str)
local era, year, month, day
era = string.sub(str, 1, 1)
if tonumber(era) then
era = '+'
end
local f = string.gmatch(str, '%d+')
year, month, day = f(), f(), f()
return era, year, month, day
end
function p.splitDate(orig, calendar)
if not orig then
return nil
end
if type(orig) == 'table' then
return orig
end
if type(orig) ~= 'string' then
return error("bad datatype for date, string expected, got " .. type(orig))
end
local era, y, m, d = splitWDdate(orig)
if not era then
era, y, m, d = splitISO(orig)
end
y, m, d = tonumber(y or 1), tonumber(m or 1), tonumber(d or 1)
return {day = d, month = m, year = y, era = era, type = 'dateobject', calendar = calendar}
end
function p.before(a, b) -- return true if b is before a or if at least one of a or b is missing
a = p.splitDate(a)
b = p.splitDate(b)
if (not a) or (not b) then
return true
end
local order = {'year', 'month', 'day'}
if a['era'] == '+' then
if b['era'] == '+' then
for i, j in ipairs(order) do
if b[j] < a[j] then
return true
elseif b[j] > a[j] then
return false
end
end
else -- b -
return true
end
else -- a -
if b['era'] == '+' then
return false
else -- b -
for i, j in ipairs(order) do
if b[j] > a[j] then
return true
elseif b[j] < a[j] then
return false
end
end
end
end
return true
end
function p.equal(a, b, precision)
a = p.splitDate(a)
b = p.splitDate(b)
if type(precision) == "string" then
precision = tonumber(precision) or numericprecision[mw.text.trim(precision)]
end
if not precision then
precision = 11 -- day by default ?
end
if (not a) or (not b) then
return true
end
if a.era and b.era and (b.era ~= a.era) then
return false
end
if (precision >= 11) then
if a.day and b.day and (b.day ~= a.day) then
return false
end
end
if (precision >= 10) then
if a.month and b.month and (b.month ~= a.month) then
return false
end
end
if (precision >= 9) then
if a.year and b.year and (b.year ~= a.year) then
return false
end
end
return true
end
return p