Regex para validar el formato de fecha dd / mm / aaaa


172

Necesito validar una cadena de fecha para el formato dd/mm/yyyycon una expresión regular.

Esta expresión regular valida dd/mm/yyyy, pero no las fechas inválidas como 31/02/4500:

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

¿Qué es una expresión regular válida para validar el dd/mm/yyyyformato con soporte para años bisiestos?


3
Creo que podría ayudar si establece una expectativa precisa, ya que esta expresión regular NO, de hecho, valida correctamente los años bisiestos; por ejemplo, no hay 29 de febrero en 2013, pero esta expresión regular afirma que tal es válida: regexr.com?346fp
TML

77
¿Por qué con Regex? Hay formas más fáciles (y más precisas) ...
Dan Puzey

2
Las expresiones regulares son para patrones coincidentes, no para verificar valores numéricos. Encuentre una cadena probable con la expresión regular, luego verifique su valor numérico en cualquier idioma de su host (PHP, lo que sea).
Andy Lester

3
Esta respuesta se ha agregado a las Preguntas frecuentes sobre Expresión regular de desbordamiento de pila , en "Tareas de validación comunes".
aliteralmind

44
@BurhanKhalid: Estás equivocado. La expresión regular es la mejor herramienta para la validación, ya que la entrada HTML5 tiene un atributo llamado patternque toma una expresión regular, y los navegadores se validan automáticamente contra la expresión regular sin usar ningún javascript. ¡Solo estableciendo una expresión regular en el atributo de patrón!
asombro

Respuestas:


329

La expresión regular que pegó no valida los años bisiestos correctamente, pero hay uno que sí lo hace en la misma publicación . Lo modifiqué para tomar dd/mm/yyyy, dd-mm-yyyyo 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})$

Lo probé un poco en el enlace que Arun proporcionó en su respuesta y también aquí y parece funcionar.

Editar 14 de febrero de 2019: eliminé una coma que estaba en la expresión regular que permitía fechas como 29-0,-11


9
Regex épico! ¿Con qué facilidad se podría intercambiar según el formato? Por ejemplo aaaa-mm-dd y mm-dd-aaaa. Intenté entenderlo con eso en mente, pero está más allá de mis habilidades de expresión regular.
mrswadge

77
Aparte de DD/MM/YYYYesto, esta expresión regular también acepta DD/MM/YYque no estoy seguro de que fuera en la intención inicial del póster. Si no desea admitir 'YY', elimine todos los ?cuantificadores opcionales .
user1485864

2
@PurveshDesai reemplaza cada uno 0?con 0, y también elimina la última aparición de ?.
Ofir Luzon

44
@MaraisRossouw, Tiene usted razón, para el año de 4 dígitos, en realidad hay 3 ?que debe ser eliminado: reemplazar todo (?:1[6-9]|[2-9]\d)?con (?:1[6-9]|[2-9]\d).
Ofir Luzon el

2
Visitando solo para decir esto: WOW y, por supuesto, gracias
Jero Dungog, el

266

He extendido la expresión regular dada por @Ofir Luzon para los formatos dd-mmm-AAAA, dd / mmm / AAAA, dd.mmm.YYYY según mi requisito. Cualquier otra persona con el mismo requisito puede referir esto

^(?:(?: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})$

y probado para algunos casos de prueba aquí http://regexr.com/39tr1 .

Para una mejor comprensión de esta expresión regular, consulte esta imagen: ingrese la descripción de la imagen aquí


1
Sí, ¿cómo lo generaste? :)
Razor

Lo generé en línea usando algún sitio web y ahora tampoco recuerdo el sitio web desde el que generé esta imagen. Agregaré la referencia una vez que lo recuerde :)
Alok Chaudhary

44
@ user3733831 8888es un año posible. Espero vivir a esa edad.
Dan Nissenbaum

1
Funciona muy bien incluso en los años bisiestos. También agregué soporte para nombres cortos de meses en español.
Fer R

2
@AlokChaudhary, el diagrama se generó usando debuggex.com
Taha BASRI

69

Aviso:

Su expresión regular no funciona durante años que "son múltiplos de 4 y 100, pero no de 400". Los años que pasan esa prueba no son años bisiestos. Por ejemplo: 1900, 2100, 2200, 2300, 2500, etc. En otras palabras, coloca todos los años con el formato \ d \ d00 en la misma clase de años bisiestos, lo cual es incorrecto. - MuchToLearn

Por lo tanto, funciona correctamente solo para [1901 - 2099] (Whew) 😊

dd / MM / aaaa:

Comprueba si año bisiesto. Los años de 1900 a 9999 son válidos. Solo 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)$)

77
Esta respuesta solo funciona con dd / MM / aaaa. Por lo tanto, es la respuesta correcta.
Rodrigo

2
@SylvainB lo he arreglado
gdZeus

2
@gdZeus ¡Gracias por entregar, incluso dos años después! Sin embargo, da miedo pensar que una solución incompleta se ha validado por aquí durante tanto tiempo.
SylvainB

Para hacerlo más rápido, puede hacer que los grupos no se agrupen. 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

Supongo que encontré un error: 29/02/2100no existe (2100 NO es un año bisiesto), pero todavía es aceptado por el patrón dado.
KnorxThieus


12

Sospecho que lo siguiente es tan preciso como se puede esperar sin saber cuándo la configuración regional del usuario cambió de los calendarios juliano a gregoriano.

Acepta '-', '/', o nada como separadores entre año, mes y día, sin importar el orden.

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)$

