Regex para validar o formato da data dd / mm / aaaa

172

Preciso validar uma sequência de datas para o formato dd/mm/yyyycom uma expressão regular.

Este regex valida dd/mm/yyyy, mas não as datas inválidas, como 31/02/4500:

^(0?[1-9]|[12][0-9]|3[01])[\/\-](0?[1-9]|1[012])[\/\-]\d{4}$

O que é um regex válido para validar o dd/mm/yyyyformato com suporte para o ano bissexto?

Nalaka526
fonte
3
Eu acho que pode ajudar se você definir uma expectativa precisa, pois esse regex NÃO, de fato, valida corretamente os anos bissextos; por exemplo, não há 29 de fevereiro de 2013, mas esse regex afirma que isso é válido: regexr.com?346fp
TML
7
Por que com Regex? Há mais fácil (e mais precisos) maneiras ...
Dan Puzey
2
Expressões regulares são para padrões correspondentes, não para verificar valores numéricos. Encontre uma sequência provável com o regex e verifique seu valor numérico em qualquer que seja a sua linguagem host (PHP, qualquer que seja).
Andy Lester
3
Esta resposta foi adicionada às Perguntas frequentes sobre a expressão regular de estouro de pilha , em "Tarefas comuns de validação".
precisa saber é o seguinte
4
@BurhanKhalid: Você está errado. Expressão regular é a melhor ferramenta para validação, já que a entrada HTML5 possui um atributo chamado patternque recebe uma expressão regular, e os navegadores são validados automaticamente em relação à regex sem usar nenhum javascript. Apenas definindo uma regex no atributo pattern!
temor

Respostas:

329

A regex que você colou não valida os anos bissextos corretamente, mas existe uma que faz na mesma postagem . Eu modifiquei para levar dd/mm/yyyy, dd-mm-yyyyou dd.mm.yyyy.

^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(\/|-|\.)(?:0?[13-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)0?2\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$

Eu testei um pouco no link que Arun forneceu em sua resposta e também aqui e parece funcionar.

Editar 14 de fevereiro de 2019: removi uma vírgula que estava no regex que permitia datas como 29-0,-11

Ofir Luzon
fonte
9
Regex épico! Com que facilidade isso poderia ser trocado de acordo com o formato? Por exemplo aaaa-mm-dd e mm-dd-aaaa. Eu tentei entender isso com isso em mente, mas está além das minhas habilidades em expressões regulares.
Mrswadge
7
Além DD/MM/YYYYdisso, esse regex também aceita, o DD/MM/YYque não tenho certeza de que estava na intenção inicial do pôster. Se você deseja não suportar 'YY', remova todos os ?quantificadores opcionais .
usar o seguinte comando
2
@PurveshDesai substitua cada um 0?por 0e também remova a última ocorrência de ?.
Ofir Luzon
4
@MaraisRossouw, você está correto, há 4 dígitos no ano, na verdade existem 3 ?que devem ser removidos: substitua todos (?:1[6-9]|[2-9]\d)?por (?:1[6-9]|[2-9]\d).
Ofir Luzon
2
Cair por apenas para dizer isto: WOW e, claro, muito obrigado
Jero Dungog
266

Estendi o regex fornecido por @Ofir Luzon para os formatos dd-mmm-AAAA, dd / mmm / AAAA, dd.mmm. AAAA, conforme meus requisitos. Qualquer pessoa com o mesmo requisito pode consultar isso

^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]|(?:Jan|Mar|May|Jul|Aug|Oct|Dec)))\1|(?:(?:29|30)(\/|-|\.)(?:0?[1,3-9]|1[0-2]|(?:Jan|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)(?:0?2|(?:Feb))\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9]|(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep))|(?:1[0-2]|(?:Oct|Nov|Dec)))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$

e testado para alguns casos de teste aqui http://regexr.com/39tr1 .

Para uma melhor compreensão desta expressão regular, consulte esta imagem: insira a descrição da imagem aqui

Alok Chaudhary
fonte
1
Sim, como você o gerou? :)
Navalha
Eu o criei on-line usando algum site e agora também não me lembro do site a partir do qual gerei esta imagem. Vou adicionar a referência, uma vez que me lembro :)
Alok Chaudhary
4
@ user3733831 8888é um ano possível. Eu espero viver até essa idade.
Dan Nissenbaum
1
Funciona muito bem, mesmo nos anos bissextos. Também adicionei suporte para nomes curtos de meses em espanhol.
Fer R
2
@AlokChaudhary, o diagrama foi gerado usando debuggex.com
Taha BASRI
69

