Tiêu chí:
Năm nào chia hết cho 4 là năm nhuận, trừ khi chia hết cho 100 trừ khi chia hết cho 400. Vì vậy:
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
Tháng 2 có 29 ngày trong năm nhuận và 28 ngày không phải năm nhuận
30 ngày trong tháng 4, 6, 9 và 11
31 ngày trong tháng 1, 3, 5, 7, 8, 10 và 12
Kiểm tra:
Tất cả các ngày sau đây đều phải vượt qua xác thực:
1976-02-29
2000-02-29
2004-02-29
1999-01-31
Tất cả các ngày sau đây sẽ không xác thực được:
2015-02-29
2015-04-31
1900-02-29
1999-01-32
2015-02-00
Phạm vi:
Chúng tôi sẽ kiểm tra các ngày từ ngày 1 tháng 1 năm 1000 đến ngày 31 tháng 12 năm 2999. Về mặt kỹ thuật, lịch Gregorian hiện đang được sử dụng chỉ được sử dụng vào năm 1753 cho Đế quốc Anh và vào những năm khác nhau trong những năm 1600 cho các quốc gia ở Châu Âu, nhưng tôi sẽ không lo lắng về điều đó.
Regex để kiểm tra một năm nhuận:
Các năm chia hết cho 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
Các năm chia hết cho 4:
[12]\d([02468][048]|[13579][26])
Các năm chia hết cho 100:
[12]\d00
Không chia hết cho 100:
[12]\d([1-9]\d|\d[1-9])
Các năm chia hết cho 100 nhưng không chia hết cho 400:
((1[1345789])|(2[1235679]))00
Chia hết cho 4 nhưng không chia hết cho 100:
[12]\d([2468][048]|[13579][26]|0[48])
Những năm nhuận:
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])
Không chia hết cho 4:
[12]\d([02468][1235679]|[13579][01345789])
Không phải là một năm nhuận:
Not divisible by 4 OR is divisible by 100 but not by 400
([12]\d([02468][1235679]|[13579][01345789]))|(((1[1345789])|(2[1235679]))00)
Tháng và ngày hợp lệ không bao gồm tháng 2 (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))
Tháng 2 với 28 ngày:
02-(0[1-9]|1\d|2[0-8])
Tháng 2 với 29 ngày:
02-(0[1-9]|[12]\d)
Ngày hợp lệ:
(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]))))
Vì vậy, bạn có nó là regex cho các ngày từ ngày 1 tháng 1 năm 1000 đến ngày 31 tháng 12 năm 2999 ở định dạng YYYY-MM-DD.
Tôi nghi ngờ nó có thể được rút ngắn một chút, nhưng tôi sẽ để điều đó cho người khác.
Điều đó sẽ phù hợp với tất cả các ngày hợp lệ. Nếu bạn muốn nó chỉ hợp lệ khi nó chỉ chứa một ngày và không có gì khác, thì hãy bọc nó lại ^( )$
như sau:
^(((((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])))))$
Nếu bạn muốn nó cho một mục ngày tùy chọn (nghĩa là nó có thể để trống hoặc một ngày hợp lệ) thì hãy thêm ^$|
vào đầu, như sau:
^$|^(((((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";
hoặc PHPcheckdate ( int $month , int $day , int $year )
.