http://www.perlmonks.org?node_id=564594

alandev has asked for the wisdom of the Perl Monks concerning the following question:

hi monks i need to check whether a valid date is passed in yyyymmdd format . thanks monks

Replies are listed 'Best First'.
Re: checking for valid date
by GrandFather (Saint) on Jul 30, 2006 at 07:02 UTC

    There are a pile of Date manipulation modules available for Perl. The big hammer is Date::Manip. Possibly the way to validate your date string is first to chop it up assuming that the format is correct:

    if ($yyyymmdd !~ /(\d{4})(\d\d)(\d\d)/) { print "Bad data string provided: $yyyymmdd\n"; return 0; } my ($year, $month, $day) = ($1, $2, $3); ...

    You can then check that the year, month and day are within the expected ranges and finally validate the full date by using Date::Manip.


    DWIM is Perl's answer to Gödel
Re: checking for valid date
by planetscape (Chancellor) on Jul 30, 2006 at 13:40 UTC
Re: checking for valid date
by Ieronim (Friar) on Jul 30, 2006 at 10:31 UTC
    The standard module Time::Local will do the trick.
    use Time::Local; my $date = ' 19990230'; # 30th Feb 1999 $date =~ s/\s+$//; $date =~ s/^\s*//; my ($year, $month, $day) = unpack "A4 A2 A2", $date; eval{ timelocal(0,0,0,$day, $month-1, $year); # dies in case of bad date + 1; } or print "Bad date: $@";
    UPD: But this won't work for valid dates less than Jan 1 1970 and greater than Jan 19 2038. If you need to check dates outside this range, try Date::Manip.

         s;;Just-me-not-h-Ni-m-P-Ni-lm-I-ar-O-Ni;;tr?IerONim-?HAcker ?d;print
Re: checking for valid date
by ambrus (Abbot) on Jul 30, 2006 at 12:50 UTC

    I'll do this in two steps. First I'll check that the date is indeed eight digits, then I'll check if it refers to a valid date with the Date::Manip module (so this will fail with historical dates using the Julian calendar).

    perl -we 'use Date::Manip; sub valid_yyyymmdd { $_[0] =~ /^(\d{8})$/ a +nd ParseDate($1) and 1; } valid_yyyymmdd($_) and print "$_\n" for qw" +20060630 20060631 20060730 20060731 20060732 2006.07.30 06.07.31";'
    Output:
    20060630 20060730 20060731
Re: checking for valid date
by davidrw (Prior) on Jul 30, 2006 at 20:03 UTC
    for completeness, here's a Date::Calc solution:
    use Date::Calc qw/check_date/; my @date = $yyyymmdd =~ /^(\d{4})(\d{2})(\d{2})$/; die "ERROR: bad date '$yyymmdd'" unless check_date(@date); printf "Valid (y,m,d)=(%d,%d,%d)\n", @date;
Re: checking for valid date
by explorer (Chaplain) on Jul 30, 2006 at 13:57 UTC

    DateTime modules have almost all responses...

    use DateTime::Format::ISO8601; eval { $date = DateTime::Format::ISO8601->parse_datetime("20061730"); }; if ( $@ ) { print "ERROR: date not valid" };
Re: checking for valid date
by TedPride (Priest) on Jul 30, 2006 at 16:54 UTC
    Just because I like to roll my own:
    use strict; use warnings; while (<DATA>) { chomp; print "$_ : ", validate($_), "\n"; } BEGIN { my @mdays = (0,31,28,31,30,31,30,31,31,30,31,30,31); sub validate { no warnings; my ($year, $month, $day) = $_[0] =~ m/^(\d{4})(\d{2})(\d{2})$/ +; my $nyear = (localtime())[5] + 1900; ##### Year range is 10 years on either side of current year ##### Also exits if m// returned nothing return if $year < $nyear - 10 || $year > $nyear + 10; return if $month < 1 || $month > 12; ##### Leap year conditions if ($month == 2) { if ($year % 4 != 0) { $mdays[2] = 28; } elsif ($year % 400 == 0) { $mdays[2] = 29; } elsif ($year % 100 == 0) { $mdays[2] = 28; } else { $mdays[2] = 29; } } return if $day < 1 || $day > $mdays[$month]; return 1; } } __DATA__ 1234567 19991203 20051303 20051232 20040229 20050229 20401223