Aviso prévio:

Sua regexp não funciona há anos que "são múltiplos de 4 e 100, mas não de 400". Os anos que passam nesse teste não são bissextos. Por exemplo: 1900, 2100, 2200, 2300, 2500 etc. Por outras palavras, coloca todos os anos com o formato \ d \ d00 na mesma classe de anos bissextos, o que está incorreto. - MuchToLearn

Por isso, funciona corretamente apenas para [1901 - 2099] (Ufa) 😊

dd / MM / aaaa:

Verifica se o ano bissexto. Os anos de 1900 a 9999 são válidos. Apenas dd / MM / aaaa

(^(((0[1-9]|1[0-9]|2[0-8])[\/](0[1-9]|1[012]))|((29|30|31)[\/](0[13578]|1[02]))|((29|30)[\/](0[4,6,9]|11)))[\/](19|[2-9][0-9])\d\d$)|(^29[\/]02[\/](19|[2-9][0-9])(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)$)
gdZeus
fonte
7
Esta resposta funciona apenas com dd / MM / aaaa. Portanto, é a resposta certa.
Rodrigo
2
@SylvainB Eu corrigi
gdZeus
2
@gdZeus Obrigado por entregar, mesmo dois anos depois! É assustador pensar que uma solução incompleta permaneceu validada por aqui por tanto tempo.
SylvainB
Para torná-lo mais rápido, você pode tornar os grupos não agrupados. regexr.com/3esom ^ (? :(? :(? :( ?: 0 [1-9] | 1 [0-9] | 2 [0-8]) [\ /] (?: 0 [1- 9] | 1 [012])) | (? :( ?: 29 | 30 | 31) [\ /] (?: 0 [13578] | 1 [02])) | (? :( ?: 29 | 30 ) [\ /] (?: 0 [4,6,9] | 11))] [\ /] (?: 19 | [2-9] [0-9]) \ d \ d) | (?: 29 [\ /] 02 [\ /] (?: 19 | [2-9] [0-9]) (?: 00 | 04 | 08 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | 96)) $
Matt Vukomanovic
Suponho que encontrei um erro: 29/02/2100não existe (2100 NÃO é um ano bissexto), mas ainda é aceito pelo padrão fornecido.
precisa saber é o seguinte
17

tente isso.

^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d$

você pode testar expressões regulares em http://www.regular-expressions.info/javascriptexample.html facilmente.

AT
fonte
2
este regex não valida a data com o mês como 30-02-2001... de qualquer forma obrigado pela resposta :)
Nalaka526
12

Suspeito que o seguinte seja o mais preciso possível sem saber quando o local do usuário passou dos calendários juliano para o gregoriano.

Ele aceita '-', '/' ou nada como separadores entre ano, mês e dia, independentemente da ordem.

MMddyyyy:

^(((0[13-9]|1[012])[-/]?(0[1-9]|[12][0-9]|30)|(0[13578]|1[02])[-/]?31|02[-/]?(0[1-9]|1[0-9]|2[0-8]))[-/]?[0-9]{4}|02[-/]?29[-/]?([0-9]{2}(([2468][048]|[02468][48])|[13579][26])|([13579][26]|[02468][048]|0[0-9]|1[0-6])00))$

ddMMyyyy:

^(((0[1-9]|[12][0-9]|30)[-/]?(0[13-9]|1[012])|31[-/]?(0[13578]|1[02])|(0[1-9]|1[0-9]|2[0-8])[-/]?02)[-/]?[0-9]{4}|29[-/]?02[-/]?([0-9]{2}(([2468][048]|[02468][48])|[13579][26])|([13579][26]|[02468][048]|0[0-9]|1[0-6])00))$

aaaaMMdd:

^([0-9]{4}[-/]?((0[13-9]|1[012])[-/]?(0[1-9]|[12][0-9]|30)|(0[13578]|1[02])[-/]?31|02[-/]?(0[1-9]|1[0-9]|2[0-8]))|([0-9]{2}(([2468][048]|[02468][48])|[13579][26])|([13579][26]|[02468][048]|0[0-9]|1[0-6])00)[-/]?02[-/]?29)$

