Rexact
Cheatsheet

Regex French date (dd/mm/yyyy)

The reference Stack Overflow question (267 votes) starts from a concrete problem: a regex with no leap-year logic validated "31/02/4500" as a correct date. The top-voted answer (450 votes) fixes that specific point. But actually testing two other answers from the same thread turns up — in each, independently — a forgotten comma inside a character class, reopening a flaw similar to one the top answer's own author had fixed in their edit history. Here's a reliable pattern, compared against these 3 real attempts.

/^(?:31\/(?:0?[13578]|1[02])\/|(?:29|30)\/(?:0?[13-9]|1[0-2])\/)(?:1[6-9]|[2-9]\d)\d{2}$|^29\/0?2\/(?:(?: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])\/(?:1[6-9]|[2-9]\d)\d{2}$/
passes 28/28 cases

Comparison of existing patterns

SourcepatternScore on the corpusReDoS
Stack Overflow — tentative de l'auteur de la question, sans logique d'année bissextile (accepte « 31/02/4500 »)^(0?[1-9]|[12][0-9]|3[01])[\/\-](0?[1-9]|1[012])[\/\-]\d{4}$20 / 28safe
Stack Overflow — extension à 307 votes de la réponse la plus votée, virgule oubliée dans une classe de caractères^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(\/|-|\.)(?:0?[1,3-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})$25 / 28safe
Stack Overflow — réponse à 86 votes, ne gère pas correctement les siècles (bug signalé en commentaire, valide seulement 1901-2099), même virgule oubliée(^(((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)$)24 / 28safe

Implementation

const re = new RegExp("^(?:31\\/(?:0?[13578]|1[02])\\/|(?:29|30)\\/(?:0?[13-9]|1[0-2])\\/)(?:1[6-9]|[2-9]\\d)\\d{2}$|^29\\/0?2\\/(?:(?: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])\\/(?:1[6-9]|[2-9]\\d)\\d{2}$", "");
re.test(input);

Limits

  • Ne couvre que la forme numérique jj/mm/aaaa avec « / » comme séparateur : les formes « jj-mm-aaaa », « jj.mm.aaaa » ou en toutes lettres (« 3 septembre 2026 »), également utilisées en France, ne sont pas reconnues par ce motif.
  • Accepte un jour ou un mois à un seul chiffre sans zéro de tête (« 1/1/2020 ») aussi bien que la forme complète : pour exiger strictement deux chiffres, il faut retirer les « 0? » optionnels du motif.
  • L'année doit compter exactement 4 chiffres et rester dans la plage 1600-9999 : une année à 2 chiffres (« 20 » pour 2020) ou antérieure à 1600 est rejetée, une limite arbitraire héritée des plages de siècle du motif source, sans lien avec une règle du calendrier grégorien lui-même.
  • Valide uniquement la FORME d'une date calendaire (nombre de jours par mois + règle bissextile) : ne connaît ni les 10 jours sautés lors de la réforme grégorienne de 1582, ni aucune règle métier (date future interdite, jour férié, etc.).

Related pages