Critères :
Toute année divisible par 4 est une année bissextile, sauf si elle est divisible par 100, sauf si elle est divisible par 400. Donc :
2004 - leap year - divisible by 4
1900 - not a leap year - divisible by 4, but also divisible by 100
2000 - leap year - divisible by 4, also divisible by 100, but divisible by 400
Le mois de février compte 29 jours dans une année bissextile et 28 jours dans une année non bissextile.
30 jours en avril, juin, septembre et novembre
31 jours en janvier, mars, mai, juillet, août, octobre et décembre.
Test :
Les dates suivantes devraient toutes être validées :
1976-02-29
2000-02-29
2004-02-29
1999-01-31
Les dates suivantes ne devraient pas être validées :
2015-02-29
2015-04-31
1900-02-29
1999-01-32
2015-02-00
Gamme :
Nous allons tester les dates du 1er janvier 1000 au 31 décembre 2999. Techniquement, le calendrier grégorien actuellement utilisé n'est entré en vigueur qu'en 1753 pour l'Empire britannique et à diverses dates dans les années 1600 pour les pays d'Europe, mais je ne vais pas m'en inquiéter.
Regex pour tester la présence d'une année bissextile :
Les années divisibles par 400 :
1200|1600|2000|2400|2800
can be shortened to:
(1[26]|2[048])00
if you wanted all years from 1AD to 9999 then this would do it:
(0[48]|[13579][26]|[2468][048])00
if you're happy with accepting 0000 as a valid year then it can be shortened:
([13579][26]|[02468][048])00
Les années divisibles par 4 :
[12]\d([02468][048]|[13579][26])
Les années divisibles par 100 :
[12]\d00
Non divisible par 100 :
[12]\d([1-9]\d|\d[1-9])
Les années divisibles par 100 mais pas par 400 :
((1[1345789])|(2[1235679]))00
Divisible par 4 mais pas par 100 :
[12]\d([2468][048]|[13579][26]|0[48])
Les années bissextiles :
divisible by 400 or (divisible by 4 and not divisible by 100)
((1[26]|2[048])00)|[12]\d([2468][048]|[13579][26]|0[48])
Non divisible par 4 :
[12]\d([02468][1235679]|[13579][01345789])
Pas une année bissextile :
Not divisible by 4 OR is divisible by 100 but not by 400
([12]\d([02468][1235679]|[13579][01345789]))|(((1[1345789])|(2[1235679]))00)
Mois et jour valides, sauf février (MM-DD) :
((01|03|05|07|08|10|12)-(0[1-9]|[12]\d|3[01]))|((04|06|09|11)-(0[1-9]|[12]\d|30))
shortened to:
((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30))
Février avec 28 jours :
02-(0[1-9]|1\d|2[0-8])
Février avec 29 jours :
02-(0[1-9]|[12]\d)
Date de validité :
(leap year followed by (valid month-day-excluding-february OR 29-day-february))
OR
(non leap year followed by (valid month-day-excluding-february OR 28-day-february))
((((1[26]|2[048])00)|[12]\d([2468][048]|[13579][26]|0[48]))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|[12]\d))))|((([12]\d([02468][1235679]|[13579][01345789]))|((1[1345789]|2[1235679])00))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|1\d|2[0-8]))))
Voilà donc une regex pour les dates comprises entre le 1er janvier 1000 et le 31 décembre 2999 au format AAAA-MM-JJ.
Je pense qu'il peut être raccourci, mais je laisse le soin à quelqu'un d'autre de le faire.
Cela correspondra à toutes les dates valides. Si vous voulez qu'elle ne soit valide que lorsqu'elle ne contient qu'une seule date et rien d'autre, il faut l'entourer de la mention ^( )$
comme ça :
^(((((1[26]|2[048])00)|[12]\d([2468][048]|[13579][26]|0[48]))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|[12]\d))))|((([12]\d([02468][1235679]|[13579][01345789]))|((1[1345789]|2[1235679])00))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|1\d|2[0-8])))))$
Si vous souhaitez qu'il s'agisse d'une entrée de date facultative (c'est-à-dire qu'elle peut être vide ou une date valide), ajoutez alors ^$|
au début, comme ça :
^$|^(((((1[26]|2[048])00)|[12]\d([2468][048]|[13579][26]|0[48]))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|[12]\d))))|((([12]\d([02468][1235679]|[13579][01345789]))|((1[1345789]|2[1235679])00))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|1\d|2[0-8])))))$