Rexact
Cheatsheet

Regex date française (jj/mm/aaaa)

La question de référence sur Stack Overflow (267 votes) part d'un problème concret : une regex sans logique d'année bissextile validait « 31/02/4500 » comme une date correcte. La réponse la plus votée (450 votes) corrige ce point précis. Mais en testant réellement deux autres réponses du même fil, on retrouve — dans chacune, indépendamment — une virgule oubliée dans une classe de caractères, qui rouvre une faille du même genre que celle que l'auteur de la réponse la plus votée avait lui-même corrigée dans son historique d'édition. Voici un motif fiable, comparé à ces 3 tentatives réelles.

/^(?: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}$/
passe 28/28 cas

Comparatif des patterns existants

SourcepatternScore sur le 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 / 28sûr
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 / 28sûr
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 / 28sûr

Implémentation

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

Limites

  • 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.).

Pages liées