Módulo:Data/Testes

Origem: Wikipédia, a enciclopédia livre.
Saltar para a navegação Saltar para a pesquisa
Broom icon.svg Este módulo pode ter sua documentação deficiente.
Por favor, documente-o ou melhore suas explicações caso o saiba usar ou tenha conhecimentos para tal.
Documentação do módulo[ver] [editar] [histórico] [purgar]



Descrição[editar código-fonte]

Este módulo tem funções auxiliares para criar infocaixas.

Ver módulo de dados Módulo:Data/Dados

Uso[editar código-fonte]

Funções que podem ser usadas de uma predefinição[editar código-fonte]

  • modeloData (frame) - exibe uma data com os links mais relevantes (definições abaixo).
  • templateInscriptionDate (frame) - exibe uma data não relacionada corretamente formatada. O ano é obrigatório. Parâmetros nomeados ano, mês, dia.
  • dateISO (frame) - semelhante a templateInscriptionDate, mas a data está no formato aaaa-mm-dd. Parâmetros nomeados ano, mês, dia. Para respeitar a ISO 8601, que define a data apenas de acordo com o calendário gregoriano, essa função não retorna nada para datas anteriores a 1583.
  • dateInfobox (frame) exibe uma data com os links relevantes, manipula corretamente os parâmetros que já contêm um modelo de data ou com o texto após a data (precisions below ). Projetado para ser usado em Infobox.
  • erroModuleData () - retorna uma mensagem de erro se o módulo: Data / Data não for carregado corretamente.
  • checkDataCat (frame) - retorna uma lista anual e mensal de páginas para facilitar atualizações de Data / Data. Parâmetros 1 = cat, month = lista de meses se 'yes', alias = listar todos os aliases se 'yes'

Funções que podem ser usadas de outro módulo[editar código-fonte]

  • validMonth (month) - retorna o nome em português e o número do mês (nome em portuguÊs, abreviado, inglês ou número entre 1 e 12).
  • determinationMes (mês, frame) - semelhante a validMonth, mas o número do mês não é limitado (14 → fevereiro) e pode até ser uma expressão se um objeto de quadro for fornecido (6 + 3 → setembro)
  • do_dayRank (argumentos) - Rank do dia no ano. Argumentos de parâmetro = {ano, mês, dia} ou {ano = ano, mês = mês, dia = dia}
  • isLeapYear (year) - retorna true se year for um ano bissexto no calendário gregoriano.
  • toRoman (number) - transforma o número em uma string representando-o em "algarismos romanos".
  • idade (an, mn, jn, ac, mc, jc) - semelhante ao modelAge, mas os parâmetros não estão em uma tabela
  • <Código>julianday (ano, mês, dia, hora, minuto, segundo) - retorna a Julian Day a data passou, de acordo com a calendário astronômico gregoriano ( com o ano 0)
  • <Código>julianDayJulian (ano, mês, dia, hora, minuto, segundo) - retorna a Julian dia um datado de Astronomical Julian calendário (com ano 0)
  • <Código>julianDayToGregorian (JD) - retorna três variáveis ​​ano, mês, dia representando a data do calendário gregoriano astronômico correspondente ao dia Julian.
  • julianDayToJulian (jd) - retorna três variáveis ​​ano, mês, dia representando a data de Julian calendar correspondente a este dia juliano.
  • julianToGregorian (ano, mês, dia) - transforma uma data do calendário juliano na data do calendário gregoriano.
  • gregorianToJulian (ano, mês, dia) - transforma uma data do calendário gregoriano para o calendário juliano.

Módulos externos que este módulo precisa para funcionar[editar código-fonte]

  • Data/Dados - banco de dados que permite não testar as páginas que sabemos que existem ou não existem.
  • TableBuilder - Use .insert e .concat para simplificar a sintaxe.

modeloData( frame )[editar código-fonte]

Parâmetros[editar código-fonte]

  • 1 - dia ou em branco - numérico, possível exceção para 1º.
  • 2 - mês ou dia - nome numérico ou português ou inglês, possivelmente uma abreviação atual.
  • 3 - ano ou mês - Um número será considerado ano. Os anos são considerados como seguindo o calendário gregoriano depois de 14 de outubro de 1582 (a menos que Juliano = 'sim') e o calendário juliano antes, sem o ano 0.
  • 4 - qualificador ou ano - texto correspondente a uma página típica "em fotografia" para "2008 na fotografia"
  • 5 - qualificador
  • age ou age - não está vazio para exibir a idade (nenhuma idade é exibida para datas no futuro)
  • juliano - 'sim' para a data a ser considerada como seguindo o calendário juliano depois de 14 de outubro de 1582. A data gregoriana com links é exibida, seguida pela data juliana entre parênteses.
  • a.C. - 'não' para não exibir 'a.C. ' depois do ano se representa um ano antes de Cristo. Útil para evitar repetições.
  • Página de parâmetros - Se um template {{data}} contém este parâmetro, os parâmetros juliano, a.C. e qualifier < / code> será aplicado a todas as datas na página, a menos que outro valor desses parâmetros seja especificado. O modelo de data que contém esse parâmetro não precisa ser exibido pelo módulo Data e pode ser comentado na página. A página deve ser limpa para que esse parâmetro seja levado em consideração.
  • qualifier - o qualificador para aplicar em toda a página. Funciona somente em conjunto com o parâmetro page parameters

