Module:Date complexe : Différence entre versions

De Lagny-sur-Marne Wiki
Aller à : navigation, rechercher
(fonction pour "entre machin et truc", "avant truc".. pas propre du tout, mais mieux que de le laisser dans Module:Utilitaire Wikidata)
(between : retouche précision pour ajouter "le")
 
(21 révisions intermédiaires par 3 utilisateurs non affichées)
Ligne 2 : Ligne 2 :
  
 
local datemodule = require 'Module:Date'
 
local datemodule = require 'Module:Date'
local linguistic = require 'Module:Linguistique'
+
local linguistic -- = require 'Module:Linguistique' -- chargé uniquement si nécessaire
local roman = require 'Module:Romain'
+
local roman -- = require 'Module:Romain' -- chargé uniquement si nécessaire
 
local p = {}
 
local p = {}
  
Ligne 16 : Ligne 16 :
 
day = 11,
 
day = 11,
 
hour = 12,
 
hour = 12,
minute = 12,
+
minute = 13,
 
second = 14,
 
second = 14,
 
}
 
}
  
 
local function vowelfirst(str)
 
local function vowelfirst(str)
 +
linguistic = require 'Module:Linguistique'
 
return linguistic.vowelfirst(str)
 
return linguistic.vowelfirst(str)
 
end
 
end
  
 
local function setprecision(obj, maxprecision)
 
local function setprecision(obj, maxprecision)
if (not obj) or (type(obj) == 'string') then
+
local precision
return obj
+
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
 
end
local precision = tonumber(obj.precision) or numericprecision[obj.precision]
+
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
 
if maxprecision then
 
maxprecision = tonumber(maxprecision) or numericprecision[maxprecision]
 
maxprecision = tonumber(maxprecision) or numericprecision[maxprecision]
Ligne 39 : Ligne 48 :
  
 
local function bigDate(year, precision) -- TODO : gestion de la précision
 
local function bigDate(year, precision) -- TODO : gestion de la précision
 +
local format = require "Module:Format"
 
local val, unit = 0, ""
 
local val, unit = 0, ""
 
if year > 999999999 then
 
if year > 999999999 then
Ligne 47 : Ligne 57 :
 
val = year / 1000000
 
val = year / 1000000
 
end
 
end
return tostring(val) .. unit
+
val = format.do_formatnum({val})
 +
return val .. unit
 
end
 
end
  
  
 
local function milleniumString(millenium, era, hideera)
 
local function milleniumString(millenium, era, hideera)
 +
roman =  roman or require 'Module:Romain'
 
local str = roman.toRoman(millenium) .. '<sup>e</sup> millénaire'
 
local str = roman.toRoman(millenium) .. '<sup>e</sup> millénaire'
 
if era == '-' and (not hideera) then
 
if era == '-' and (not hideera) then
Ligne 60 : Ligne 72 :
  
 
local function centuryString(century, era, hideera)
 
local function centuryString(century, era, hideera)
 +
roman =  roman or require 'Module:Romain'
 
local str = roman.toRoman(century) .. '<sup>e</sup> siècle'
 
local str = roman.toRoman(century) .. '<sup>e</sup> siècle'
 
if era == '-' and (not hideera) then
 
if era == '-' and (not hideera) then
 
str = str .. ' av. J.-C.'
 
str = str .. ' av. J.-C.'
 
end
 
end
return '' -- trop d'erreurs sur Wikidata, en attente du UI correcte
+
return str
 
end
 
end
  
Ligne 72 : Ligne 85 :
 
str = str .. ' av. J.-C.'
 
str = str .. ' av. J.-C.'
 
end
 
end
return str
+
return '[[' .. str .. ']]'
 
end
 
end
  
function p.simplestring(dateobject, displayformat)  
+
function p.simplestring(dateobject, displayformat)
 +
 
 
-- transforme un object date ponctuel en texte
 
-- 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
 
