Module:Date complexe : Différence entre versions

De Lagny-sur-Marne Wiki
Aller à : navigation, rechercher
(between : retouche précision pour ajouter "le")
 
(64 révisions intermédiaires par 5 utilisateurs non affichées)
Ligne 1 : Ligne 1 :
 
-- TODO: améliorer les synergies avec Module:Date (gestion par module:Date de dates sans lien et de "XIe siècle en astronautique"
 
-- 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 datemodule = require 'Module:Date'
local linguistic = require('Module:Linguistique')
+
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 15 : 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 guessprecision(obj) -- précision des dates qui ne viennent pas de Module:Wikidata/Dates
+
local function setprecision(obj, maxprecision)
local prec = 0
+
local precision
for i, j in pairs(obj) do
+
if type(obj) == "string" then
if (numericprecision[i] or 0) > prec then
+
precision = tonumber(obj)
prec = numericprecision[i]
+
elseif type(obj) == "number" then
end
+
precision = obj
end  
+
elseif type(obj) == "table" then
return prec
+
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
 
end
  
local function centuryString(centurynumber)
+
 
return mw.getCurrentFrame():expandTemplate{ title = 'Nombre en romain', args = { centurynumber + 1 }} .. '<sup>e</sup> siècle'
+
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
 
end
  
local function milleniumString(centurynumber)
+
local function centuryString(century, era, hideera)
return mw.getCurrentFrame():expandTemplate{ title = 'Nombre en romain', args = { centurynumber + 1 }} .. '<sup>e</sup> millénaire'
+
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(decade)
+
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, 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
local yearstr, monthstr, daystr= tostring(dateobject.year), tostring(dateobject.month), tostring(dateobject.day)
+
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
  
-- adaptation à mw.formatDate en attendant de passer par Module:Date
+
if not displayformat then
if yearstr then
+
displayformat = {}
while #yearstr < 4 do
+
end
yearstr = 0 .. yearstr
+
local linktopic = displayformat.linktopic
end
+
local nolinks
 +
if linktopic == '-' then
 +
nolinks = true
 
end
 
end
  
local era = dateobject.era
+
local str
local precision = tonumber(dateobject.precision) or numericprecision[dateobject.precision] or guessprecision(dateobject)
+
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
 
if precision == 6 then
local century = tostring(math.floor(dateobject.year/100))
+
local millenium = math.floor(year/1000) + 1
str = milleniumString(century)
+
str = milleniumString(millenium, era, hideera)
 
elseif precision == 7 then
 
elseif precision == 7 then
local century = tostring(math.floor(dateobject.year/100))
+
local century = math.floor(year/100) + 1
str = centuryString(century)
+
str = centuryString(century, era, hideera)
 
elseif precision == 8 then
 
elseif precision == 8 then
local decade = tostring(math.floor(dateobject.year/10))  
+
local decade = tostring(math.floor(year/10))
str = decadeString(decade)
+
str = decadeString(decade, era, hideera)
elseif precision == 9 then
+
end
str = yearstr
+
if str then
elseif precision == 10 then
+
return str
str =mw.language.new('fr'):formatDate('F Y', yearstr .. '-' .. monthstr )  
+
end
if dateobject.year < 1000 then -- enlève les zéros en trop
+
str = string.gsub(str, '0', '')
+
-- 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
elseif precision == 11  then
+
end
if (type(displayformat) == 'table' and displayformat.linktopic) then
+
return datemodule.modeleDate({daystr, monthstr, yearstr, displayformat.linktopic})
+
local avJC -- équivalent de hideera pour modeleDate
end
+
if displayformat.hideera then
str = mw.language.new('fr'):formatDate('j F Y', yearstr .. '-' .. monthstr .. '-' .. daystr)
+
avJC = 'non'
if dateobject.day == 1 then -- ajustement "1 janvier" -> 1er janvier
+
end
str = string.gsub(str, '1', "1<sup>er</sup>", 1) -- remplace "1 janvier" par "1er janvier"
+
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
if dateobject.year < 1000 then
 
str = string.gsub(str, '0', '')
 
end
 
end
 
if era == '-' then
 
str = str .. ' av. J.-C.'
 
 
end
 
end
return str or 'date invalide'
+
return "depuis " .. datestr
 
end
 
end
  
 
local function fromdate(d, displayformat)  -- retourne "à partir de date" en langage naturel
 
local function fromdate(d, displayformat)  -- retourne "à partir de date" en langage naturel
local precision = d.precision or guessprecision(d)
+
displayformat = displayformat or {}
 +
local precision = setprecision(d, displayformat.precision)
 
local datestr = p.simplestring(d, displayformat)
 
local datestr = p.simplestring(d, displayformat)
 
if displayformat and displayformat.textformat == 'minimum' then
 
if displayformat and displayformat.textformat == 'minimum' then
 
return datestr -- par exemple pour les classements MH, juste afficher la date de début
 
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
 
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
 
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
 
return 'à partir du ' .. datestr
else
 
if vowelfirst(str) then
 
return "à partir d'" .. datestr
 
else
 
return 'à partir de ' .. datestr
 
end
 
 
end
 
end
 +
if (precision == 10) and (vowelfirst(datemodule.nomDuMois(d.month))) then
 +
return "à partir d'" .. datestr
 +
end
 +
return 'à partir de ' .. datestr
 
end
 
end
  
 
local function upto(d, displayformat)  -- retourne "jusqu'à date' en langage naturel
 
local function upto(d, displayformat)  -- retourne "jusqu'à date' en langage naturel
 +
displayformat = displayformat or {}
 
local datestring = p.simplestring(d, displayformat)
 
local datestring = p.simplestring(d, displayformat)
local precision = d.precision or guessprecision(d)
+
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
  
local function fromuntillong(startstr, endstr) -- inutile ?
+
local function fromuntillong(startstr, endstr, era, precision)
 
-- 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 " .. startstr .. " 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
 +
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
 
else
return "de " .. startstr .. " à " .. endstr
+
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
 
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
 
end
 
end
  
 
local function fromuntil(startpoint, endpoint, displayformat)
 
local function fromuntil(startpoint, endpoint, displayformat)
local precision = endpoint.precision or guessprecision(endpoint) -- may need 2 precisions for start and end dates
+
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 startstr = p.simplestring(startpoint)
+
local hideera= displayformat.hideera
local endstr = p.simplestring(endpoint)
+
displayformat.hideera = true -- pour les chaînes intermédiaires
-- à améliorer pour éviter les tournures répétitives comme  "du 13 septembre 2006 au 18 september 2006"
+
if not params then
+
local startstr, endstr = p.simplestring(startpoint, displayformat), p.simplestring(endpoint, displayformat)
params = {}
+
 +
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
 
end
if params.displayformat == 'long' then
+
if displayformat.textformat == 'long' then
return fromuntillong(startstr, endstr)
+
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 .. '-' .. endstr
+
return startstr .. '-<wbr>' .. endstr .. era
 
end
 
end
 
end
 
end
  
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
  
function p.daterange(startpoint, endpoint, displayformat)  
+
function p.daterange(startpoint, endpoint, displayformat)
 
if startpoint and endpoint then
 
if startpoint and endpoint then
 
return fromuntil(startpoint, endpoint, displayformat)
 
return fromuntil(startpoint, endpoint, displayformat)
Ligne 174 : Ligne 351 :
 
return datemodule.age(start.year, start.month, start.day, ending.year, ending.month, ending.day)
 
return datemodule.age(start.year, start.month, start.day, ending.year, ending.month, ending.day)
 
end
 
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
 
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