General Madness (years 0-9999)
The following (based on this answer) works for many years between 0 and 9999.
(?<!\d)(?:(?:(?:1[6-9]|[2-9]\d)?\d{2})(?:(?:(?:0[13578]|1[02])31)|(?:(?:0[1,3-9]|1[0-2])(?:29|30)))|(?:(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))0229)|(?:(?:1[6-9]|[2-9]\d)?\d{2})(?:(?:0?[1-9])|(?:1[0-2]))(?:0?[1-9]|1\d|2[0-8]))(?!\d)
(check out the demo )
General insanity simplified (years 2000-2099)
If you want, you can simplify it to work only for many years between 2000 and 2099.
(?<!\d)(?:(?:20\d{2})(?:(?:(?:0[13578]|1[02])31)|(?:(?:0[1,3-9]|1[0-2])(?:29|30)))|(?:(?:20(?:0[48]|[2468][048]|[13579][26]))0229)|(?:20\d{2})(?:(?:0?[1-9])|(?:1[0-2]))(?:0?[1-9]|1\d|2[0-8]))(?!\d)
But, as you can see, this is not much easier.
(check demo )
The smart way (years *)
To maintain common sense, you should stick with a very simple regular expression and then test it with code.
(20\d{2})(\d{2})(\d{2})
(check out the demo )
source share