Funcionamento[editar código-fonte]

  • o modelo procura exibir a data com links para as páginas dos qualificadores. Se não houver uma página vinculada ao qualificador, um link será feito para a página geral.
  • o primeiro parâmetro está vazio e o terceiro é um mês (somente texto), todos os parâmetros são considerados offset e o ano não será exibido.
  • Se não houver uma página específica para este mês-ano, o mês será exibido vinculado ao dia das efemérides. A prioridade é dada às efemérides do qualificador no link mês-ano sem qualificador.
  • o modelo usa o banco de dados Data/Dados para evitar o uso da função mw.title (equivalente do parser #ifexist :).
  • esta base permite substituir o qualificador por uma categoria mais genérica. Se o qualificador estiver "no tênis", as efemérides e a página mensal serão vinculadas ao qualificador "no esporte".
  • para evitar repetir o mesmo qualificador em todas as datas da página, basta ter em algum lugar no texto da página, mesmo em comentários, mas não trazido por um modelo, o texto {{Data|parâmetros page =|qualifier = meu qualificador}}. O modelo pode conter outros parâmetros. Somente o primeiro modelo de data contendo esse parâmetro será levado em consideração.

Função modeloData[editar código-fonte]

Motif testado Cadeia testada Módulo Funções custosas
modelo de antes / módulo
data recente 14|outubro|2001 1 / 0
date antiga (1700 - 1943), jour =1 1|outubro|1842 1 / 1
date muito antiga (<1700), dia = 1º 1|janeiro|537 1 / 0
qualificador que não está na base 14|outubro|2010|na animação ásiatica 4 / 1
data antiga, qualificador que não está na base 14|outubro|1842|na animação ásiatica 4 / 2
com qualificativo 14|Outubro|2001|na astronomia 3 / 0
com qualificador com efemérides 14|outubro|2005|nas ferrovias 4 / 0
sem dia |outubro|2001 1 / 0
sem dia com qualificativo |Outubro|2001|na astronomia 3 / 0
qualificador com página anual que poderia existir 14|outubro|2006|no Egito 4 / 1
qualificador com página mensal existente 14|outubro|2017|em Portugal 3 / 0
qualificador com página mensal que poderá existir 14|outubro|2012|em Portugal 4 / 1
qualificador com página anual e mensal que poderá existir 14|outubro|2012|na economia 4 / 2
date ancienne avec qualificativo 14|outubro|1845|en aéronautique 4 / 1
data negativa 13|outubro|-63 1 / 0
data a.C. 1|outubro|63 a.C. 1 / 0
data a.C. 13|outubro|63 a.C. 1 / 0
data negativa, parâmetro para esconder a.C. 13|outubro|-63|aC=não 1 / 0
année invalide 14|outubro|2001 en sport Ano inválido (2001 en sport) 1 / 0
dia + mês com maíscula 14|Outubro|2001 1 / 0
mês abreviado 14|oct.|2001 Mês inválido (oct.) 1 / 0
mês em numeros 14|10|2001 1 / 0
mês inválido 14|outubre|2001 Mês inválido (outubre) 1 / 0
dia inválido quinta-feira 14|outubro|2001 Dia inválido (quinta-feira 14) 1 / 0
dia inválido (muito grande para o mês) 31|setembro|2001 Dia inválido (31 setembro) 1 / 0
só o ano ||2001 1 / 0
só o ano com qualificador ||2001|na literatura 1 / 0
sem ano 14|outubro 0 / 0
só o dia 14 0 / 0
só o mês |Outubro outubro 0 / 0
sem argumento 0 / 0
data do calendário juliano 1|outubro|2001|juliano=sim 1 outubro 2001 ( dentro do calendário gregoriano)
Data do calendário juliano (mudança do mês) 25|outubro|2001|juliano=sim 25 outubro 2001 ( dentro do calendário gregoriano)
Data do calendário juliano (mudança do ano) 25|dezembro|2001|juliano=sim 25 dezembro 2001 ( dentro do calendário gregoriano)
data de nascimento 14|outubro|2001|idade=sim (17 anos)

Comparação com {{ani}}[editar código-fonte]

  • as funções caras são as mesmas que as do modelo Data
  • sem idade, veja a comparação com {{Date}}
Motivo testado Cadeia testada Predefinição Ani Módulo
simples 1|8|2006|idade=sim 2009 de agosto de 1 (2017 anos) (12 anos)
com qualificativo 1|agosto|2006|na Suíça|idade=sim 1 de agosto de 2006 (12 anos) (12 anos)
data antiga 2|1|598|idade=sim 2 de janeiro de 598 (1420 anos) (1420 anos)
o ano anterior 2|1|2012|idade=sim 1 de fevereiro de 2012 (6 anos) (6 anos)
este ano 2|1|2013|idade=sim 2 de janeiro de 2013 (5 anos) (5 anos)
ano que vem 2|1|2014|age=sim (4 anos)
sem dia |8|2006|idade=sim agosto de 2009 (9 anos) (12 anos)
ano único ||2006|idade=sim 2006 (11–12 anos)

Comparação com date sport[editar código-fonte]

  • quando não há qualificador, "in sport" é adicionado para testar o módulo.
Motivo testado Cadeia testada Predefinição date sport Módulo Funções custosas
predefinição / módulo
simples 1|2|1980 1|2|1980}} 1 / 0
com qualificativo 12|2|1980|na ginástica 12|2|1980|na ginástica}} 2 / 0
qualificador com possível página para este ano 12|2|1977|na ginástica 12|2|1977|na ginástica}} 3 / 1
com qualificativo e idade 12|2|1980|na ginástica|age=sim 12|2|1980|na ginástica|age=sim}} 2 / 0
data antiga 12|2|1843 12|2|1843}} 1 / 0
data muito recente com página mensal 12|2|2006 12|2|2006}} 1 / 0
data muito recente sem página mensal e qualif 12|2|2006|na ginástica 12|2|2006|na ginástica}} 2 / 0
data muito recente sem página mensal 1|8|2013 1|8|2013}} 1 / 1
data muito recente sem página mensal
e qualificado com a página anual possível
1|8|2013|na ginástica 1|8|2013|na ginástica 3 / 2

dataInfobox( frame )[editar código-fonte]

Função destinada a infoboxes, especialmente para exibir as datas de nascimento e morte, os links presentes nas datas fornecidas são automaticamente excluídos para gerenciar casos em que o parâmetro já contenha um modelo de data. O conteúdo do parâmetro após a data (por exemplo, um local, uma referência) é mantido.

Parâmetros[editar código-fonte]

  • 1: tipo de data a exibir (nascimento / n, morte / m ou data / d)
  • 2: data ou data de nascimento
  • 3: Data da morte, se o tipo n ou m
  • qualifier: sufixo das páginas de data para link (exemplo: na música)
  • nolinks: não mostra link
  • prefixo : prefixo a ser exibido se houver um dia (padrão vazio)
  • prefixo sem dia: prefixo a ser exibido se não houver dia (padrão vazio)

Esses parâmetros devem estar diretamente na função de chamada #invoke.