Além da ordem, todos eles são precisos para o calendário juliano (ano bissexto a cada quatro anos) até 1700, quando o calendário gregoriano diverge do juliano. Tem dois problemas:

  1. Ele aceita o ano 0000, que não existe em muitos, mas não em todos os padrões. Observe que a ISO 8601 aceita o ano 0000 (equivalente a 1 AEC).
  2. Não pula os 10-13 dias que foram perdidos quando o Calendário Gregoriano entrou em uso. Isso varia de acordo com a localidade. Por exemplo, a Igreja Católica Romana pulou 10 dias, de 5 a 14 de outubro de 1582, mas a Grécia (a última a mudar) pulou de 16 de fevereiro a 28 de 1923, 13 dias, tendo que levar em consideração os anos bissextos de 1700, 1800 e 1900.

Isso foi testado contra a implementação do calendário de Java do ano 0001 até o ano de 9999, com a única discrepância nos 10 dias mencionados em 1582.

Jason Greanya
fonte
O regex AAAAMMDD corresponde incorretamente a [01 | 02 | 03 | 05 | 06 | 07 | 09 | 10 | 11 | 13 | 14 | 15] 00-02-29. Regex corrigido: ^([0-9]{4}[-/]?((0[13-9]|1[012])[-/]?(0[1-9]|[12][0-9]|30)|(0[13578]|1[02])[-/]?31|02[-/]?(0[1-9]|1[0-9]|2[0-8]))|([0-9]{2}(([2468][048]|[02468][48])|[13579][26])|([13579][26]|[02468][048])00)[-/]?02[-/]?29)$. Testado com python: repl.it/repls/DependentBestChapters
kpr
10

Para quem olha para eles e fica completamente confuso, aqui está um trecho do meu roteiro. Infelizmente, tudo o que faz é corresponder a números válidos em uma entrada de data e hora e 31 de fevereiro será marcado como válido, mas como muitos disseram, o regex realmente não é a melhor ferramenta para fazer esse teste.

Para corresponder a uma data no formato 'aaaa-MM-dd hh: mm' (ou na ordem que você desejar)

var dateerrors = false;
var yearReg = '(201[4-9]|202[0-9])';            ///< Allows a number between 2014 and 2029
var monthReg = '(0[1-9]|1[0-2])';               ///< Allows a number between 00 and 12
var dayReg = '(0[1-9]|1[0-9]|2[0-9]|3[0-1])';   ///< Allows a number between 00 and 31
var hourReg = '([0-1][0-9]|2[0-3])';            ///< Allows a number between 00 and 24
var minReg = '([0-5][0-9])';                    ///< Allows a number between 00 and 59
var reg = new RegExp('^' + yearReg + '-' + monthReg + '-' + dayReg + ' ' + hourReg + ':' + minReg + '$', 'g');
$('input').filter(function () {return this.id.match(/myhtml_element_with_id_\d+_datetime/);}).each(function (e) {
    if (e > 0) {
        // Don't test the first input. This will use the default
        var val = $(this).val();
        if (val && !val.trim().match(reg)) {
            dateerrors = true;
            return false;
        }
    }
});
if (dateerrors) {
    alert('You must enter a validate date in the format "yyyy-mm-dd HH:MM", e.g. 2019-12-31 19:30');
    return false;
}

O script acima começa criando um objeto regex. Em seguida, ele encontra todas as entradas cujos IDs correspondem a um determinado padrão e depois os percorre. Não testo a primeira entrada que encontro ( if (e > 0)).

Um pouco de explicação:

var reg = new RegExp('^' + yearReg + '-' + monthReg + '-' + dayReg + ' ' + hourReg + ':' + minReg + '$', 'g');

^significa início da partida, enquanto que $significa final da partida.

return this.id.match(/myhtml_element_with_id_\d+_datetime/);

\d+meios corresponder a um único ou de uma sequência contígua de números inteiros, de modo que myhtml_element_with_id_56_datetimee myhtml_element_with_id_2_datetimevai corresponder, mas myhtml_element_with_id_5a_datetimenão vai

Luke Madhanga
fonte
8

Aqui está outra versão do regex para corresponder a qualquer um dos seguintes formatos de data e permitir que os zeros à esquerda sejam omitidos:

Regex: ^[0-3]?[0-9].[0-3]?[0-9].(?:[0-9]{2})?[0-9]{2}$

Partidas:

