Critères:
Chaque année divisible par 4 est une année bissextile, sauf lorsqu'elle est divisible par 100 à moins qu'elle ne soit 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
Février a 29 jours dans une année bissextile et 28 jours si ce n'est pas une année bissextile
30 jours en avril, juin, septembre et novembre
31 jours en janvier, mars, mai, juillet, août, octobre et décembre
Tester:
Les dates suivantes devraient toutes passer la validation:
1976-02-29
2000-02-29
2004-02-29
1999-01-31
Les dates suivantes devraient toutes échouer à la validation:
2015-02-29
2015-04-31
1900-02-29
1999-01-32
2015-02-00
Intervalle:
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 années dans les années 1600 pour les pays d'Europe, mais je ne vais pas inquiétez-vous à ce sujet.
Regex à tester pour 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 hors février (MM-JJ):
((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 valide:
(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 expression régulière pour les dates entre le 1er janvier 1000 et le 31 décembre 2999 au format AAAA-MM-JJ.
Je soupçonne que cela peut être raccourci un peu, mais je laisse cela à quelqu'un d'autre.
Cela correspondra à toutes les dates valides. Si vous voulez qu'il ne soit valide que lorsqu'il ne contient qu'une seule date et rien d'autre, enveloppez-le ^( )$
comme suit:
^(((((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 le souhaitez pour une entrée de date facultative (c'est-à-dire qu'il peut être vide ou une date valide), ajoutez ^$|
au début, comme ceci:
^$|^(((((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])))))$
date("Y-m-d", strtotime("2012-09-12"))=="2012-09-12";
ou PHPcheckdate ( int $month , int $day , int $year )
.