This code fails in Y10k, but that should be good enough. The regex could be stricter, but if the date has already been validated (or will be validated in the new form) then it doesn't matter.
#!/usr/bin/perl
use strict;
use warnings;
my @mon = qw/null JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC/;
my $d = "20080428";
$d =~ s/..(..)(..)(..)/$3-$mon[$2]-$1/;
print "date is now $d\n";
Or, if you are insane and want to validate in the regex (requires Perl 5.10):
#!/usr/bin/env perl5.10.0
use strict;
use warnings;
my @mon = qw/null JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC/;
my $d = join '', @ARGV;
# only validates between 1600 and 9999
# because of calendar weirdness prior to 1600
$d =~ s/
^
(?:
# non-leap years and everything but 29th of Feb in leap years
(?:
1[6-9] (?<y> [0-9]{2}) |
[2-9][0-9] (?<y> [0-9]{2})
)
(?: #any month 1st through 28th
(?: (?<m> 0[1-9] | 1[0-2]) (?<d> 0[0-9] | 1[0-9] | 2[0-8]) )
| #or 30th of any month but 2
(?: (?<m>0[13-9] | 1[0-2]) (?<d> 30) )
| # or 31st of 1, 3, 5, 7, 8, 10, or 12
(?: (?<m>0[13578] | 1[02]) (?<d> 31) )
)
| # or 29th of Feb in leap years
(?:
(?: #centuries divisible by 4 minus the ones divisible by 100
16 |
[2468][048] |
[3579][26]
)
(?<y> 00)
| #or non-centuries divisible by 4
(?: 1[6-9] | [2-9][0-9] )
(?<y>
0[48] |
[2468][048] |
[13579][26]
)
)
(?<m> 02) (?<d> 29)
)
$
/$+{y}-$mon[$+{m}]-$+{d}/x or die "invalid date: $d";
print "date is now $d\n";