Module:Date complexe : Différence entre versions

De Lagny-sur-Marne Wiki
Aller à : navigation, rechercher
(between : retouche précision pour ajouter "le")
 
(77 révisions intermédiaires par 5 utilisateurs non affichées)
Ligne 1 : Ligne 1 :
local datemodule = require('Module:Date')
+
-- TODO: améliorer les synergies avec Module:Date (gestion par module:Date de dates sans lien et de "XIe siècle en astronautique"
local linguistic = require('Module:Linguistique')
+
 
 +
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 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 centuryString(centurynumber)
+
local function setprecision(obj, maxprecision)
return mw.getCurrentFrame():expandTemplate{ title = 'Nombre en romain', args = { century }} .. '<sup>e</sup> siècle'
+
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
 
end
  
local function decadeString(decadenumber)
+
local function decadeString(decade, era, hideera)
return 'années ' .. decade .. '0'
+
local str = 'années ' .. decade .. '0'
 +
if era == '-' and (not hideera) then
 +
str = str .. ' av. J.-C.'
 +
end
 +
return '[[' .. str .. ']]'
 
end
 
end
  
function p.simplestring(dateobject) -- transforme un object date ponctuel en texte
+
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 str
local year, month, day = dateobject.year, dateobject.month, dateobject.day
+
local precision = setprecision(dateobject, displayformat.precision)
local era = dateobject.era
+
local precision = dateobject.precision
+
-- formats gérés par ce module
if object.precision == 7 then
+
local year = tonumber( dateobject.year) or 0
local century = tostring(math.floor(year/100))
+
str = centuryString(century)
+
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
 
elseif precision == 8 then
local decade = tostring(math.floor(year/10))  
+
local decade = tostring(math.floor(year/10))
str = decadestring(decade)
+
str = decadeString(decade, era, hideera)
elseif precision == 9 then
+
end
str = tostring(year)
+
if str then
elseif precision == 10 then
+
return str
str =mw.language.new('fr'):formatDate('F Y', year .. '-' .. month) -- devrait utiliser module date mais ne faut pas de lien
+
end
elseif precision == 11  then
+
str = mw.language.new('fr'):formatDate('j F Y', day .. '-' .. year .. '-' .. month)
+
-- formats gérés par Module:Date
if day == 1 then -- ajustement "1 janvier" -> 1er janvier
+
local year = dateobject.year
str = string.gsub(t, '1', "1<sup>er</sup>", 1) -- remplacer "1 janvier" par "1er janvier"
+
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 era == '-' then
+
str = str .. ' av. J.-C.'
+
local avJC -- équivalent de hideera pour modeleDate
 +
if displayformat.hideera then
 +
avJC = 'non'
 
end
 
end
return str
+
str = datemodule.modeleDate{jour = day, mois = month, annee = year, qualificatif = linktopic, nolinks = nolinks, avJC = avJC}
 +
return str or ''
 
end
 
end
  
local function fromdate(d) -- retourne "à partir de date" en langage naturel
+
local function fromToNow(d, datestr, precision) -- retourne "depuis" plutôt que "à partir de" quand c'est pas terminé
local str = simplestring(d)
+
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
if d.precision >= 11 then
+
return "depuis l'" .. datestr
return 'à partir du ' .. datestring
 
else
 
if vowelfirst(str) then
 
return "à partir d'" .. datestring
 
 
else
 
else
return 'à partir de ' .. datestring
+
return "depuis le " .. datestr
 
end
 
end
 
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
 
end
  
function p.upto(d)  -- retourne "jusqu'à date' en langage naturel
+
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 'jusqu\'au ' .. datestring
+
if (precision >= 11) or (precision == 7) or (precision == 6) then --on dit "jusqu'au" pour les dates avec jour, et pour les siècles
elseif (precision >= 9) then
+
return "jusqu'au " .. datestring
 +
elseif (precision > 9) then
 
return "jusqu'à " .. datestring
 
return "jusqu'à " .. datestring
 
else
 
else
return "jusqu\'en " .. datestring
+
return "jusqu'en " .. datestring
 
end
 
end
 
end
 
end
  
local function fromuntil(startpoint, endpoint)
+
local function fromuntillong(startstr, endstr, era, precision)
local precision = endpoint.precision -- may need 2 precisions for start and end dates
 
local startstr = p.simplestring(startpoint)
 
local endstr = p.simplestring(endpoint)
 
-- à améliorer pour éviter les tournures répétitives comme  "du 13 septembre 2006 au 18 september 2006"
 
 
 
-- on dit "du 3 au 14 janvier" mais "de septembe à octobre
 
-- on dit "du 3 au 14 janvier" mais "de septembe à octobre
 
if precision >= 11 then -- >= day
 
if precision >= 11 then -- >= day
return "du " .. startsr .. " au " ..  endstr
+
return "du " .. startstr .. " au " ..  endstr .. era
 
else
 
else
 
if vowelfirst(startstr) then
 
if vowelfirst(startstr) then
return "d'" .. startstr .. " à ".. endstr
+
return "d'" .. startstr .. " à ".. endstr .. era
 
else
 
else
return "de " .. startstr .. " à " .. endstr
+
return "de " .. startstr .. " à " .. endstr .. era
 
end
 
end
 
end
 
end
 
end
 
end
  
function p.fuzzydate(dateobjet)
+
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"
local str = simplestring(dateobject)
+
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
 
return "vers " .. str
 
end
 
end
  
function p.daterange(startpointobject, endpointobject)
+
function p.daterange(startpoint, endpoint, displayformat)
if startpointobject and endpointobject then
+
if startpoint and endpoint then
return fromuntil(startpointobject, endpointobject)
+
return fromuntil(startpoint, endpoint, displayformat)
elseif startpointobject then
+
elseif startpoint then
return fromdate(startpointobject)
+
return fromdate(startpoint, displayformat)
elseif endpointobject then
+
elseif endpoint then
return upto(endpointobject)
+
return upto(endpoint, displayformat)
 
else
 
else
 
return nil
 
return nil
 
end
 
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
 
end
  
 
return p
 
return p

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