Aparte del orden, todos estos son precisos para el calendario juliano (año bisiesto cada cuatro años) hasta 1700, cuando el calendario gregoriano diverge del juliano. Tiene dos problemas:

  1. Acepta el año 0000, que no existe en muchos, pero no en todos, los estándares. Tenga en cuenta que ISO 8601 acepta el año 0000 (equivalente a 1 BCE).
  2. No se saltea los 10-13 días que se perdieron cuando entró en uso el calendario gregoriano. Sin embargo, esto varía según la localidad. Por ejemplo, la Iglesia Católica Romana se saltó 10 días, del 5 de octubre al 14 de octubre de 1582, pero Grecia (la última en cambiar) se saltó el 16 de febrero al 28 de 1923, 13 días, teniendo que tener en cuenta los años bisiestos de 1700, 1800 y 1900.

Esto se ha probado con la implementación del calendario de Java desde el año 0001 hasta el año 9999, con la única discrepancia de los 10 días mencionados anteriormente en 1582.


La expresión regular AAAAMMDD coincide incorrectamente [01 | 02 | 03 | 05 | 06 | 07 | 09 | 10 | 11 | 13 | 14 | 15] 00-02-29. Expresiones regulares corregido: ^([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)$. Probado con python: repl.it/repls/DependentBestChapters
kpr

10

Para aquellos que los ven y se confunden por completo, aquí hay un extracto de mi guión. Desafortunadamente, todo lo que hace es hacer coincidir los números válidos en una entrada de fecha y hora, y el 31 de febrero se marcará como válido, pero como muchos han dicho, regex realmente no es la mejor herramienta para hacer esta prueba.

Para que coincida con una fecha en el formato 'aaaa-MM-dd hh: mm' (o de hecho en el orden que desee)

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;
}

El script anterior comienza construyendo un objeto regex. Luego encuentra todas las entradas cuyas identificaciones coinciden con cierto patrón y luego las recorre. No pruebo la primera entrada que encuentro ( if (e > 0)).

Un poco de explicación:

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

^significa inicio del partido, mientras que $significa final del partido.

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

\d+medios que coincida con una única o una secuencia contigua de números enteros, de modo myhtml_element_with_id_56_datetimey myhtml_element_with_id_2_datetimecoincidirán, pero myhtml_element_with_id_5a_datetimeno lo harán


8

Aquí hay otra versión de regex que coincide con cualquiera de los siguientes formatos de fecha y permite omitir los ceros iniciales:

Expresión regular: ^[0-3]?[0-9].[0-3]?[0-9].(?:[0-9]{2})?[0-9]{2}$

Partidos:

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

Visualización de expresiones regulares

Demo de Debuggex


44
no funciona si tienes 13/13/2000= coincidencias es verdad
Andrei Krasutski

3
39/39/39 no es una cita. Por favor, deje de votar por esta respuesta.
Warren Sergent

6

Aquí escribí uno dd/mm/yyyydonde separador puede ser uno de -.,/rango de año 0000-9999.

Se trata de años bisiestos y está diseñado para sabores regex, que admiten lookaheads, capturando grupos y referencias. NO válido para tales como d/m/yyyy. Si es necesario, agregue separadores adicionales a[-.,/]

^(?=\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}$

Prueba a regex101 ; como una cadena de 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}$"

explicado:

(?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

Consulte también las preguntas frecuentes sobre SO Regex ; Avísame si falla.


5

Encontré este reg ex aquí

^(((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))))$

Esto valida el formato mm/dd/yyyyy las fechas válidas correctamente (pero no m/d/yyyy).

Algunas pruebas


1
Solo funciona antes de 2014, tiene que cambiar | 20 (0 [0-9] | 1 [0-4]))) a | 20 (0 [0-9] | 1 [0-9]))) para admitir hasta 2019
Tony Dong

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

validará cualquier fecha entre 1900-2099


5

La siguiente expresión es agradable y 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])))

Se valida de acuerdo con el formato MM / dd / AAAA y permite el soporte de año bisiesto de 1960 a 2016. Si necesita el soporte de año bisiesto extendido, solo necesita manipular esta parte de la expresión:

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

Espero que esto te haya ayudado mucho


3

Otra respuesta que valida el día (dd) según el mes (mm) y el año (aaaa) (es decir, también valida el 29 de febrero en los años bisiestos) y permite años que van desde 0001 a 9999 (0000 en un año no válido según el gregoriano calendario)

^(?:(?:(?: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]))))$

1
no valida 18/05/0017

1

Estoy trabajando con una API que solo acepta el formato MM / DD / AAAA. No pude encontrar ninguna otra publicación que tuviera años bisiestos tan bien como la respuesta de Ofir , por lo que la modifiqué y la vuelvo a publicar aquí para cualquiera que pueda necesitarla.

/^(?:(?:(?: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})$/

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á el MM/DD/YYYYformato con 1960a2028

si necesita extender el soporte para los años bisiestos, agregue

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

esto también es trabajo

^((((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])))

si se puede cambiar el formato mm-dd-yyyyde reemplazar [/]a [-] comprobar también en línea http://regexr.com/


0

Para la fecha MM / DD / AAAA puede 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}$

Verifica días y polillas adecuados.

Recuerde que puede verificar su expresión regular en

regex101

que recomiendo :)

¡Que te diviertas!


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])))

Esta expresión regular validará las fechas en formato:

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


0

Sé que es una respuesta tangencial a la pregunta, pero si la intención de la pregunta es '¿cómo valido una fecha?', Entonces ¿por qué no intentar dejar que el lenguaje de programación haga todo el trabajo duro (si está utilizando un lenguaje que lata)?

por ejemplo en php

$this_date_object = date_create($this_date);

if ($this_date_object == false )
    {

        // process the error

    }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.