Exemplos[editar código-fonte]

  • {{#invoke:Data|dataInfobox|data|13 de julho de 1927}}→ 13 de julho de 1927
  • {{#invoke:Data|dataInfobox|nascimento|13 de julho de 1927|}}→ 13 de julho de 1927
  • {{#invoke:Data|dataInfobox|nascimento|13 de julho de 1927|14 mai 2017}}→ 13 de julho de 1927
  • {{#invoke:Data|dataInfobox|nascimento|30 de junho de 2017-}}→ 30 de junho de 2017-
  • {{#invoke:Data|dataInfobox|morte|13 de julho de 1927|30 de junho de 2017}}→ 30 de junho de 2017
  • {{#invoke:Data|dataInfobox|morte||30 de junho de 2017}}→ 30 de junho de 2017
  • {{#invoke:Data|dataInfobox|morte|13 de julho de 1927|}}
  • {{#invoke:Data|dataInfobox|data|13 de julho de 1927| qualificativo = na França}}→ 13 de julho de 1927
  • {{#invoke:Data|dataInfobox|data|13 de julho de 1927| préfixe = le}}→ 13 de julho de 1927
  • {{#invoke:Data|dataInfobox|data|13 de julho de 1927| préfixe = le|préfixe sans jour = en}}→ 13 de julho de 1927
  • {{#invoke:Data|dataInfobox|data|julho de 1927| préfixe = le}}→ julho
  • {{#invoke:Data|dataInfobox|data|julho de 1927| préfixe = le | préfixe sans jour = en}}→ julho
  • {{#invoke:Data|dataInfobox|data|13 de julho de [[1927]]}}→ 13 de julho de 1927
  • {{#invoke:Data|dataInfobox|data|13 de julho de [[1927 na França|1927]]}}→ 13 de julho 1927
  • {{#invoke:Data|dataInfobox|data|{{data|13 de julho de 1927|na França}}}}O primeiro parâmetro é necessário, mas foi fornecido incorretamente! de 13 de julho de 1927

Outra documentação:

local fun = {}

local Ferramentas = require 'Módulo:Ferramentas'
-- carregando o banco de dados listando algumas páginas existentes para evitar "ifexist".
local dataLinks
local success, resultado = pcall ( mw.loadData, 'Módulo:Data/Dados' )
if success then
    dataLinks = resultado
else
    -- proteção no caso ou sub módulos serem mal modificados
    dataLinks = { [''] = { mes = { vazio = 1000, todos = { 1773, 2014 } }, } }
end

-- limpa um parâmetro sem nome (vira os espaços no começo e no fim)
-- voltar nil se o texto estiver vazio ou não estiver enviando mensagens de texto. A atenção é importante para a função que a utiliza.
local trim = Ferramentas.trim

-- Função destinada a meter a primeira letra do mês em minúscula do mês :
-- uso de string porque nenhum mês começa com uma letra não ascii em português ou inglês.
local function lcfirst( str )
    return str:sub( 1, 1 ):lower() .. str:sub( 2 )
end


-- lista de meses, escritas exatamente com alias, em minúscula
local listaMes = {
    { num = 1,    nDia = 31, abrev = 'jan.',    nome = 'janeiro', alias = { 'jan.', 'jan.', 'jan', 'janeiro', 'january'} },
    { num = 2,    nDia = 29, abrev = 'fev.',     nome = 'fevereiro', alias = { 'fevereiro', 'fev.', 'fev', 'february'} },
    { num = 3,    nDia = 31, abrev = 'mar.',     nome = 'março', alias = { 'mar.', 'mar', 'março', 'march' } },
    { num = 4,    nDia = 30, abrev = 'abr.',     nome = 'abril', alias = { 'abr.', 'abr','abril', 'april' } },
    { num = 5,    nDia = 31, abrev = 'maio',      nome = 'maio', alias = { 'maio', 'may' } },
    { num = 6,    nDia = 30, abrev = 'jun.',     nome = 'junho', alias = { 'jun', 'june' } },
    { num = 7,    nDia = 31, abrev = 'jul.', nome = 'julho', alias = { 'jul.', 'july' } },
    { num = 8,    nDia = 31, abrev = 'ago.',     nome = 'agosto', alias = { 'ago', 'august' } },
    { num = 9,    nDia = 30, abrev = 'set.',    nome = 'setembro', alias = { 'set', 'set.', 'setembro', 'september' } },
    { num = 10, nDia = 31, abrev = 'out.',     nome = 'outubro', alias = { 'out', 'out.', 'october' } },
    { num = 11, nDia = 30, abrev = 'nov.',     nome = 'novembro', alias = { 'nov', 'nov.', 'november' } },
    { num = 12, nDia = 31, abrev = 'dez.',     nome = 'dezembro', alias = { 'dezembro',  'dez.', 'dez', 'december' } },

}

-- adicionar nomes, abreviaturas e aliases como uma lista de keyMonth listaMes
for i = 1, 12 do
    local mes = listaMes[ i ]
    listaMes[ tostring( i ) ] = mes
    listaMes[ '0' .. i ] = mes
    listaMes[ mes.nome ] = mes
    listaMes[ mes.abrev ] = mes
    for _, n in ipairs( mes.alias ) do
    listaMes[ n ] = mes
    end
end
--for _, n in ipairs( listaMes.aout.alias ) do
--    listaMes[ n ] = listaMes.aout
--end
fun.listaMes = listaMes

local lista_estacao = {
    { 'Primavera', 'spring', },
    { 'Verão', 'summer', },
    { 'Outono', 'autumn', },
    { 'Inverno', 'winter', },
}

---
-- validadar que a string passada é uma valida.
-- devolver o nome completo ou nil se não for reconhecido
-- se reconhecido, também retorna o número de mes [1-12]
function fun.validaMes( mes )
    local m = trim( mes )
    if m then
        m = mw.ustring.lower( m )
        if listaMes[ m ] then
            return listaMes[ m ].nome, listaMes[ m ].num
        end
    end
end

---
-- validar que a string passada é uma estação valida.
-- devolver o nome completo ou nil se não for reconhecido
function fun.validaEstacao( estacao )
    local s = trim( estacao )
    if s then
        s = mw.ustring.lower( s )
        for i = 1, 4 do
            for _, n in ipairs( lista_estacao[i] ) do
                if s == n then
                    return lista_estacao[i][1]
                end
            end
        end
    end
end

---
-- determinationMes encontrar o número do mes e seu nome,
-- do seu nome, seu número ou uma expressão matemática.
-- Se o segundo parâmetro for true, números maiores que 12 ou não inteiros serão aceites.
function fun.determinationMes( mes, mod, laco )
    local num, nome
    if tonumber( mes ) then
        num = math.floor( tonumber( mes ) )
        if mod then     
            -- se o número de mes é calculado por uma expressão, o resultado pode ser maior que 12, ou menor que 1
            num = math.fmod( num + 239, 12 ) + 1  -- +239 car fmod(-1) = -1 et non 11
        elseif num < 1 or num > 12 then
            num = nil
        end
    elseif trim( mes ) then
        nome, num = fun.validaMes( mes )
        if nome == nil and laco == nil then
            -- tente determinar um número com o analisador #expr do Mediawiki.
            -- o parâmetro laco evita o loop.
            nome, num = fun.determinationMes( mw.getCurrentFrame():callParserFunction( '#expr', mes ), true, true )
        end
    end
    if num and not nome then
        nome = listaMes[ num ].nome
    end
    return nome, num
end


--  função interna para modelData, para determinar se podemos fazer sem ifexitif
local function existData( dataQualificativo, ano, mes )
    local data
    if mes then
        data = dataQualificativo.mes
    else
        data = dataQualificativo.ano
    end
    if type( data ) ~= 'table' then
        -- Se os dados não existem, considera-se que não há link.
        return
    end
    -- o qualificador é substituído pelo do banco de dados, que permite aliases.
    local link = ano
    if dataQualificativo.qualificativo then
        link = link .. ' ' .. dataQualificativo.qualificativo
    end
    local singular = ano
    if mes then
        link = mes .. ' de ' .. link
        singular =      mes .. ' de ' .. ano
    end
    local vazio = tonumber( data.vazio )
    if vazio and ano <= vazio then
        -- se o ano está na parte "não", testamos se ainda há um link isolado
        if type( data.singular ) == 'table' then
            for i, v in ipairs( data.singular ) do
                if singular == v or singular == tonumber( v ) then
                    return link
                end
            end
       end
       -- parte não e nenhum link => nada
       return nil
       elseif type( data.todos ) == 'table' then
           local todos1, todos2 = tonumber( data.todos[1] ), tonumber( data.todos[2] )
           if todos1 and todos2 and ano >= todos1 and ano <= todos2 then
               -- o ano está no partido 'todos' então retornamos o link
               return link
           end
       end
       -- o ano não está nem na parte nem na parte de todos, então você tem que testar se a página existe.
       local alvoLink = mw.title.new( link )
       if alvoLink and alvoLink.exists then
           return link
       end
end

---
-- Exclui o dia da semana e "o" antes de um dado
function fun.limpezaDia( dia )
    if type( dia ) == 'string' then
        local nomeDia = { '[Ss]egunda-feira', '[Tt]erça-feira', '[Qq]uarta-feira', '[Qq]uinta-feira', '[Ss]exta-feira', '[Ss]ábado', '[Dd]omingo', '^ *[Oo]' }
        for i, v in ipairs( nomeDia ) do
            dia = dia:gsub( v, '' )
        end
        dia = trim( dia )
    end
    return dia
end

---
-- Separa uma cadeia de data numa tabela com campos dia, mes e ano.
-- os dados devem conter o mês.
function fun.separationDiaMesAno( data )
    data = trim( data )
    if data then
        local function erro( periode, valor )
        return false, '<span class="error">' .. periode .. ' invalida (' .. valor .. ')</span>'
    end
    local dia, mes, ano, esconderMes, esconderAno, separador
    -- variável para construir as regex
    local j = '([0-3]?%d)'          -- dia
    local m = '([01]?%d)'         -- mês numérico
    local mmm =  '([^%s%p%d]+[.]?)' -- mês em todas as  letras
    local aj = '(%-?%d+)'         -- ano ou dia
    local s = '[ ./-de]+'          -- separador simples
--  local sep = '([ ./-de]+)'      -- separador com capture, para detectá-lo duas vezes que não é necesário
    local menos = '(%-?)'          -- o sinal menos para indicar que esses dados não devem ser exibidos
    local regexb = {
        jmmm = '^'..j..s..mmm..menos..'$',
        mmmjva = '^'..mmm..s..j..', ?'..aj..'$',
    }
  
    data = fun.limpezaDia( data )
    -- excluir categoria, links, tags
    data = mw.ustring.gsub( data, '%[%[[Cc]ategor[yi]a?:.-%]%]', '' )
    data = data    :gsub( '%b<>', '' )
            :gsub( '%[%[([^%[%]|]*)|?([^%[%]]*)%]%]', function ( l, t ) return trim( t ) or l end )
    -- remoção de espaços não quebráveis
            -- nbsp
            :gsub( '\194\160', ' ' )
            :gsub( '&nbsp;', ' ' )
            :gsub( '&#160;', ' ' )
            -- narrow nbsp
            :gsub( '\226\128\175', ' ' )
            :gsub( '&#8239;', ' ' )
            -- thin space
            :gsub( '\226\128\137', ' ' )
            :gsub( '&thinsp;', ' ' )
            :gsub( '&#8201;', ' ' )
            -- simple space
            :gsub( '&#32;', ' ' )
            -- vários espaços
            :gsub( ' +', ' ' )
    -- redução a.C. para simplificar um pouco de regex:
            :gsub( '(%d+) ?[Aa]%.? ?C%.?', '-%1' )
    -- exclusão de horas em dados ISO
            :gsub( '^+?([%d-]*%d%d%-%d%d)T%d%d[%d:,.+-]*Z?$' , '%1')
  
    -- teste de um ano
    if data:match( '^'..aj..'$' ) then
        ano = data:match( '^'..aj..'$' )
    elseif data:match( '^'..aj..s..aj..menos..'$' ) then
        -- dd/mm, mm/aaaa ou aaaa/mm
        local a, separador, b, sb = data:match( '^'..aj..s..aj..menos..'$' )
        a, b = tonumber( a ), tonumber( b )
        if separador:match( '^.+%-$' ) then
            -- provavelmente mm/-aaaa, ano a.C.
            b = 0 - b
        end
        if  a > 12 and ( b < 1 or b > 31 ) or
            b > 12 and ( a < 1 or a > 31 ) then
            return erro( 'Data', data )
        elseif b < 1 or b > 31 then
            mes, ano, esconderAno = a, b, sb
        elseif a < 1 or a > 31 then
            ano, mes  = a, b
        elseif b > 12 then
            return erro( 'Mes', b )
        else
            dia, mes, esconderMes = a, b, sb
        end
    elseif data:match( '^'..aj..s..m..menos..'%2'..s..aj..menos..'$' ) then
        -- dd/mm/aaaa ou aaaa/mm/dd
        dia, separador, mes, esconderMes, ano, esconderAno =     data:match( '^'..aj..s..m..menos..'%2'..s..aj..menos..'$' )
        if separador == '-' and esconderMes == '-' and
        esconderAno == '' and tonumber( ano ) > 0 then
            -- data no formato dd-mm--aaaa type 17-06--44 para 17 junho 44 a.C.
            esconderMes = nil
            ano = 0 - ano
        end
    elseif data:match( '^'..j..s..mmm..menos..'%2'..s..aj..menos..'$' ) then
        -- dd mmm aaaa
        dia, separador, mes, esconderMes, separador, ano, esconderAno = data:match( '^'..j..s..mmm..menos..'%2'..s..aj..menos..'$' )
    elseif data:match( '^'..mmm..s..aj..menos..'$' ) then
        -- mmm aaaa
        mes, separador, ano, esconderAno = data:match( '^'..mmm..s..aj..menos..'$' )
        if separador:match( '^.+%-$' ) then
            ano = '-' .. ano
        end
    elseif data:match( '^'..j..s..mmm..menos..'$' ) then
        -- dd mmmm
        dia, mes, esconderMes = data:match( '^'..j..s..mmm..menos..'$' )
    elseif data:match( '^'..mmm..s..j..', ?'..aj..'$') then
        -- mmm dd, aaaa (formato anglo-saxão)
        mes, dia, ano = data:match( '^'..mmm..s..j..', ?'..aj..'$')
    elseif data:match( '^'..mmm..'$' ) then
        mes = data
    else
        return erro( 'Data', data )
    end
    local jn, an = tonumber( dia ), tonumber( ano )
    if jn and an and ( jn > 31 or
        jn < 0 or #dia >= 3 ) and an <= 31 then
        -- caso particular dos dados ISO 2015-06-17, -0044-06-17 e -0002-06-17
        -- inversão do dia e do ano
        local temp = ano
        ano = dia
        dia = temp
    end
  
    return fun.validationDiaMesAno{
        dia, mes, ano,
        esconderAno = trim( esconderAno ) and true or nil,
        esconderMes = ( trim( esconderAno ) or not ano ) and
    trim( esconderMes ) and true or nil,
        -- or nil serve apenas para evitar arrastar um valor falso em todos os testes unitários.
    }
    else
        return true, {}
    end
end


---
-- validationDiaMesAno verifica os parâmetros correspondentes a uma cadeia valida de dados.
-- os dados podem estar nos parâmetros 1 a 3, ou nos parâmetros dia, mes e ano.
-- A função retorna true seguida por uma tabela com os dados em parâmetros nomeados (sem foco no ano)
-- ou falso seguido por uma mensagem de erro.
function fun.validationDiaMesAno( frame, ... )
    local args = Ferramentas.extractArgs( frame, ... )
    local dia, mes, numMes, ano
    local bdia = args[1] or args['dia'] or ''
    local bmes = tostring( args[2] or args['mês'] or args['mes'] or '' )
    local bano = args[3] or args['ano'] or args['year'] or ''
 
    local function erro( periode, valor )
        return false, '<span class="error">' .. periode .. ' inválido (' .. valor .. ')</span>'
    end
 
    -- agora tratamos o ano
    if Ferramentas.notEmpty( bano ) then
        ano = tonumber( bano )
        if ano == nil and type( bano ) == 'string'  then
            -- teste se o ano contiver a.C.
            ano = string.match( string.upper( bano ), '^(%d+) ?[Aa]%.? ?[Cc]%.?' )
            ano = tonumber( ano )
            if ano then
                ano = 0 - ano
            else
                return erro( 'Ano', bano )
            end
        elseif ano == 0 then
           return erro( 'Ano', 0 )
        end
    else
        ano = nil
    end
 
    -- agora tratamos o mês
    if Ferramentas.notEmpty( bmes ) then
        mes, numMes = fun.determinationMes( bmes )
        if mes == nil then
            mes = fun.validaEstacao( bmes )
            if mes == nil then
                return erro( 'Mês', bmes )
            end
        else  
            -- agora tratamos o dias se está informado
            if Ferramentas.notEmpty( bdia ) then
                dia = tonumber( bdia )
                if dia == nil then
                    dia = tonumber( fun.limpezaDia( bdia ) )
                end
                if dia == nil then
                    return erro( 'Dia', bdia )
                end
                -- agora verifica se dia está bem
                if dia < 1 or dia > 31 then
                    return erro( 'Dia', bdia )
                elseif dia > listaMes[numMes].nDia then
                    return erro( 'Dia', bdia .. ' ' .. mes )
                elseif dia == 29 and numMes == 2 and
                ano and ( math.fmod( ano, 4 ) ~= 0 ) then
                    -- o ano bisexto nos séculos é de todos os dias
            -- aceite para ser compatível com dados julianos.
                    return erro( 'Dia', '29 de fevereiro de ' .. ano     )
                end
            else
                -- Se não houver dia, confirma se a primeira letra do mes é minúscula
                if bmes:match( '^%u' ) then
                    -- sim, passamos a primeira letra em letras minúsculas
            -- mas precisamos ver se idioma é pt-ao ? em falta
--                  mes = lcfirst( mes )
                end
                -- se não houver ano, retornamos o mês simples
            end
        end
    else
        -- verificamos o dia se está informado
        if Ferramentas.notEmpty( bdia ) then
            if ano then
                return erro( 'Mês', 'não informado' )
            else
                bdia = fun.limpezaDia( bdia )
                dia = tonumber( bdia )
                if dia then
                    if dia > 31 or dia < 1 then
                        ano = dia
                        dia = nil
                    else
                        return erro( 'Data', 'dia único : ' .. bdia )
                    end
                else
                    return erro( 'Dia', bdia )
                end
            end
        end
    end
 
    -- verificação da ausência de desvio
    if ano and ano < 13 and ano > 0 and
        not dia and ( tonumber( bmes ) or
    (not mes and tonumber( args[4] ) ) ) then
        return false, '<span class="error">ano improvável (' .. ano .. ')</span>'
    end
  
    local resultado = {
    dia = dia,
    mes = mes,
    numMes = numMes,
    ano = ano,
    esconderAno = args.esconderano,
    esconderMes = args.escondermes,
    }
    return true, resultado
end


---
-- emula a predefinição {{tl|Data}}.
-- Configurações:
-- 1: dia (número) ou os dados completos
-- 2: mês (na íntegra) ou estação do ano
-- 3: ano (número)
-- 4: estação do ano
-- juliano: dados no calendário juliano
-- compacto: exibe o mês como uma abreviatura
-- ad: não para desativar a exibição de "a.C." para dados negativos
-- idade: adicione a duração desde que esses dados
-- nolink: não coloque um link nos dados
-- nascimento: adicione a classe "bday"
-- dead: adicione a classe "dday"
function fun.modeloData( frame )
    local args = Ferramentas.extractArgs( frame )
    local cat, resultado = ''
 
    -- analisar parâmetros sem nome (ou parâmetros de dados dia, mês, ano)
    local test, params
    local arg1, arg2, arg3 = fun.limpezaDia( args[1] ), trim( args[2] ), trim( args[3] )
    if type( arg1 ) == 'string' and arg3 == nil and
        ( arg1:match( '[^ ./-][ ./-]+[^ ./-]' ) or
    arg2 == nil or dataLinks[arg2] or
    mw.ustring.match( arg2, '%a %a' ) ) then
        -- os dados estão no primeiro parâmetro
        test, params = fun.separationDiaMesAno( arg1 )
        if test then
            params.qualificativo = arg2
        end
    else
        local function esconderParam( p )
            -- separa o possível sinal de menos significando
        -- que o parâmetro não deve ser exibido.
            if type( p ) ~= 'string' then
                return p, nil
            end
            local value, mask = p:match( '^%s*(.-)(%-?)%s*$' )
            return value, ( mask == '-' or nil )
        end
        local cleanArgs = { arg1 or args.dia }
        cleanArgs[2], cleanArgs.escondermes = esconderParam( args[2] or args.mes )
        cleanArgs[3], cleanArgs.esconderano = esconderParam( args[3] or args.ano )
  
        test, params = fun.validationDiaMesAno( cleanArgs )
        if test then
            params.qualificativo = trim( args[4] )
        end
    end
 
    -- analisar os parâmetros nomeados
    if test then
        local Yesno = require 'Módulo:Yesno'
        params.qualificativo = params.qualificativo or args.qualificativo
        -- Juliano pode ter três valores: inativo, formato padrão (true), formato curto
        params.juliano = Yesno( args.juliano, 'curto', false )
        params.ac = Yesno( args.ac )
      
        local listaParam = {
            idade = 'idade',
            nascimento = 'nascimento',
            morte = 'morte',
            falecido = 'morte',
            ac = 'a.C.',
            nolinks = 'nolinks',
            compacto = 'compacto',
            compacta = 'compacto',
        }
        for n, v in pairs( listaParam ) do
            params[v] = params[v] or Yesno( args[n], true, false ) or nil
        end
  
        -- saída para testes unitários ou para depurar
        if args.debug then
            return params
        end
  
        resultado = fun._modeloData( params )

    else
        local namespaceCategorisation = { [0] = true, [4] = true, [10] = true, [14] = true, [100] = true }
        if namespaceCategorisation[ mw.title.getCurrentTitle().namespace ] and
        not Ferramentas.notEmpty( args.nocat ) then
            cat = '[[Categoria:!Páginas que usam a predefinição data com erros de sintaxe]]'
        end
        resultado = params .. cat
    end
 
    return resultado or ''
end

function fun._modeloData( args )
    local ano, mes, numMes, dia = args.ano, args.mes, args.numMes, args.dia
    local qualificativo = args.qualificativo
 
    if ( ano or mes or dia ) == nil then
        return
    end
 
    -- agora tratamos a idade, o nascimento e a morte
    local idade = args['idade'] and  fun.idade( ano, numMes, dia )
    local nascimento = args.nascimento
    local morte = args.morte
 
    -- tratar o calendário
    local gano, gmes, gdia = ano, numMes, dia    -- dados de acordo com o calendário gregoriano para <hora>
    local jano, jmes, jdia = ano, mes, dia      -- dados de acordo com o calendário juliano, se necessário
    local julianoData, julianoSup, julianoSep         -- pode ser usado para exibir os dados de acordo com o calendário juliano
    local gregAprMes, gregAprAno, gregFim       -- Mensagem do calendário gregoriano quando os dados estão de acordo com o calendário juliano
    if ano and dia then
        local amj = ano * 10000 + numMes * 100 + dia
    if amj < 15821014 then
        if ano > 0 then
            gano, gmes, gdia = fun.julianToGregorian( ano, numMes, dia )
        else
            -- Calendário gregoriano proléptico com ano 0.
            gano, gmes, gdia = fun.julianToGregorian( ano + 1, numMes, dia )
        end
        args.juliano = false
  
    elseif args.juliano then
        gano, gmes, gdia = fun.julianToGregorian( ano, numMes, dia )
        ano, mes, dia = gano, listaMes[gmes].nome, gdia
        if args.compacto then
            jmes = listaMes[ jmes ].abrev
        end
        if args.juliano == 'curto' then
            julianoData = jdia .. ' ' .. jmes .. ' '
            julianoSup = '<sup>[[calendário juliano|jul.]]</sup>'
            if jano == ano then
               gregAprMes = '<sup>[[calendário gregoriano|greg.]]</sup>'
            else
               julianoData = julianoData .. jano .. ' '
               gregAprAno = '<sup>[[calendário gregoriano|greg.]]</sup>'
            end
            julianoSep = ' / '
        else
            julianoData = jdia .. ' ' .. jmes .. ' ' .. jano
            julianoSep = ' ('
            gregFim = ' [[Mudança para o calendário gregoriano|dentro do calendário gregoriano]])'
        end
    end
    else
       if ano and ano < 0 then
           gano = gano + 1
       end
       args.juliano = false
 
    end
 
    -- agora geramos o resultado
 
    -- Declarações de variáveis
    local wikiLista = {}      -- recebe a mensagem de texto exibida para cada parâmetro
    local iso = {}            -- recebe o formato de data ISO de cada parâmetro
    local textoMes = mes      -- mensagem de texto que será exibida (possivelmente a abreviação)
    if args.compacto then
        if args.nolinks then
            textoMes = '<abbr class=abbr title="' .. mes .. '">' .. listaMes[ mes ].abrev .. '</abbr>'
        else
            textoMes = listaMes[ mes ].abrev
        end
    end
 
    local dataQualificativo, dataCat
    if not args.nolinks then
        dataQualificativo = dataLinks[qualificativo or '']
        if type( dataQualificativo ) ~= 'table' then
            -- se o qualificador não estiver no banco de dados, criamos uma tabela mínima,
            -- que vai impor um teste no ano, mas considera que não há link no dia ou no mes
            dataQualificativo = { qualificativo = ' ' .. qualificativo, ano = { } }
        end
        dataCat = dataLinks[dataQualificativo.cat]
        if type( dataCat ) ~= 'table' or dataCat == dataQualificativo then
            dataCat = { qualificativo = '' }
        end
    end
    local function wikiLink( link, texto )
        if link == texto then
            return '[[' .. texto .. ']]'
        else
            return '[[' .. link .. '|' .. texto .. ']]'
        end
    end
 

    -- o dia se informado
    local qualifDia = ''
    if dia then
        local textoDia = dia
        if args.nolinks then
            table.insert( wikiLista,  dia )
        else
            qualifDia = dataQualificativo.dia and
        dataQualificativo.qualificativo or dataCat.dia and
        dataCat.qualificativo or ''
            local link = dia .. ' de ' .. mes .. ' ' .. qualifDia
            -- se não houver um link no mes, ele será exibido com o dia.
            table.insert( wikiLista,  wikiLink( link, dia .. ' de ') ) -- faltava o de
            table.insert( wikiLista,  wikiLink( link, dia .. ' de '.. textoMes ) )
        end
        table.insert( iso,  1, string.sub( '0' .. gdia, -2 ) )
    end
 
    -- o mês
    if mes then
        if #wikiLista == 0 and ano == nil then
            return textoMes
        end
        if args.nolinks then
            if not args.escondermes then
                table.insert( wikiLista,  textoMes )
            end
        else
            local link
            if ano then
                link = existData( dataQualificativo, ano, mes ) or existData( dataCat, ano, mes )
                if link == nil and qualificativo and qualifDia == '' then
                    -- teste novo teste sem o qualificador somente se não houver efemérides para esse qualificador.
                    link = existData( dataLinks[''], ano, mes )
                end
            end
            if link or args.escondermes then
            -- se houver um link, remova o link que exibe 'dia mes' para adicionar 'Mês dia'
            table.remove( wikiLista )
            if not args.escondermes then
                table.insert( wikiLista,  wikiLink( link, textoMes ) )
            end
        elseif #wikiLista > 0 then
            -- caso contrário, removemos o link exibindo 'dia' para manter apenas o link 'dia mês'
            table.remove( wikiLista, #wikiLista - 1 )
        elseif args.esconderano then
            -- se não houver dia e o ano não for exibido, insira o único
        textoMes = textoMes    :gsub( ' de ', '' ) -- remover o de extra
            table.insert( wikiLista,  textoMes )
        end
    end
    if gmes then
        table.insert( iso,    1, string.sub( '0' .. gmes, -2 ) )
        table.insert( wikiLista, ' de ' ) -- está certo acrescentar aqui?
    end
    table.insert( wikiLista, gregAprMes )
    end
 
    -- o ano
    if ano and not (args.juliano == true and args.nolinks and jano == ano ) then
        if not args.esconderano then
            local textoAno = ano
            local link
            if ano < 0 then
                local anoaC = 0 - ano
                link = link or ( anoaC .. ' a.C.' )
            if args.ac == false then
                textoAno = anoaC
            else
                textoAno = anoaC .. ' <abbr class="abbr" title="'
                .. anoaC .. ' antes da Era Comum">a.C.</abbr>'
            end
        elseif args.ac then
            textoAno = textoAno .. ' <abbr class="abbr" title="'
            .. textoAno .. ' depois da Era Comum">depois de a.C.</abbr>'
        end
        if args.nolinks then -- somente se tivermos que exibi-lo
            table.insert( wikiLista,  textoAno )
        else
            link = existData( dataQualificativo, ano ) or
        existData( dataCat, ano ) or link or ano     
        if mes and #wikiLista == 0 then
            -- se o mes não tiver link e não for exibido com o dia, ele será exibido com o ano.
            textoAno = textoMes .. ' de ' .. textoAno
        end
        table.insert( wikiLista,  wikiLink( link, textoAno ) )
        end
    end
    end
    if ano then
       if gano > 999 then
             table.insert( iso,    1, gano )
       elseif gano > -1 then
             table.insert( iso,    1, string.sub( '000' .. gano , -4 ) )
       elseif gano > -999 then
           -- Calendário gregoriano proléptico com ano 0.
          table.insert( iso,    1, 'U-' .. string.sub( '000' .. ( 0 - gano ), -4 ) )
       else
          table.insert( iso,    1, 'U' .. gano )      
       end
    end
    table.insert( wikiLista, gregAprAno )

    -- a idade
    if type( idade ) == 'number' and idade >= 0 and ( not nascimento or idade < 120 ) then
    if idade == 0 then
        idade = '(menos de um ano)'
    elseif idade == 1 then
        idade = '(1 ano)'
    else
        idade = '(' .. idade .. ' anos)'
    end
    else
    idade = false
    end
 
 
    -- compilação dos resultados
    local wikiTexto = table.concat( wikiLista, ' ' )
    local isoTexto = table.concat( iso, '-' )
 
    -- Nós adicionamos um pouco de semântica.
    local wikiHtml = mw.html.create( '' )
 
    if julianoData then
    wikiHtml:tag( 'span')
        :addClass( 'nowrap' )
        :attr( 'date-sort-value', isoTexto )
        :wikitext( julianoData    )
        :node( julianoSup )
        :done()
        :wikitext( julianoSep )
    end
 
    local dataHtml = wikiHtml:tag( 'time' )
        :wikitext( wikiTexto )
    if wikiTexto:match( ' ' ) then
        dataHtml:addClass( 'nowrap' )
    end
    if isoTexto ~= wikiTexto then
        dataHtml:attr( 'datetime', isoTexto )
            :attr( 'date-sort-value', isoTexto )
    end
    if not args.nolinks then
        dataHtml:addClass( 'date-link' )
    end
    if nascimento then
        dataHtml:addClass( 'bday' )
    elseif morte then
        dataHtml:addClass( 'dday' )
    end
 
    wikiHtml:wikitext( gregFim )
 
    if idade then
        wikiHtml:wikitext( ' ' )
            :tag( 'span' )
            :addClass( 'noprint')
            :wikitext( idade )
            :done()
    end
 
    return tostring( wikiHtml )
end


---
-- função para infoboxes, especialmente para exibir nascimento e dados mortos
-- os links presentes nos dados fornecidos são automaticamente excluídos para gerenciar os casos ou
-- o parâmetro já contém um modelo de dados.
-- Configurações:
--      1 : type de dados a afixar (nascimento / n, morte / m, ou data / d)
--      1 : Data ou data de nascimento
--      2 : Data de morte se tipo n ou m
--      qualificativo = sufixo de páginas de dados para vincular (exemplo: na música)
--      nolinks : não mostrar link
--      préfixe : prefixo para exibir se houver um dia (por padrão '')
--      prefixo sem dia: prefixo a ser exibido se não houver dia (padrão: '')
function fun.dataInfobox( frame )
    local args = frame.args
    if type( args ) ~= 'table' or not ( args[1] and args[2] ) then
        return
    end
 
    -- analisarData separa os dados do conteúdo a seguir, exclui os links e, se possível, retorna uma tabela com os anos
    local function analisarData( d )
        if trim( d ) then
            local analisar = d:match( ' ou ') or d:match( 'entre ' ) or d:match( 'para ' ) or d:match( 'depois ' ) or d:match( 'antes ' )
            if analisar then
                return d
            end
            analisar = d:match( 'datetime="([%d-]+)"' ) or d
            -- separa os dados (com seus links) de uma referência ou conteúdo que começa com um espaço)
            local inicio, fim = analisar:match( '(.-%d%d%d%]*%-?)([\127 ].+)' )
            if not inicio then
                -- separa os dados do conteúdo começando com <br>
                inicio, fim = analisar:match( '(.-%d%d%d%]*%-?)(<br ?/?>.+)' )
            end
            analisar = inicio or analisar
            -- excluir links
            analisar = analisar:gsub(
            '%[%[([^%[%]|]*)|?([^%[%]]*)%]%]',
            function ( l, t )
                return trim( t ) or l
            end
            )
            local t, r = fun.separationDiaMesAno( analisar )
            if t then
                return r, fim
            else
                return d, fim
            end
        end
    end
    -- prefixo adiciona um prefixo dependendo da presença ou ausência do dia se o parâmetro "prefixo sem dia" for definido
    local function prefix( dataString )
    if dataString then
        local datetime = dataString:match( 'datetime="([U%d%-]+)"' )
        if datetime and datetime:match('%-%d%d%-%d%d') and
        trim( args['prefixo'] ) then
            return args['prefixo'] .. ' ' .. dataString
        end
        if trim( args['prefixo sem dia'] ) then
            return args['prefixo sem dia'] .. ' ' .. dataString
        end
    end
    return dataString
    end
 
    local nascimento = args[1]:match( '^n' ) == 'n'
    local morte = args[1]:match( '^m' ) or args[1]:match( 'morte' )
    local mostrarData, qualificativo = args[2], args[4]
    local mostrarDataTab, resultadoData, complementData
    local dataNascimento, dataMorte
    if morte then
        mostrarData = args[3]
    end
    if not trim( mostrarData ) then
        return
    end
    if mostrarData:match( '</time>' ) then
        -- Se houver links, provavelmente já existe um modelo de dados, evite executá-lo uma segunda vez
        if ( nascimento or morte ) and
        ( mostrarData:match( 'wikidata%-linkback' ))  then
            dataNascimento = analisarData( args[2] )
            dataMorte = analisarData( args[3] )
            resultadoData = mostrarData
        else
            return prefix( mostrarData )
        end
    else
        mostrarDataTab, complementData = analisarData( mostrarData )
        if type( mostrarDataTab ) ~= 'table' then
            return mostrarDataTab
        else
            if nascimento then
                dataNascimento = mostrarDataTab
                dataMorte = analisarData( args[3] )
            elseif morte then
                dataNascimento = analisarData( args[2] )
                dataMorte = mostrarDataTab
            else
                qualificativo = args[3]
            end
            mostrarDataTab.nascimento = nascimento
            mostrarDataTab.morte = morte
            mostrarDataTab.qualificativo = args.qualificativo or qualificativo
            mostrarDataTab.nolinks = args.nolinks
            mostrarDataTab.nocat = args.nocat
            mostrarDataTab.juliano = args.juliano
        end
    end
    resultadoData = resultadoData or fun.modeloData( mostrarDataTab )
 
    local idade, prefixIdade, suffixIdade, calculoIdade = '', ' <span class="noprint">(', ')</span>', nil
    if nascimento and dataNascimento and not dataMorte and
        type( dataNascimento ) == 'table' then
        calculoIdade = fun.idade( dataNascimento.ano, dataNascimento.numMes, dataNascimento.dia )
        if calculoIdade and calculoIdade > 120 then
            calculoIdade = nil
        end
    elseif morte and dataNascimento and dataMorte and
        type( dataNascimento ) == 'table' and
    type( dataMorte ) == 'table' then
            calculoIdade = fun.idade(
            dataNascimento.ano,
            dataNascimento.numMes,
            dataNascimento.dia,
            dataMorte.ano,
            dataMorte.numMes,
            dataMorte.dia
        )
        prefixIdade = ' (a '
        suffixIdade = ')'
    end
    if tonumber( calculoIdade ) then
        if calculoIdade > 1 then
            idade = prefixIdade .. calculoIdade .. ' anos' .. suffixIdade
        elseif calculoIdade == 1 then
            idade = prefixIdade .. 'um ano' .. suffixIdade
        elseif calculoIdade == 0 then
            idade = prefixIdade .. 'menos de um ano' .. suffixIdade
        end
        if complementData and complementData:match( 'anos?%)' ) then
           complementData = ''
        end
    end
 
    return prefix( resultadoData ) .. ( complementData or '' ) .. idade
end


---
-- a função dataISO retorna um dado no formato aaaa-mm-dd (sem links)
-- o ano pode ser na forma 2013 ou [[2013 na literatura|2013]]
-- o mês pode estar em letra ou em número
-- o dia pode estar no formato '5',  ou 'Sexta 13'

function fun.dataISO( frame )
    local args = Ferramentas.extractArgs( frame )
    local ano = Ferramentas.notEmpty( args.ano, args.year, args.data )
    -- extração do ano
    if type( ano ) == 'string' then
        ano = ( tonumber( ano )       -- match '2013'
        or string.match ( ano, '%D(%d%d%d%d)%D' ) -- match  '[[2013 na música|2013]]'
        or string.match ( ano, '%D(%d%d%d%d)%D$' )  -- match '17 de setembro de 2013'
        or string.match ( ano, '^(%d%d%d%d)%D' )  -- match '2013-09-17'
        )
        end
    ano = tonumber( ano )
 
    -- O formato iso de dados é definido de acordo com o calendário gregoriano.
    -- Antes do ano de 1583 os dados são calendários é provavelmente do calendário juliano,
    -- então se abstenha.
    if ano and ano > 1582  then
        local mes = Ferramentas.notEmpty( args.mes, args.month )
        -- num mês encontra o número de mês, seja númerico ou texto, completo ou abreviado.
        local nomeMes, numMes = fun.determinationMes( mes )
        if numMes then
            mes = '-' .. string.sub( '0' .. numMes, -2 )
  
            local dia = Ferramentas.notEmpty( args.dia, args.day, args['calendário'] )
            if type( dia ) == 'string' then
                dia = tonumber( dia ) or tonumber( string.match ( dia, '%d+') )
            end
            dia = tonumber( dia )
            if dia and dia <= listaMes[numMes].nDia then
                dia = '-' .. string.sub( '0' .. dia, -2 )
                return ano .. mes .. dia
            else
                return ano .. mes
            end
        else
            return tostring( ano )
        end
    end
end

---
-- Rank do dia no ano
-- Uso: do_dayRank {ano, meu, dia}
function fun.do_dayRank(arguments)
    local yr = tonumber(arguments.year or arguments[1]) or 1
    local mt = tonumber(arguments.month or arguments[2]) or 1
    local dy = tonumber(arguments.day or arguments[3]) or 1
    -- Classificações do primeiro do mês
    local ranks = {0,31,59,90,120,151,181,212,243,273,304,334}
 
    local rank = (ranks[mt] or 0) + dy - 1
    if(fun.isLeapYear(yr) and (mt >= 3)) then
        rank = rank+1
    end
    return rank
end

-- Número de dias entre dois anos (de 1 de janeiro a 1 de janeiro)
-- Segue o calendário gregoriano
function fun.do_daysBetween(arguments)
    local yr1 = tonumber(arguments[1]) or 0
    local yr2 = tonumber(arguments[2]) or 0
 
    return fun.daysSinceOrigin(yr2) - fun.daysSinceOrigin(yr1)
end

-- Número de dias desde o ano 1 (de 1 de janeiro a 1 de janeiro)
function fun.daysSinceOrigin(year)
    local yr = year-1
    return 365*yr + math.floor(yr/4) - math.floor(yr/100) + math.floor(yr/400)
end

-- Teste do ano bissexto (segue o calendário gregoriano)
function fun.isLeapYear(year)
    local yr = tonumber(year) or 1
    return (yr%4 == 0) and ((yr%100 ~= 0) or (yr%400 == 0))
end

-- Convertendo um número em algarismos romanos
function fun.toRoman(number)
    local n = math.floor(number)
    local letters = {"I","V","X","L","C","D","M","",""}
    local pattern = {"","0","00","000","01","1","10","100","1000","02"}
    local result = ""
    if(n<=0 or n>=4000) then
        result = "---"
    else
        for i=1,7,2 do
            local p = pattern[n%10 + 1]
            for j=0,2 do
                p = string.gsub(p,tostring(j),letters[i+j])
            end
            result = p .. result
            n = math.floor(n/10)
        end
    end
    return result
end

---
-- Calculando um dado no calendário republicano
-- Supõe-se que os anos 4n + 3 são mais sextiles (3, 7, 11 ...)
function fun.do_toRepCal(arguments)
    local yr = tonumber(arguments.year or arguments[1]) or 2000
    -- gama absoluto do dia solicitado, sendo o dia 0 ou 22 de setembro de 1792 (1º dia do ano I)
    local repDays = fun.do_dayRank(arguments) + fun.do_daysBetween{1792,yr} - fun.do_dayRank{1792,9,22}
    local repYear = math.floor((repDays+731)/365.25) - 1
    local repDayRank = repDays - 365*(repYear-1) - math.floor(repYear/4)
    local repMonth, repDay = math.floor(repDayRank/30)+1, (repDayRank%30)+1
    return {repYear, repMonth, repDay}
end

---
-- Ver Predefinição:Idade
-- retorna a idade de acordo com os dados fornecidos. O valor retornado é do tipo 'número'
-- Parâmetros:
-- 1, 2, 3: ano, mês dia de nascimento (suposto no calendário gregoriano)
-- 4, 5, 6: year, mês, dia do cálculo (opcional, por padrão, os dados UTC atuais).
function fun.idade( an, mn, jn, ac, mc, jc )
    if ac == nil then
        local today = os.date( '!*t' )
        ac = today.year
        mc = today.month
        jc = today.day
    else
        ac = tonumber( ac )
        mc = tonumber( mc )
        jc = tonumber( jc )
    end

    local an = tonumber( an )
    local mn = tonumber( mn )
    local jn = tonumber( jn )

    if an == nil or ac == nil or mn == nil or mc == nil then
       -- nenhuma mensagem de erro que possa travar a função de chamada
       -- para ela gerenciar esse retorno.
       return
    end
 
    local idade = ac - an
    if mc == mn then
        if jc == nil or jn == nil then
            return
        end
        return idade-tonumber( jc < jn and 1 or 0 )
    else
        return idade-tonumber( mc < mn and 1 or 0 )
    end
end

function fun.modeloIdade( frame )
    local args = frame.getParent().args
    local idade = fun.idade (
    args[1] or args['ano'],
    args[2] or args['mês'] or args['mes'],
    args[3] or args['dia'],
    args[4],
    args[5],
    args[6]
    )
    if idade then
        return idade
    else
        return '<span class="error">Parâmetro incorretos ou insuficientes para calcular a precisão da idade</span>'
    end
end

---
-- calcula o dia juliano à partir de uma data do calendário gregoriano
function fun.julianDay( year, month, day, hour, min, sec )
    local julian
    julian = math.floor( math.floor( ( year * 12 + month + 57609 ) / 12 - 1 ) * 1461 / 4 )
        - math.floor( math.floor( ( year * 12 + month + 57609 ) / 12 - 1 ) / 100 )
        + math.floor( math.floor( ( year * 12 + month + 57609 ) / 12 - 1 ) / 400 )
        + math.floor( ( math.fmod( month + 57609, 12 ) + 4 ) * 153 / 5 )
        + day + ( hour or 12 ) / 24 + ( min or 0 ) / 1440 + ( sec or 0 ) / 86400
        - 32167.5
    return julian
end

---
-- cálculo do dia juliano a partir de um dado do calendário juliano
function fun.julianDayJulian( year, month, day, hour, min, sec )
    local julian
    julian = math.floor( math.floor( ( year * 12 + month + 57609 ) / 12 - 1 ) * 1461 / 4 )
        + math.floor( ( math.fmod( month + 57609, 12 ) + 4 ) * 153 / 5 )
        + day + ( hour or 12 ) / 24 + ( min or 0 ) / 1440 + ( sec or 0 ) / 86400
        - 32205.5
    return julian
end

---
-- cálculo de um dado no calendário gregoriano do dia juliano
function fun.julianDayToGregorian( julianDay )
    local base = math.floor( julianDay + 32044.5 )    -- 1 March -4800 (proleptic Gregorian data)
    local nCentury = math.floor( ( base * 4 + 3 ) / 146097 )
    local sinceCentury = base - math.floor( nCentury * 146097 / 4 )
    local nYear = math.floor( ( sinceCentury * 4 + 3 ) / 1461 )
    local sinceYear = sinceCentury - math.floor( nYear * 1461 / 4 )
    local nMonth = math.floor( ( sinceYear * 5 + 2 ) / 153 )
 
    local day = sinceYear - math.floor( (  nMonth  * 153 + 2 ) / 5 ) + 1
    local month = nMonth  - math.floor(     nMonth     / 10 ) * 12 + 3
    local year = math.floor( sinceYear / 306 ) + nYear + 100 * nCentury - 4800
 
    return year, month, day
end

---
-- cálculo de um dado no calendário juliano do dia juliano
function fun.julianDayToJulian( julianDay )
    local year = math.modf( ( julianDay * 4 - 6884469 ) / 1461 )
    local r2 = julianDay - math.modf( ( 1461 * year + 6884472 ) / 4 )
    local month = math.modf( ( 5 * r2 + 461 ) / 153 )
    local day = r2 - math.modf( ( 153 * month - 457 ) / 5 ) + 1
    if month > 12 then
        year = year + 1
        month = month - 12
    end
    return year, month, day
end

---
-- cálculo de um dado no calendário gregoriano a partir de um dado no calendário juliano
function fun.julianToGregorian( year, month, day )
    return fun.julianDayToGregorian( fun.julianDayJulian( year, month, day ) )
end

---
-- cálculo de um dado no calendário juliano a partir de um dado no calendário gregoriano
function fun.gregorianToJulian( year, month, day )
    year = tonumber(year)
    if month then month = tonumber(month) else month = 6 end --leva um valor central para dar um melhor "palpite"
        if day then day = tonumber(day) else day = 15 end
    return fun.julianDayToJulian( fun.julianDay( year, month, day ) )
end


--[[
  Esta função devolve "CET" ou "CEST" dependendo se no pseudo timezone atual
     é hora de verão ou inverno.
   Esta função só faz sentido para predefinições usados na Europa
 
   Parâmetro opcional sem nome: "sem link": retorna o texto CET / CEST. caso contrário
     retornar o mesmo texto com um wikilink para os artigos correspondentes
--]]
function fun.CEST(frame)
    -- opção : não crie wikilink
    local opt = trim(frame.args[1] or frame:getParent().args[1])
    -- recuperamos as informações na zona atual
    local t = mw.getContentLanguage():formatDate("I", nil, true)
 
    if (t == "1") then    -- hora de Verão
        if (opt == "sem link") then
            return "CEST"
        elseif (opt == "desvio") then
            return "2"
        else
            return "[[Horário de Verão da Europa Central|CEST]]"
        end
    else  -- horário de inverno (ou outra área onde não se aplica)
        if (opt == "sem link") then
            return "CET"
        elseif (opt == "desvio") then
            return "1"
        else
            return "[[Horário da Europa Central|CET]]"
        end
    end
end

return fun