1/1/11 or 1.1.11 or 1-1-11 : true 01/01/11 or 01.01.11 or 01-01-11 : true 01/01/2011 or 01.01.2011 or 01-01-2011 : true 01/1/2011 or 01.1.2011 or 01-1-2011 : true 1/11/2011 or 1.11.2011 or 1-11-2011 : true 1/11/11 or 1.11.11 or 1-11-11 : true 11/1/11 or 11.1.11 or 11-1-11 : true

Visualização de expressão regular

Demo de depuração

Solução Simples
fonte
4
não funciona se você tiver 13/13/2000= Partidas são verdadeiras #
Andrei Krasutski
3
39/39/39 não é um encontro. Pare de votar nesta resposta.
Warren Sergent
6

Aqui eu escrevi um para dd/mm/yyyyonde o separador pode ser de um -.,/intervalo de anos 0000-9999.

Ele lida com anos bissextos e é projetado para sabores regex, que oferecem suporte a lookaheads, capturando grupos e referências anteriores. NÃO é válido para, como d/m/yyyy. Se necessário, adicione mais separadores para[-.,/]

^(?=\d{2}([-.,\/])\d{2}\1\d{4}$)(?:0[1-9]|1\d|[2][0-8]|29(?!.02.(?!(?!(?:[02468][1-35-79]|[13579][0-13-57-9])00)\d{2}(?:[02468][048]|[13579][26])))|30(?!.02)|31(?=.(?:0[13578]|10|12))).(?:0[1-9]|1[012]).\d{4}$

Teste no regex101 ; como uma sequência Java:

"^(?=\\d{2}([-.,\\/])\\d{2}\\1\\d{4}$)(?:0[1-9]|1\\d|[2][0-8]|29(?!.02.(?!(?!(?:[02468][1-35-79]|[13579][0-13-57-9])00)\\d{2}(?:[02468][048]|[13579][26])))|30(?!.02)|31(?=.(?:0[13578]|10|12))).(?:0[1-9]|1[012]).\\d{4}$"

explicou:

(?x) # modifier x: free spacing mode (for comments)
     # verify date dd/mm/yyyy; possible separators: -.,/
     # valid year range: 0000-9999

^    # start anchor

# precheck xx-xx-xxxx,... add new separators here
(?=\d{2}([-.,\/])\d{2}\1\d{4}$)

(?:  # day-check: non caturing group

  # days 01-28
  0[1-9]|1\d|[2][0-8]| 

  # february 29d check for leap year: all 4y / 00 years: only each 400
  # 0400,0800,1200,1600,2000,...
  29
  (?!.02. # not if feb: if not ...
    (?!
      # 00 years: exclude !0 %400 years
      (?!(?:[02468][1-35-79]|[13579][0-13-57-9])00)

      # 00,04,08,12,... 
      \d{2}(?:[02468][048]|[13579][26])
    )
  )|

  # d30 negative lookahead: february cannot have 30 days
  30(?!.02)|

  # d31 positive lookahead: month up to 31 days
  31(?=.(?:0[13578]|10|12))

) # eof day-check

# month 01-12
.(?:0[1-9]|1[012])

# year 0000-9999
.\d{4}

$ # end anchor

Veja também as perguntas frequentes sobre o Regex do SO ; Por favor, deixe-me saber, se falhar.

Jonny 5
fonte
5

Encontrei este reg ex aqui

^(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$

Isso valida o formato mm/dd/yyyye as datas válidas corretamente (mas não m/d/yyyy).

Alguns testes

Nalaka526
fonte
1
Funciona apenas antes de 2014, tem que mudar | 20 (0 [0-9] | 1 [0-4]))) para | 20 (0 [0-9] | 1 [0-9]))) para suportar até 2019
Tony Dong
5
"^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.]((19|20)\\d\\d)$"

validará qualquer data entre 1900-2099

user3575114
fonte
5

A seguinte expressão é agradável e fácil de manipular:

((((0[13578]|1[02])(\/|-|.)(0[1-9]|1[0-9]|2[0-9]|3[01]))|((0[469]|11)(\/|-|.)(0[1-9]|1[0-9]|2[0-9]|3[0]))|((02)((\/|-|.)(0[1-9]|1[0-9]|2[0-8]))))(\/|-|.)(19([6-9][0-9])|20(0[0-9]|1[0-4])))|((02)(\/|-|.)(29)(\/|-|.)(19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26])))