-- les dates de type ISO devraient passer par Module:Date, mais il faut pouvoir désactiver les liens
Ligne 81 : Ligne 95 :
 
return dateobject
 
return dateobject
 
end
 
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
 +
return dateobject.day
 +
end
 +
 
local era = dateobject.era
 
local era = dateobject.era
  
Ligne 140 : Ligne 158 :
 
local function fromToNow(d, datestr, precision) -- retourne "depuis" plutôt que "à partir de" quand c'est pas terminé
 
local function fromToNow(d, datestr, precision) -- retourne "depuis" plutôt que "à partir de" quand c'est pas terminé
 
if (precision >= 11) or (precision == 7) or (precision == 6)  then -- ont dit "à partir du pour les dates avec jour, les siècles, les millénaires
 
if (precision >= 11) or (precision == 7) or (precision == 6)  then -- ont dit "à partir du pour les dates avec jour, les siècles, les millénaires
if voweverlfirst(datestr) then -- suppose l'absence de lien interne
+
if vowelfirst(datestr) then -- suppose l'absence de lien interne
 
return "depuis l'" .. datestr
 
return "depuis l'" .. datestr
 
else
 
else
return "depuis le" .. datestr
+
return "depuis le " .. datestr
 
end
 
end
 
end
 
end
Ligne 176 : Ligne 194 :
 
local precision = setprecision(d, displayformat.precision)
 
local precision = setprecision(d, displayformat.precision)
 
if (precision >= 11) or (precision == 7) or (precision == 6) then --on dit "jusqu'au" pour les dates avec jour, et pour les siècles
 
if (precision >= 11) or (precision == 7) or (precision == 6) then --on dit "jusqu'au" pour les dates avec jour, et pour les siècles
return 'jusqu\'au ' .. datestring
+
return "jusqu'au " .. datestring
 
elseif (precision > 9) then
 
elseif (precision > 9) then
 
return "jusqu'à " .. datestring
 
return "jusqu'à " .. datestring
 
else
 
else
return "jusqu\'en " .. datestring
+
return "jusqu'en " .. datestring
 
end
 
end
 
end
 
end
Ligne 220 : Ligne 238 :
 
function p.between(startpoint, endpoint, displayformat)
 
function p.between(startpoint, endpoint, displayformat)
 
displayformat = displayformat or {}
 
displayformat = displayformat or {}
local precision = setprecision(endpoint, displayformat.precision)
+
local precision = setprecision(endpoint, displayformat.precision) or 9
  
if not (starpoint or endpoint) then
+
local startpoint = p.simplestring(startpoint, displayformat)
 +
local endpoint = p.simplestring(endpoint, displayformat)
 +
 +
if not (startpoint or endpoint) then
 
return nil
 
return nil
 
end
 
end
 
if not endpoint then
 
if not endpoint then
 
if precision <= 10 then
 
if precision <= 10 then
return "après " ..  p.simplestring(startpoint, displayformat)
+
return "après " ..  startpoint
 
else
 
else
return "après le " ..  p.simplestring(startpoint, displayformat)
+
return "après le " ..  startpoint
 
end
 
end
 
end
 
end
 
if not startpoint then
 
if not startpoint then
 
if precision <= 10 then
 
if precision <= 10 then
return "avant " ..  p.simplestring(startpoint, displayformat)
+
return "avant " ..  endpoint
 
else
 
else
return "avant le " ..  p.simplestring(startpoint, displayformat)
+
return "avant le " ..  endpoint
 
end
 
end
 
end
 
end
Ligne 261 : Ligne 282 :
 
end
 
end
 
 
if precision <= 9 then
+
if precision <= 10 then
return "entre " .. startstr .. " et " .. endsstr .. " " .. era
+
return "entre " .. startstr .. " et " .. endstr .. " " .. era
 
else
 
else
return "entre le " .. startstr .. " et le " .. endsstr .. " " .. era
+
return "entre le " .. startstr .. " et le " .. endstr .. " " .. era
 
