Módulo:Edad
Nota Importante: Este módulo está en proceso de adaptación de Module:Age al español para poder soportar la funcionalidad de todas las plantillas de edad que se utilizan en la Wikipedia en español. La idea es que sea un reemplazo único para todas las plantillas de edad existentes para juntar toda la implementación en un sitio y hacerla más fácil de mantener. Se agradece muchísimo el impecable trabajo original de User:Johnuniq sin el cual esto no sería posible.
Plantillas implementadas
Módulo:Edad implementa las siguientes plantillas: Las últimas dos columnas representan:
- Adaptado a español: si la implementación del módulo se ha adaptado para aceptar los parámetros de la actual implementación de sus respectivas plantillas.
- En uso: si la implementación actual de esa plantilla en español utiliza éste módulo.
Plantilla | Wikitexto de la plantilla | Adaptado a español | En uso |
---|---|---|---|
{{intervalo tiempo}} |
{{#invoke:edad|time_interval}} |
Completo | Sí |
{{edad en días}} |
{{#invoke:edad|age_generic|template=age_days}} |
Parcial | No |
{{duración en días}} |
{{#invoke:edad|age_generic|template=duration_days}} |
Completo | Sí |
{{edad}} |
{{#invoke:edad|age_generic|template=age_full_years}} |
Completo | Pendiente |
{{edad en años}} |
{{#invoke:edad|age_generic|template=age_in_years}} |
Completo | Pendiente |
{{edad en meses}} |
{{#invoke:edad|age_generic|template=age_m}} |
Completo | Sí |
{{edad en semanas}} |
{{#invoke:edad|age_generic|template=age_w}} |
Completo | Sí |
{{edad en años y días}} |
{{#invoke:edad|age_generic|template=age_yd}} |
Completo | Pendiente |
{{edad en años y meses}} |
{{#invoke:edad|age_generic|template=age_ym}} |
Completo | Sí |
{{edad en años, meses y días}} |
{{#invoke:edad|age_generic|template=age_ymd}} |
Parcial | Pendiente |
Las plantillas de edad esperan recibir la fecha más antigua primero Las implementaciones de age_in_years
y age_in_years_nts
muestran un mensaje de error si no es así. Si se necesita una comprobación similar en otras plantillas, se puede añadir negative=error
al invoke. Por ejemplo, {{edad}}
podría usar:
{{#invoke:edad|age_generic|template=age_full_years|negative=error}}
Si no se aplica negative=error
la diferencia negativa se muestra con un signo menos (−).
Formatos de Fecha
Las fechas pueden usar parámetros numerados o nombrados para especificar el día/mes/año. De forma alternativa, una fecha completa se puede introducir en una variedad de formatos. Por ejemplo:
{{edad en años y meses|a1=2001|m1=1|d1=10|a2=2012|m2=2|d2=20}}
→ 11 años y 1 mes{{edad en años y meses|a=2001|m=1|d=10|a2=2012|m2=2|d2=20}}
→ 11 años y 1 mes{{edad en años y meses|10|1|2001|20|2|2012}}
→ 11 años y 1 mes{{edad en años y meses|2001-1-10|2012-2-20}}
→ 11 años y 1 mes{{edad en años y meses|10 ene 2001|20 feb 2012}}
→ 11 años y 1 mes{{edad en años y meses|10 de enero de 2001|20 de febrero de 2012}}
→ 11 años y 1 mes{{edad en años y meses|enero 10, 2001|feb 20, 2012}}
→ 11 años y 1 mes
Si se omite una de las dos fechas, se utiliza la actual en su lugar. Por ejemplo:
{{edad en años y meses|a2=2012|m2=2|d2=20}}
→ −12 años y 8 meses{{edad en años y meses||||20|2|2012}}
→ −12 años y 8 meses{{edad en años y meses||2012-2-20}}
→ −12 años y 8 meses{{edad en años y meses||20 feb 2012}}
→ −12 años y 8 meses{{edad en años y meses||feb 20, 2012}}
→ −12 años y 8 meses{{edad en años y meses|a1=2001|m1=1|d1=10}}
→ 23 años y 9 meses{{edad en años y meses|year=2001|month=1|day=10}}
→{{edad en años y meses|10|1|2001|}}
→ 23 años y 9 meses{{edad en años y meses|2001-1-10}}
→ 23 años y 9 meses{{edad en años y meses|10 ene 2001}}
→ 23 años y 9 meses{{edad en años y meses|10 de enero de 2001}}
→ 23 años y 9 meses{{edad en años y meses|enero 10, 2001}}
→ 23 años y 9 meses
Parámetros
The following options are available:
Parámetro | Descripción |
---|---|
duration=on |
La fecha final está incluida en el resultado añadiendo un día a la edad. |
fix=on |
Ajusta unidades de tiempo no válidas Ver "Template:Extract#Fix" (Pendiente de traducir). |
format=commas |
Un valor de 1000 o mayor aparece con comas como separadores. |
format=raw |
Los números se muestran sin comas y los negativos con un guión para {{#expr}} . Además, {{age}} devuelve el número tal cual sin el span con información.
|
format=cardinal |
Mostrar el número resultante en texto utilizando palabras como "cinco" en lugar de 5. Ver más abajo. |
format=ordinal |
Mostrar el número resultante utilizando palabras como "quinto" en vez de 5. Ver más abajo. |
prefix=texto |
Inserta el texto antes del resultado pero después de una clave de ordenación. Por ejemplo, {{edad|23 de julio de 1910|14 de julio de 1976|prefix=sobre|sortable=on}} devuelve una clave de ordenación oculta seguida de "sobre 65".
|
range=dash |
Aceptar un año solo o año y mes y devolver un rango de edades separadas por un guión largo (–). |
range=yes |
Aceptar un año o mes/año y mostrar el rango separado por "or". |
range=no |
Aceptar un año o mes/año, pero mostrar solo una edad como si se hubiesen introducido fechas completas. |
round=on |
La edad se redondea a la unidad de tiempo menos significativa más cercana. |
sc=on |
Se utiliza la (solo útil si se muestran tres o más valores). |
sc=yes |
Igual que sc=on .
|
show=hide |
No se muestra la edad; puede ser útil combinado con sortable=on .
|
sortable=on |
Inserta una clave de ordenación oculta antes del resultado (para utilizar con tablas ordenables). |
sortable=table |
Inserta una clave de ordenación utilizando la sintaxis de tabla data-sort-value="value"| .
|
sortable=debug |
Igual que sortable=on pero mostrando la clave de ordenación. Usado solo para testear.
|
sortable=off |
Sin clave de ordenación, si se incluye puede sobreescribir el valor por defecto de plantillas como {{edad nts}} ).
|
ceros=yes |
Muestra los campos que dan cero en la diferencia ('1 año, 0 meses y 3 días' VS '1 año y 3 días'). |
Algunos ejemplos de uso del parámetro range
se muestran a continuación.
{{edad en años y meses|year=2001|month=1|a2=2012|m2=2|range=yes}}
→ −12 años y 8 o 9 meses{{edad en años y meses||1|2001|2|2012|range=yes}}
→ Error: La segunda fecha debería ser año, mes, día{{edad en años y meses|ene 2001|feb 2012|range=yes}}
→ 11 años y 0 o 1 mes{{edad en años y meses|ene 2001|febrero de 2012|range=dash}}
→ 11 años y 0–1 mes{{edad en años y meses|ene 2001|feb 2012|range=no}}
→ 11 años y 1 mes No se está usando la plantilla de forma adecuada.{{edad en años y meses|12 ene 2001|feb 2012|range=no}}
→ 11 años y 1 mes No se está usando la plantilla de forma adecuada.{{edad en años y meses|2001|2012|range=no}}
→ 11 años No se está usando la plantilla de forma adecuada.{{edad en años y meses|2001|23 feb 2012|range=no}}
→ 11 años No se está usando la plantilla de forma adecuada.
La clave de ordenación se basa en la edad en días y fracciones de los mismos si se especifica una hora.
{{edad en años y meses|10 ene 2001|20 feb 2012|sortable=debug}}
→ 7003405800000000000♠11 años y 1 mes{{edad en años y meses|10 ene 2001|6:00 am 20 feb 2012|sortable=debug}}
→ 7003405825000000000♠11 años y 1 mes{{edad en años y meses|10 ene 2001|6:00 am 20 feb 2012|sortable=debug|show=hide}}
→ 7003405825000000000♠
Un día extra añadido para la duración.
{{edad en años y meses|20 ene 2001|19 feb 2012}}
→ 10 años y 11 meses No se está usando la plantilla de forma adecuada.{{edad en años y meses|20 ene 2001|19 feb 2012|duration=on}}
→ 11 años y 1 mes
También se puede redondear la unidad de tiempo menos significativa.
{{edad en años y meses|20 ene 2001|10 ene 2012}}
→ 10 años y 11 meses{{edad en años y meses|20 ene 2001|10 ene 2012|round=on}}
→ 11 años No se está usando la plantilla de forma adecuada.
Los números grandes se pueden formatear con comas.
{{edad en años y meses|2012|120|format=commas|range=yes}}
→ −1,891 o 1,892 años{{edad en años y meses|2012|120|format=commas|range=dash}}
→ −1,891–1,892 años
Deletrear números
Nota: La traducción de Módulo:ConvertNumeric no está 100% terminada, los cardinales funcionan pero en español la distinción entre cardinal
y cardinal_us
no tiene sentido. Se está trabajando en ello.
Nota2: Los siguientes ejemplos no funcionarán hasta que se migre la plantilla de edad
Las plantillas que utilizan age_generic
pueden mostrar números en forma de palabras en vez de numerales. El resultado puede ser un número cardinal como "cinco" o un número ordinal como "quinto". Dependiendo de cómo se escriba el parámetro la primera letra será o no en mayúscula. Si indicas una fecha parcial y pides un rango de vuelta también te lo puede deletrear. Ejemplos:
{{edad en meses|01|01|1898|01|02|2018|format=cardinal}}
→ mil cuatrocientos cuarenta y uno{{edad en meses|01|01|1898|01|02|2018|format=Cardinal}}
→ Mil cuatrocientos cuarenta y uno{{edad en meses|01|01|1898|01|02|2018|format=ordinal}}
→ milésimo cuadringentésimo cuadragésimo primero{{edad en meses|01|01|1898|01|02|2018|format=Ordinal}}
→ Milésimo cuadringentésimo cuadragésimo primero{{edad en meses|1980|1990|range=yes|format=Cardinal}}
→ Ciento ocho o ciento treinta y uno{{edad en años y meses|abril 1980|1995|format=Cardinal|range=yes}}
→ Catorce o quince años
Categoría de seguimiento
Ver también
{{intervalo tiempo}}
• Esta plantilla soporta todos los cálculos de edad/duración y provee más opciones como abreviaturas o omisión de unidades.
-- Implement various "age of" and other date-related templates.
local mtext = {
-- Message and other text that should be localized.
['mt-bad-param1'] = 'Parámetro no válido $1',
['mt-bad-param2'] = 'El parámetro $1=$2 no es válido',
['mt-bad-show'] = 'El parámetro show=$1 no está soportado',
['mt-cannot-add'] = 'No se puede sumar "$1"',
['mt-conflicting-show'] = 'El parámetro show=$1 está en conflicto con round=$2',
['mt-date-wrong-order'] = 'La segunda fecha tiene que ocurrir después que la primera',
['mt-dd-future'] = 'La fecha de muerte (la primera) no puede ser en el futuro',
['mt-dd-wrong-order'] = 'La fecha de muerte (la primera) tiene que ocurrir después que la de nacimiento (la segunda)',
['mt-invalid-bd-age'] = 'Fecha de nacimiento no válida para calcular una edad',
['mt-invalid-dates-age'] = 'Fechas no válidas para calcular la edad',
['mt-invalid-end'] = 'Fecha de fin no válida en el segundo parámetro',
['mt-invalid-start'] = 'Fecha de comienzo no válida en el primer parámetro',
['mt-need-jdn'] = 'Se necesita un número de fecha juliana válido',
['mt-need-valid-bd'] = 'Se necesita una fecha de nacimiento válida: año, mes día',
['mt-need-valid-bd2'] = 'Se necesita una fecha de nacimiento válida (segunda fecha): año, mes día',
['mt-need-valid-date'] = 'Se necesita una fecha válida',
['mt-need-valid-dd'] = 'Se necesita una fecha de muerte válida (segunda fecha): año, mes, día',
['mt-need-valid-ymd'] = 'Se necesita un año, mes y día válidos',
['mt-need-valid-ymd-current'] = 'Se necesita un año|mes|día válidos o "currentdate"',
['mt-need-valid-ymd2'] = 'La segunda fecha debería ser año, mes, día',
['mt-template-bad-name'] = 'El nombre de plantilla especificado no es válido',
['mt-template-x'] = 'La plantilla que llame a este método debe especificar "|template=x" donde x es la operación necesaria',
['txt-age'] = '(edad ',
['txt-aged'] = ' (a los ',
['txt-and'] = ' y ',
['txt-comma-and'] = ', y ',
['txt-error'] = 'Error: ',
['txt-or'] = ' o ',
}
local translate, from_en, to_en, isZero
if translate then
-- Functions to translate from en to local language and reverse go here.
-- See example at [[:bn:Module:বয়স]].
else
from_en = function (text)
return text
end
isZero = function (text)
return tonumber(text) == 0
end
end
local _Date, _currentDate
-- Return objects exported from the date module or its sandbox.
local function getExports(frame)
if not _Date then
local sandbox = frame:getTitle():find('sandbox', 1, true) and '/sandbox' or ''
local datemod = require('Módulo:Date' .. sandbox)
local realDate = datemod._Date
_currentDate = datemod._current
if to_en then
_Date = function (...)
local args = {}
for i, v in ipairs({...}) do
args[i] = to_en(v)
end
return realDate(unpack(args))
end
else
_Date = realDate
end
end
return _Date, _currentDate
end
local Collection -- a table to hold items
Collection = {
add = function (self, item)
if item ~= nil then
self.n = self.n + 1
self[self.n] = item
end
end,
join = function (self, sep)
return table.concat(self, sep)
end,
remove = function (self, pos)
if self.n > 0 and (pos == nil or (0 < pos and pos <= self.n)) then
self.n = self.n - 1
return table.remove(self, pos)
end
end,
sort = function (self, comp)
table.sort(self, comp)
end,
new = function ()
return setmetatable({n = 0}, Collection)
end
}
Collection.__index = Collection
-- If text is a string, return its trimmed content, or nil if empty.
-- Otherwise return text (which may, for example, be nil).
local function stripToNil(text)
if type(text) == 'string' then
text = text:match('(%S.-)%s*$')
end
return text
end
-- Return true if parameter should be interpreted as "yes".
-- Do not want to accept mixed upper/lowercase unless done by current templates.
-- Need to accept "on" because "round=on" is wanted.
local function yes(parameter)
return ({ y = true, yes = true, on = true })[parameter]
end
-- Return formatted message text for an error or warning.
local function message(msg, id)
local function getText(msg)
return mtext[msg] or error('Bug: el mensaje "' .. tostring(msg) .. '" no está definido')
end
local text
if type(msg) == 'table' then
text = getText(msg[1])
local rep = {}
for i, v in ipairs(msg) do
if i > 1 then
rep['$' .. (i - 1)] = v
end
end
text = text:gsub('$%d+', rep)
else
text = getText(msg)
end
local categories = {
error = '[[Categoría:Error de Edad]]',
warning = '[[Categoría:Error de Edad]]', -- same as error until determine whether 'Age warning' would be worthwhile
}
local a, b, category
if id == 'warning' then
a = '<sup>[<i>'
b = '</i>]</sup>'
else
a = '<strong class="error">' .. getText('txt-error')
b = '</strong>'
end
if mw.title.getCurrentTitle():inNamespaces(0) then
-- Category only in namespaces: 0=article.
category = categories[id or 'error']
end
return
a ..
mw.text.nowiki(text) ..
b ..
(category or '')
end
-- Return the given number formatted with commas as group separators,
-- given that the number is an integer.
local function formatNumber(number)
local numstr = tostring(number)
local length = #numstr
local places = Collection.new()
local pos = 0
repeat
places:add(pos)
pos = pos + 3
until pos >= length
places:add(length)
local groups = Collection.new()
for i = places.n, 2, -1 do
local p1 = length - places[i] + 1
local p2 = length - places[i - 1]
groups:add(numstr:sub(p1, p2))
end
return groups:join(',')
end
-- Return result of spelling number, or
-- return number (as a string) if cannot spell it.
-- i == 1 for the first number which can optionally start with an uppercase letter.
local function spellNumber(number, options, i)
number = tostring(number)
return require('Módulo:ConvertNumeric').spell_number(
number,
-- nil, -- fraction numerator NO SOPORTADO
-- nil, -- fraction denominator NO SOPORTADO
i == 1 and options.upper, -- true: 'One' instead of 'one'
options.ordinal, -- true: 'first' instead of 'one'
options.adj -- true: hyphenated
) or number
end
-- Return extra text that will be inserted before the visible result
-- but after any sort key.
local function makeExtra(args, flagCurrent)
local extra = args.prefix or ''
if mw.ustring.len(extra) > 1 then
-- Parameter "~" gives "~3" whereas "over" gives "over 3".
if extra:sub(-6, -1) ~= ' ' then
extra = extra .. ' '
end
end
if flagCurrent then
extra = '<span class="currentage"></span>' .. extra
end
return extra
end
-- Return a sort key if requested.
-- Assume value is a valid number which has not overflowed.
local function makeSort(value, sortable)
if sortable == 'sortable_table' or sortable == 'sortable_on' or sortable == 'sortable_debug' then
local sortKey
if value == 0 then
sortKey = '5000000000000000000'
else
local mag = math.floor(math.log10(math.abs(value)) + 1e-14)
if value > 0 then
sortKey = 7000 + mag
else
sortKey = 2999 - mag
value = value + 10^(mag+1)
end
sortKey = string.format('%d', sortKey) .. string.format('%015.0f', math.floor(value * 10^(14-mag)))
end
local result
if sortable == 'sortable_table' then
result = 'data-sort-value="_SORTKEY_"|'
elseif sortable == 'sortable_debug' then
result = '<span data-sort-value="_SORTKEY_♠"><span style="border:1px solid">_SORTKEY_♠</span></span>'
else
result = '<span data-sort-value="_SORTKEY_♠"></span>'
end
return result:gsub('_SORTKEY_', sortKey)
end
end
local translateParameters = {
abbr = {
off = 'abbr_off',
on = 'abbr_on',
},
disp = {
age = 'disp_age',
raw = 'disp_raw',
},
format = {
raw = 'format_raw',
commas = 'format_commas',
},
round = {
on = 'on',
yes = 'on',
months = 'ym',
weeks = 'ymw',
days = 'ymd',
hours = 'ymdh',
},
sep = {
comma = 'sep_comma',
[','] = 'sep_comma',
serialcomma = 'sep_serialcomma',
space = 'sep_space',
},
show = {
hide = { id = 'hide' },
y = { 'y', id = 'y' },
ym = { 'y', 'm', id = 'ym' },
ymd = { 'y', 'm', 'd', id = 'ymd' },
ymw = { 'y', 'm', 'w', id = 'ymw' },
ymwd = { 'y', 'm', 'w', 'd', id = 'ymwd' },
yd = { 'y', 'd', id = 'yd', keepZero = true },
m = { 'm', id = 'm' },
md = { 'm', 'd', id = 'md' },
w = { 'w', id = 'w' },
wd = { 'w', 'd', id = 'wd' },
h = { 'H', id = 'h' },
hm = { 'H', 'M', id = 'hm' },
hms = { 'H', 'M', 'S', id = 'hms' },
d = { 'd', id = 'd' },
dh = { 'd', 'H', id = 'dh' },
dhm = { 'd', 'H', 'M', id = 'dhm' },
dhms = { 'd', 'H', 'M', 'S', id = 'dhms' },
ymdh = { 'y', 'm', 'd', 'H', id = 'ymdh' },
ymdhm = { 'y', 'm', 'd', 'H', 'M', id = 'ymdhm' },
ymwdh = { 'y', 'm', 'w', 'd', 'H', id = 'ymwdh' },
ymwdhm = { 'y', 'm', 'w', 'd', 'H', 'M', id = 'ymwdhm' },
},
sortable = {
off = false,
on = 'sortable_on',
table = 'sortable_table',
debug = 'sortable_debug',
},
}
local spellOptions = {
cardinal = {},
Cardinal = { upper = true },
ordinal = { ordinal = true },
Ordinal = { ordinal = true, upper = true },
}
-- Return part of a date after performing an optional operation.
local function dateExtract(frame)
local Date = getExports(frame)
local args = frame:getParent().args
local parms = {}
for i, v in ipairs(args) do
parms[i] = v
end
if yes(args.fix) then
table.insert(parms, 'fix')
end
if yes(args.partial) then
table.insert(parms, 'partial')
end
local show = stripToNil(args.show) or 'dmy'
local date = Date(unpack(parms))
if not date then
if show == 'format' then
return 'error'
end
return message('mt-need-valid-date')
end
local add = stripToNil(args.add)
if add then
for item in add:gmatch('%S+') do
date = date + item
if not date then
return message({ 'mt-cannot-add', item })
end
end
end
local sortKey, result
local sortable = translateParameters.sortable[args.sortable]
if sortable then
local value = (date.partial and date.partial.first or date).jdz
sortKey = makeSort(value, sortable)
end
if show ~= 'hide' then
result = date[show]
if result == nil then
result = from_en(date:text(show))
elseif type(result) == 'boolean' then
result = result and '1' or '0'
else
result = from_en(tostring(result))
end
end
return (sortKey or '') .. makeExtra(args) .. (result or '')
end
-- Return text to be used between a range of ages.
local function rangeJoin(range)
return range == 'dash' and '–' or mtext['txt-or']
end
-- Return wikitext representing an age or duration.
local function makeText(values, components, names, options, noUpper)
local text = Collection.new()
local count = #values
local sep = names.sep or ''
for i, v in ipairs(values) do
-- v is a number (say 4 for 4 years), or a table ({4,5} for 4 or 5 years).
local islist = type(v) == 'table'
if (islist or v > 0) or (text.n == 0 and i == count) or (text.n > 0 and components.keepZero) then
local fmt, vstr
if options.spell then
fmt = function(number)
return spellNumber(number, options.spell, noUpper or i)
end
elseif i == 1 and options.format == 'format_commas' then
-- Numbers after the first should be small and not need formatting.
fmt = formatNumber
else
fmt = tostring
end
if islist then
vstr = fmt(v[1]) .. rangeJoin(options.range)
noUpper = true
vstr = vstr .. fmt(v[2])
else
vstr = fmt(v)
end
local name = names[components[i]]
if name then
local plural = names.plural
if not plural or (islist and v[2] or v) == 1 then
plural = ''
end
if plural ~= '' and name == 'mes' then -- Manejar el caso de que sea necesario poner 'meses' para evitar 'mess'
name = 'meses'
plural = ''
end
if not options.ignoreZero then
text:add(vstr .. sep .. name .. plural)
elseif not (vstr == '0') then
text:add(vstr .. sep .. name .. plural)
end
else
if not options.ignoreZero then
text:add(vstr)
elseif not (vstr == '0') then
text:add(vstr)
end
end
end
end
local first, last
if options.join == 'sep_space' then
first = ' '
last = ' '
elseif options.join == 'sep_comma' then
first = ', '
last = ', '
elseif options.join == 'sep_serialcomma' and text.n > 2 then
first = ', '
last = mtext['txt-comma-and']
elseif options.join == 'sep_and' then
first = ', '
last = mtext['txt-and']
else
first = ', '
last = mtext['txt-and']
end
for i, v in ipairs(text) do
if i < text.n then
text[i] = v .. (i + 1 < text.n and first or last)
end
end
local sign = ''
if options.isnegative then
-- Do not display negative zero.
if text.n > 1 or (text.n == 1 and text[1]:sub(1, 1) ~= '0' ) then
if options.format == 'format_raw' then
sign = '-' -- plain hyphen so result can be used in a calculation
else
sign = '−' -- Unicode U+2212 MINUS SIGN
end
end
end
return
(options.sortKey or '') ..
(options.extra or '') ..
sign ..
text:join() ..
(options.suffix or '')
end
-- Return a formatted date difference using the given parameters
-- which have been validated.
local function dateDifference(parms)
local names = {
abbr_off = {
plural = 's',
sep = ' ',
y = 'año',
m = 'mes',
w = 'semana',
d = 'día',
H = 'hora',
M = 'minuto',
S = 'segundo',
},
abbr_on = {
y = 'a',
m = 'm',
w = 's',
d = 'd',
H = 'h',
M = 'm',
S = 's',
},
abbr_infant = { -- for {{age for infant}}
plural = 's',
sep = ' ',
y = 'yr',
m = 'mo',
w = 'wk',
d = 'day',
H = 'hr',
M = 'min',
S = 'sec',
},
abbr_raw = {},
}
local diff = parms.diff -- must be a valid date difference
local show = parms.show -- may be nil; default is set below
local abbr = parms.abbr or 'abbr_off'
local defaultJoin
if abbr ~= 'abbr_off' then
defaultJoin = 'sep_space'
end
if not show then
show = 'ymd'
if parms.disp == 'disp_age' then
if diff.years < 3 then
defaultJoin = 'sep_space'
if diff.years >= 1 then
show = 'ym'
else
show = 'md'
end
else
show = 'y'
end
end
end
if type(show) ~= 'table' then
show = translateParameters.show[show]
end
if parms.disp == 'disp_raw' then
defaultJoin = 'sep_space'
abbr = 'abbr_raw'
elseif parms.wantSc then
defaultJoin = 'sep_serialcomma'
end
local diffOptions = {
round = parms.round,
duration = parms.wantDuration,
range = parms.range and true or nil,
}
local sortKey
if parms.sortable then
local value = diff.age_days + (parms.wantDuration and 1 or 0) -- days and fraction of a day
if diff.isnegative then
value = -value
end
sortKey = makeSort(value, parms.sortable)
end
local textOptions = {
extra = parms.extra,
format = parms.format,
join = parms.sep or defaultJoin,
isnegative = diff.isnegative,
range = parms.range,
sortKey = sortKey,
spell = parms.spell,
suffix = parms.suffix, -- not currently used
ignoreZero = parms.ignoreZero,
}
if show.id == 'hide' then
return sortKey or ''
end
local values = { diff:age(show.id, diffOptions) }
if values[1] then
return makeText(values, show, names[abbr], textOptions)
end
if diff.partial then
-- Handle a more complex range such as
-- {{age_yd|20 Dec 2001|2003|range=yes}} → 1 year, 12 days or 2 years, 11 days
local opt = {
format = textOptions.format,
join = textOptions.join,
isnegative = textOptions.isnegative,
spell = textOptions.spell,
ignoreZero = parms.ignoreZero,
}
return
(textOptions.sortKey or '') ..
makeText({ diff.partial.mindiff:age(show.id, diffOptions) }, show, names[abbr], opt) ..
rangeJoin(textOptions.range) ..
makeText({ diff.partial.maxdiff:age(show.id, diffOptions) }, show, names[abbr], opt, true) ..
(textOptions.suffix or '')
end
return message({ 'mt-bad-show', show.id })
end
-- Parse template parameters and return one of:
-- * date (a date table, if single)
-- * date1, date2 (two date tables, if not single)
-- * text (a string error message)
-- A missing date is optionally replaced with the current date.
-- If wantMixture is true, a missing date component is replaced
-- from the current date, so can get a bizarre mixture of
-- specified/current y/m/d as has been done by some "age" templates.
-- Some results may be placed in table getopt.
local function getDates(frame, getopt)
local Date, currentDate = getExports(frame) -- Obtener referencias a las dependencias
getopt = getopt or {} -- Extraer opciones establecidas
local function flagCurrent(text)
-- This allows the calling template to detect if the current date has been used,
-- that is, whether both dates have been entered in a template expecting two.
-- For example, an infobox may want the age when an event occurred, not the current age.
-- Don't bother detecting if wantMixture is used because not needed and it is a poor option.
if not text then
if getopt.noMissing then
return nil -- this gives a nil date which gives an error
end
text = 'currentdate'
if getopt.flag == 'usesCurrent' then
getopt.usesCurrent = true
end
end
return text
end
local args = frame:getParent().args
local fields = {}
local isNamed = args.a or args.a1 or args.a2 or
args.m or args.m1 or args.m2 or
args.d or args.d1 or args.d2
-- Si se usan nombres asignarlos a la lista
if isNamed then
fields[1] = args.d1 or args.d
fields[2] = args.m1 or args.m
fields[3] = args.a1 or args.a
fields[4] = args.d2
fields[5] = args.m2
fields[6] = args.a2
else -- Y si no sacarlos en el orden establecido
for i = 1, 6 do
fields[i] = args[i]
end
end
local imax = 0
for i = 1, 6 do
fields[i] = stripToNil(fields[i])
if fields[i] then
imax = i
end
if getopt.omitZero and i % 3 ~= 1 then -- omit zero months and days as unknown values but keep year 0 which is 1 BCE
if isZero(fields[i]) then
fields[i] = nil
getopt.partial = true
end
end
end
local fix = getopt.fix and 'fix' or ''
local partialText = getopt.partial and 'partial' or ''
local dates = {}
if getopt.useWikiDefault then
if imax == 0 then
fields[1] = 20
fields[2] = 5
fields [3] = 2001
imax = 3
end
end
if isNamed or imax >= 3 then
local nrDates = getopt.single and 1 or 2
if getopt.wantMixture then
-- Cannot be partial since empty fields are set from current.
local components = { 'year', 'month', 'day' }
for i = 1, nrDates * 3 do
fields[i] = fields[i] or currentDate[components[i > 3 and i - 3 or i]]
end
for i = 1, nrDates do
local index = i == 1 and 1 or 4
local d, m, y = fields[index], fields[index+1], fields[index+2]
if (m == 2 or m == '2') and (d == 29 or d == '29') then
-- Workaround error with following which attempt to use invalid date 2001-02-29.
-- {{age_ymwd|year1=2001|year2=2004|month2=2|day2=29}}
-- {{age_ymwd|year1=2001|month1=2|year2=2004|month2=1|day2=29}}
-- TODO Get rid of wantMixture because even this ugly code does not handle
-- 'Feb' or 'February' or 'feb' or 'february'.
if not ((y % 4 == 0 and y % 100 ~= 0) or y % 400 == 0) then
d = 28
end
end
dates[i] = Date(y, m, d)
end
else
-- If partial dates are allowed, accept
-- year only, or
-- year and month only
-- Do not accept year and day without a month because that makes no sense
-- (and because, for example, Date('partial', 2001, nil, 12) sets day = nil, not 12).
for i = 1, nrDates do
local index = i == 1 and 1 or 4
local d, m, y = fields[index], fields[index+1], fields[index+2]
if (getopt.partial and y and (m or not d)) or (y and m and d) then
dates[i] = Date(fix, partialText, y, m, d)
elseif not y and not m and not d then
dates[i] = Date(flagCurrent())
end
end
end
else
getopt.textdates = true -- have parsed each date from a single text field
dates[1] = Date(fix, partialText, flagCurrent(fields[1]))
if not getopt.single then
dates[2] = Date(fix, partialText, flagCurrent(fields[2]))
end
end
if not dates[1] then
return message(getopt.missing1 or 'mt-need-valid-ymd')
end
if getopt.single then
return dates[1]
end
if not dates[2] then
return message(getopt.missing2 or 'mt-need-valid-ymd2')
end
return dates[1], dates[2]
end
-- Return the result required by the specified template.
-- Can use sortable=x where x = on/table/off/debug in any supported template.
-- Some templates default to sortable=on but can be overridden.
local function ageGeneric(frame)
local name = frame.args.template -- Extraer nombre de la plantilla que llama
if not name then
return message('mt-template-x') -- Error si no se indica plantilla
end
local args = frame:getParent().args -- Extraer los argumentos originales de la plantilla
local specs = {
age_days = { -- {{age in days}} --Adaptada
show = 'd',
disp = 'disp_raw',
},
age_days_nts = { -- {{age in days nts}} --Adaptada
show = 'd',
disp = 'disp_raw',
format = 'format_commas',
sortable = 'on',
},
duration_days = { -- {{duration in days}}
show = 'd',
disp = 'disp_raw',
duration = true,
},
duration_days_nts = { -- {{duration in days nts}}
show = 'd',
disp = 'disp_raw',
format = 'format_commas',
sortable = 'on',
duration = true,
},
age_full_years = { -- {{age}}
show = 'y',
abbr = 'abbr_raw',
flag = 'usesCurrent',
omitZero = true,
range = 'no',
},
age_full_years_nts = { -- {{age nts}}
show = 'y',
abbr = 'abbr_raw',
format = 'format_commas',
sortable = 'on',
},
age_in_years = { -- {{age in years}}
show = 'y',
abbr = 'abbr_raw',
negative = 'error',
range = 'dash',
},
age_in_years_nts = { -- {{age in years nts}}
show = 'y',
abbr = 'abbr_raw',
negative = 'error',
range = 'dash',
format = 'format_commas',
sortable = 'on',
},
age_infant = { -- {{age for infant}}
-- Do not set show because special processing is done later.
abbr = yes(args.abbr) and 'abbr_infant' or 'abbr_off',
disp = 'disp_age',
sep = 'sep_space',
sortable = 'on',
},
age_m = { -- {{age in months}}
show = 'm',
disp = 'disp_raw',
},
age_w = { -- {{age in weeks}}
show = 'w',
disp = 'disp_raw',
},
age_wd = { -- {{age in weeks and days}}
show = 'wd',
},
age_yd = { -- {{age in years and days}} --Adaptada
show = 'yd',
format = 'format_commas',
sep = args.sep == 'comma' and 'sep_comma' or 'sep_and',
ignoreZero = stripToNil(args['ceros']) == 'yes' and false or true,
useWikiDefault = true,
},
age_yd_nts = { -- {{age in years and days nts}} --Adaptada
show = 'yd',
format = 'format_commas',
sep = args.sep == 'comma' and 'sep_comma' or 'sep_and',
sortable = 'on',
ignoreZero = stripToNil(args['ceros']) == 'yes' and false or true,
},
age_ym = { -- {{age in years and months}}
show = 'ym',
sep = args.sep == 'comma' and 'sep_comma' or 'sep_and',
ignoreZero = stripToNil(args['ceros']) == 'yes' and false or true,
},
age_ymd = { -- {{age in years, months and days}}
show = 'ymd',
range = true,
ignoreZero = stripToNil(args['ceros']) == 'yes' and false or true,
useWikiDefault = true,
},
age_ymwd = { -- {{age in years, months, weeks and days}}
show = 'ymwd',
},
}
local spec = specs[name] -- Seleccionar la especificación de la plantilla elegida
if not spec then
return message('mt-template-bad-name') -- Si no se encuentra error
end
if name == 'age_days' then
local su = stripToNil(args['show unit']) -- Extraer el parámetro 'show unit'
if su then
if su == 'abbr' or su == 'full' then -- Seleccionar el tipo de unidad a mostrar
spec.disp = nil
spec.abbr = su == 'abbr' and 'abbr_on' or nil -- Si es abreviada se marca en la spec
end
end
end
local ceros = stripToNil(args.ceros)
if ceros then
if ceros == 'yes' then
spec.ignoreZero = false
else
spec.ignoreZero = true
end
end
-- Para mantener compatibilidad con {{edad}} antigua y el parámetro 'años'
local anyos = args['años']
if name == 'age_full_years' then
anyos = anyos ~= nil and anyos or ' años'
else
anyos = ''
end
-- Para mantener compatibilidad con las que utilizan por defecto la de la wikipedia
local useWikiDefault = ''
if spec.useWikiDefault then
useWikiDefault = spec.useWikiDefault
else
useWikiDefault = false
end
-- Gestión de rangos en fechas parciales o relleno cuando no se quieren rangos
local partial, autofill
local range = stripToNil(args.range) or spec.range
if range then
-- Si se usan fechas parciales y la edad puede ser 11 o 12 años.
-- "|range=" (vacío) no tiene ningún efecto (se usa lo que haya en spec).
-- "|range=yes" or spec.range == true utiliza range = true (retorna "11 or 12")
-- "|range=dash" or spec.range == 'dash' utiliza range = 'dash' (retorna "11–12").
-- "|range=no" or spec.range == 'no' utiliza range = nil y rellena las fechas en el diff (retorna "12").
-- ("on" equivale a "yes", y "off" equivale a "no").
-- "|range=OTHER" utiliza range = nil y rechaza fechas parciales.
range = ({ dash = 'dash', off = 'no', no = 'no', [true] = true })[range] or yes(range)
if range then
partial = true -- Aceptar fechas parciales con posible rango de edades al final
if range == 'no' then
autofill = true -- El día/mes que falten en la segunda fecha se rellenarán con datos de la primera o 1
range = nil
end
end
end
local getopt = {
fix = yes(args.fix), -- Si se usa fix=on se arreglan las unidades demasiado grandes -> 26 horas son 1 día y 2 horas
flag = stripToNil(args.flag) or spec.flag,
omitZero = spec.omitZero,
partial = partial,
wantMixture = spec.wantMixture,
useWikiDefault = useWikiDefault,
}
local date1, date2 = getDates(frame, getopt)
if type(date1) == 'string' then
return date1
end
local format = stripToNil(args.format)
local spell = spellOptions[format]
if format then
format = 'format_' .. format
elseif name == 'age_days' and getopt.textdates then
format = 'format_commas'
end
local parms = {
diff = date2:subtract(date1, { fill = autofill }),
wantDuration = spec.duration or yes(args.duration),
range = range,
wantSc = yes(args.sc),
show = args.show == 'hide' and 'hide' or spec.show,
abbr = spec.abbr,
disp = spec.disp,
extra = makeExtra(args, getopt.usesCurrent and format ~= 'format_raw'),
format = format or spec.format,
round = yes(args.round),
sep = spec.sep,
sortable = translateParameters.sortable[args.sortable or spec.sortable],
spell = spell,
ignoreZero = spec.ignoreZero, --spec.ignoreZero and true or false
}
if (spec.negative or frame.args.negative) == 'error' and parms.diff.isnegative then
return message('mt-date-wrong-order')
end
return from_en(dateDifference(parms) .. anyos)
end
-- Implement [[Template:Birth date and age]].
local function bda(frame)
local args = frame:getParent().args
local options = {
missing1 = 'mt-need-valid-bd',
noMissing = true,
single = true,
}
local date = getDates(frame, options)
if type(date) == 'string' then
return date -- error text
end
local Date = getExports(frame)
local diff = Date('currentdate') - date
if diff.isnegative or diff.years > 150 then
return message('mt-invalid-bd-age')
end
local disp, show = 'disp_raw', 'y'
if diff.years < 2 then
disp = 'disp_age'
if diff.years == 0 and diff.months == 0 then
show = 'd'
else
show = 'm'
end
end
local df = stripToNil(args.df) -- day first (dmy); default is month first (mdy)
local result = '(<span class="bday">%-Y-%m-%d</span>) </span>' ..
(df and '%-d %B %-Y' or '%B %-d, %-Y')
result = from_en('<span style="display:none"> ' ..
date:text(result) ..
'<span class="noprint ForceAgeToShow"> ' ..
mtext['txt-age'] ..
dateDifference({
diff = diff,
show = show,
abbr = 'abbr_off',
disp = disp,
sep = 'sep_space',
}) ..
')</span>')
local warnings = tonumber(frame.args.warnings)
if warnings and warnings > 0 then
local good = {
df = true,
mf = true,
day = true,
day1 = true,
month = true,
month1 = true,
year = true,
year1 = true,
}
local invalid
local imax = options.textdates and 1 or 3
for k, _ in pairs(args) do
if type(k) == 'number' then
if k > imax then
invalid = tostring(k)
break
end
else
if not good[k] then
invalid = k
break
end
end
end
if invalid then
result = result .. message({ 'mt-bad-param1', invalid }, 'warning')
end
end
return result
end
-- Implement [[Template:Death date and age]].
local function dda(frame)
local args = frame:getParent().args
local options = {
missing1 = 'mt-need-valid-dd',
missing2 = 'mt-need-valid-bd2',
noMissing = true,
partial = true,
}
local date1, date2 = getDates(frame, options)
if type(date1) == 'string' then
return date1
end
local diff = date1 - date2
if diff.isnegative then
return message('mt-dd-wrong-order')
end
local Date = getExports(frame)
local today = Date('currentdate') + 1 -- one day in future allows for timezones
if date1 > today then
return message('mt-dd-future')
end
local years
if diff.partial then
years = diff.partial.years
years = type(years) == 'table' and years[2] or years
else
years = diff.years
end
if years > 150 then
return message('mt-invalid-dates-age')
end
local df = stripToNil(args.df) -- day first (dmy); default is month first (mdy)
local result
if date1.day then -- y, m, d known
result = (df and
'%-d %B %-Y' or
'%B %-d, %-Y') ..
'<span style="display:none">(%-Y-%m-%d)</span>'
elseif date1.month then -- y, m known; d unknown
result =
'%B %-Y' ..
'<span style="display:none">(%-Y-%m-00)</span>'
else -- y known; m, d unknown
result =
'%-Y' ..
'<span style="display:none">(%-Y-00-00)</span>'
end
result = from_en(date1:text(result) ..
mtext['txt-aged'] ..
dateDifference({
diff = diff,
show = 'y',
abbr = 'abbr_off',
disp = 'disp_raw',
range = 'dash',
sep = 'sep_space',
}) ..
')')
local warnings = tonumber(frame.args.warnings)
if warnings and warnings > 0 then
local good = {
df = true,
mf = true,
}
local invalid
local imax = options.textdates and 2 or 6
for k, _ in pairs(args) do
if type(k) == 'number' then
if k > imax then
invalid = tostring(k)
break
end
else
if not good[k] then
invalid = k
break
end
end
end
if invalid then
result = result .. message({ 'mt-bad-param1', invalid }, 'warning')
end
end
return result
end
-- Implement [[Template:Gregorian serial date]].
-- Return Gregorian serial date of the given date, or the current date.
-- The returned value is negative for dates before 1 January 1 AD
-- despite the fact that GSD is not defined for such dates.
local function dateToGsd(frame)
local date = getDates(frame, { wantMixture=true, single=true })
if type(date) == 'string' then
return date
end
return tostring(date.gsd)
end
-- Return formatted date from a Julian date.
-- The result includes a time if the input includes a fraction.
-- The word 'Julian' is accepted for the Julian calendar.
local function jdToDate(frame)
local Date = getExports(frame)
local args = frame:getParent().args
local date = Date('juliandate', args[1], args[2])
if date then
return from_en(date:text())
end
return message('mt-need-jdn')
end
-- Return Julian date (a number) from a date which may include a time,
-- or the current date ('currentdate') or current date and time ('currentdatetime').
-- The word 'Julian' is accepted for the Julian calendar.
local function dateToJd(frame)
local Date = getExports(frame)
local args = frame:getParent().args
local date = Date(args[1], args[2], args[3], args[4], args[5], args[6], args[7])
if date then
return tostring(date.jd)
end
return message('mt-need-valid-ymd-current')
end
-- Implement [[Template:Time interval]].
-- There are two positional arguments: date1, date2.
-- The default for each is the current date and time.
-- Result is date2 - date1 formatted.
local function timeInterval(frame)
local Date = getExports(frame)
local args = frame:getParent().args
local parms = {
extra = makeExtra(args),
wantDuration = yes(args.duration),
range = yes(args.range) or (args.range == 'dash' and 'dash' or nil),
wantSc = yes(args.sc),
}
local fix = yes(args.fix) and 'fix' or ''
local date1 = Date(fix, 'partial', stripToNil(args[1]) or 'currentdatetime')
if not date1 then
return message('mt-invalid-start')
end
local date2 = Date(fix, 'partial', stripToNil(args[2]) or 'currentdatetime')
if not date2 then
return message('mt-invalid-end')
end
parms.diff = date2 - date1
for argname, translate in pairs(translateParameters) do
local parm = stripToNil(args[argname])
if parm then
parm = translate[parm]
if parm == nil then -- test for nil because false is a valid setting
return message({ 'mt-bad-param2', argname, args[argname] })
end
parms[argname] = parm
end
end
if parms.round then
local round = parms.round
local show = parms.show
if round ~= 'on' then
if show then
if show.id ~= round then
return message({ 'mt-conflicting-show', args.show, args.round })
end
else
parms.show = translateParameters.show[round]
end
end
parms.round = true
end
return from_en(dateDifference(parms))
end
return {
age_generic = ageGeneric, -- can emulate several age templates
birth_date_and_age = bda, -- Template:Birth_date_and_age
death_date_and_age = dda, -- Template:Death_date_and_age
gsd = dateToGsd, -- Template:Gregorian_serial_date
extract = dateExtract, -- Template:Extract
jd_to_date = jdToDate, -- Template:?
JULIANDAY = dateToJd, -- Template:JULIANDAY
time_interval = timeInterval, -- Template:Time_interval
}