Ele valida de acordo com o formato MM / dd / AAAA e permite o suporte ao ano bissexto de 1960 a 2016. Se você precisar do suporte do ano bissexto estendido, basta manipular esta parte da expressão:

(19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]))

Espero que isso tenha ajudado muito

correr atrás
fonte
3

Outra resposta que valida o dia (dd), dependendo do mês (mm) e do ano (aaaa) (ou seja, também valida 29 de fevereiro em anos bissextos) e permite anos que variam de 0001 a 9999 (0000 em um ano inválido, de acordo com o gregoriano) calendário)

^(?:(?:(?:0[1-9]|[12]\d|3[01])/(?:0[13578]|1[02])|(?:0[1-9]|[12]\d|30)/(?:0[469]|11)|(?:0[1-9]|1\d|2[0-8])/02)/(?!0000)\d{4}|(?:(?:0[1-9]|[12]\d)/02/(?:(?!0000)(?:[02468][048]|[13579][26])00|(?!..00)\d{2}(?:[02468][048]|[13579][26]))))$
Debanshu Kundu
fonte
1
não valida 18/05/0017
1

Estou trabalhando com uma API que aceita apenas o formato MM / DD / AAAA. Não consegui encontrar nenhum outro post que tenha pulado anos tão bem quanto a resposta de Ofir , então eu o aprimorei e estou postando novamente aqui para qualquer pessoa que possa precisar.

/^(?:(?:(?:0[13578]|1[02])(\/)31)\1|(?:(?:0[1,3-9]|1[0-2])(\/)(?:29|30)\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:02(\/)29\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))(\/)(?:0[1-9]|1\d|2[0-8])\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$/
Daniel
fonte
0
((((0[13578]|1[02])\/(0[1-9]|1[0-9]|2[0-9]|3[01]))|((0[469]|11)\/(0[1-9]|1[0-9]|2[0-9]|3[0]))|((02)(\/(0[1-9]|1[0-9]|2[0-8]))))\/(19([6-9][0-9])|20([0-9][0-9])))|((02)\/(29)\/(19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]|2[048])))

validará o MM/DD/YYYYformato com 1960para2028

se você precisar estender o suporte do ano bissexto, adicione

19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]|2[048]|3[26]|4[048])))

isso também é trabalho

^((((0[13578]|1[02])[/](0[1-9]|1[0-9]|2[0-9]|3[01]))|((0[469]|11)[/](0[1-9]|1[0-9]|2[0-9]|3[0]))|((02)([/](0[1-9]|1[0-9]|2[0-8]))))[/](19([6-9][0-9])|20([0-9][0-9])))|((02)[/](29)[/](19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]|2[048])))

se você pode alterar o formato mm-dd-yyyyde substituir [/]a [-] também verificar on-line http://regexr.com/

mahesh
fonte
0

Para a data MM / DD / AAAA, você pode usar

^((((0[13578])|([13578])|(1[02]))[\/](([1-9])|([0-2][0-9])|(3[01])))|(((0[469])|([469])|(11))[\/](([1-9])|([0-2][0-9])|(30)))|((2|02)[\/](([1-9])|([0-2][0-9]))))[\/]\d{4}$|^\d{4}$

Ele verifica dias e mariposas adequados.

Lembre-se de que você pode verificar sua expressão regular em

regex101

qual eu recomendo :)

Diverta-se!

Przemysław Sienkiewicz
fonte
0
^(((([13578]|0[13578]|1[02])[-](0[1-9]|[1-9]|1[0-9]|2[0-9]|3[01]))|(([469]|0[469]|11)[-]([1-9]|1[0-9]|2[0-9]|3[0]))|((2|02)([-](0[1-9]|1[0-9]|2[0-8]))))[-](19([6-9][0-9])|20([0-9][0-9])))|((02)[-](29)[-](19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]|2[048])))

esse regex validará as datas no formato:

12-30-2016 (mm-dd-aaaa) ou 12-3-2016 (mm-d-aaaa) ou 1-3-2016 (md-aaaa) ou 1-30-2016 (m-dd-aaaa)

mexekanez
fonte
0

Eu sei que é uma resposta tangencial para a pergunta, mas se a intenção da pergunta é 'como validar uma data?', Por que não tentar deixar a linguagem de programação fazer todo o trabalho duro (se você estiver usando uma linguagem que pode)?

por exemplo, em php

$this_date_object = date_create($this_date);

if ($this_date_object == false )
    {

        // process the error

    }
Neil Iosson
fonte