end
 
end
 
end
 
end
Ligne 276 : Ligne 297 :
 
local startpoint, endpoint, era, displayformat, sameera = removeclutter(startpoint, endpoint, precision, displayformat)
 
local startpoint, endpoint, era, displayformat, sameera = removeclutter(startpoint, endpoint, precision, displayformat)
  
displayformat.hideera = true
+
local hideera= displayformat.hideera
 +
displayformat.hideera = true -- pour les chaînes intermédiaires
 
 
 
local startstr, endstr =  p.simplestring(startpoint, displayformat), p.simplestring(endpoint, displayformat)
 
local startstr, endstr =  p.simplestring(startpoint, displayformat), p.simplestring(endpoint, displayformat)
 +
 
if (startstr == '') or (startstr == endstr) then
 
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
 
if (not sameera) then
 
displayformat.hideera = false --sinon c'est incompréhensible
 
displayformat.hideera = false --sinon c'est incompréhensible
return p.simplestring(endpoint, displayformat)
 
 
end
 
end
return endstr
+
return p.simplestring(endpoint, displayformat)
 
end
 
end
 
-- pour éviter les tournures répétitives comme  "du 13 septembre 2006 au 18 september 2006"
 
-- pour éviter les tournures répétitives comme  "du 13 septembre 2006 au 18 september 2006"
Ligne 294 : Ligne 317 :
 
if displayformat.textformat == 'long' then
 
if displayformat.textformat == 'long' then
 
return fromuntillong(startstr, endstr, era, precision)
 
return fromuntillong(startstr, endstr, era, precision)
 +
elseif (type(precision) == "number") and (precision > 9) then -- si les date contiennent des mois ou jours, il vaut mieux un espace
 +
return startstr .. ' -<wbr> ' .. endstr .. era
 
else
 
else
 
return startstr .. '-<wbr>' .. endstr .. era
 
return startstr .. '-<wbr>' .. endstr .. era
Ligne 300 : Ligne 325 :
  
  
function p.fuzzydate(dateobjet, displayformat)
+
function p.fuzzydate(dateobject, displayformat)
 
local str = p.simplestring(dateobject, displayformat)
 
local str = p.simplestring(dateobject, displayformat)
 +
if not str then
 +
return nil
 +
end
 
return "vers " .. str
 
return "vers " .. str
 
end
 
end
Ligne 357 : Ligne 385 :
  
 
y, m, d = tonumber(y or 1), tonumber(m or 1), tonumber(d or 1)
 
y, m, d = tonumber(y or 1), tonumber(m or 1), tonumber(d or 1)
return {day = d, month = m, year = y, era = era, timestamp = timestamp, type = 'dateobject', calendar = calendar}
+
return {day = d, month = m, year = y, era = era, type = 'dateobject', calendar = calendar}
 
end
 
end
  

Version actuelle datée du 7 octobre 2016 à 17:44

La documentation pour ce module peut être créée à Module:Date complexe/doc

-- 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 function vowelfirst(str)
	linguistic = require 'Module:Linguistique'
	return linguistic.vowelfirst(str)
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 format = require "Module:Format"
	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 = format.do_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 .. ' av. J.-C.'
	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 .. ' av. J.-C.'
	end
	return str
end

local function decadeString(decade, era, hideera)
	local str = 'années ' .. decade .. '0'
	if era == '-' and (not hideera) then
		str = str .. ' av. J.-C.'
	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
	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
		return dateobject.day
	end

	local era = dateobject.era

	if not displayformat then
		displayformat = {}
	end
	local linktopic = displayformat.linktopic
	local nolinks
	if linktopic == '-' then
		nolinks = true
	end

	local str
	local precision = setprecision(dateobject, displayformat.precision)
	
	-- formats gérés par ce module
	local year = tonumber( dateobject.year) or 0
	
	if year > 999999 then -- grosses dates pour l'astronomie, la paléontologie
		return bigDate(year, precision)
	end
	
	if precision == 6 then
		local millenium = math.floor(year/1000) + 1
		str = milleniumString(millenium, era, hideera)
	elseif precision == 7 then
		local century = math.floor(year/100) + 1
		str = centuryString(century, era, hideera)
	elseif precision == 8 then
		local decade = tostring(math.floor(year/10))
		str = decadeString(decade, era, hideera)
	end
	if str then
		return str
	end
	
	-- formats gérés par Module:Date
	local year = dateobject.year
	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 avJC -- équivalent de hideera pour modeleDate
	if displayformat.hideera then
		avJC = 'non'
	end
	str = datemodule.modeleDate{jour = day, mois = month, annee = year, qualificatif = linktopic, nolinks = nolinks, avJC = avJC}
	return str or ''
end

local function fromToNow(d, datestr, precision) -- retourne "depuis" plutôt que "à partir de" quand c'est pas terminé
	if (precision >= 11) or (precision == 7) or (precision == 6)  then -- ont dit "à partir du 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
	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 == 'infobox' then
		return datestr .. '-' -- pour certaines infobox (footballeur par exemple), afficher date de début et un tiret
	end
	if displayformat.stilltrue then return
		fromToNow(d, datestr, precision)
	end
	if (precision >= 11) or (precision == 7) or (precision == 6)  then -- ont 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.nomDuMois(d.month))) then
		return "à partir d'" .. 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 (precision >= 11) or (precision == 7) or (precision == 6) then --on dit "jusqu'au" pour les dates avec jour, et pour les siècles
		return "jusqu'au " .. datestring
	elseif (precision > 9) then
		return "jusqu'à " .. datestring
	else
		return "jusqu'en " .. datestring
	end
end

local function fromuntillong(startstr, endstr, era, precision)
	-- on dit "du 3 au 14 janvier" mais "de septembe à octobre
	if precision >= 11 then -- >= day
		return "du " .. startstr .. " au " ..  endstr .. era
	else
		if vowelfirst(startstr) then
			return "d'" .. startstr .. " à ".. endstr .. era
		else
			return "de " .. startstr .. " à " .. endstr .. era
		end
	end
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
	if startpoint.era == endpoint.era then
		sameera = true
	end
	if (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

	local startpoint = p.simplestring(startpoint, displayformat)
	local 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 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 september 2006"
	if era == "-" then
		era = " av J-C"
	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 precision = setprecision(endpoint, displayformat.precision)

 	-- analyse les paramètres pour éviter les redondances
 	
	local startpoint, endpoint, era, displayformat, sameera = removeclutter(startpoint, endpoint, precision, 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 september 2006"
	if era == '-' then
		era = ' av J-C'
	else
		era = ''
	end
	if displayformat.textformat == 'long' then
		return fromuntillong(startstr, endstr, era, precision)
	elseif (type(precision) == "number") and (precision > 9) then -- si les date contiennent des mois ou jours, il vaut mieux un espace
		return startstr .. ' -<wbr> ' .. endstr .. era
	else
		return startstr .. '-<wbr>' .. endstr .. era
	end
end


function p.fuzzydate(dateobject, displayformat)
	local str = p.simplestring(dateobject, displayformat)
	if not str then
		return nil
	end
	return "vers " .. str
end

function p.daterange(startpoint, endpoint, displayformat)
	if startpoint and endpoint then
		return fromuntil(startpoint, endpoint, displayformat)
	elseif startpoint then
		return fromdate(startpoint, displayformat)
	elseif endpoint then
		return upto(endpoint, displayformat)
	else
		return nil
	end
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)
	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 = {'era', 'year', 'month', 'day'}
	for i, j in pairs(order) do
		if b[j] < a[j] then
			return true
		elseif b[j] > a[j] then
			return false
		end
	end
	return true
end

return p