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

Here's my problem, and my code, i wish to check to see if the following is a date:

10-25-2002 - the first number is day, second is month
I want to be able to check:

s#((([0][1-9])|([1-2][0-9])|([3][0-1]))checkmonth + year#<date>$1</dat +e>#
but i can't seem to get the checking the day to work, basically it has to be between 1-31.. i have tried stuff such as: ^0[1-9]$ but i can't seem to get it to work, any help would be greatly appreciated!!

cheers, B

Replies are listed 'Best First'.
Re: checking dates in strings
by dws (Chancellor) on Nov 11, 2002 at 00:35 UTC
    An alternate approach -- one that makes pesky things like leap years easier to cope with -- is first filter for things that look like dates, then validate them with a separate routine. Something like the following:
    s#((\d+)-(\d+)-(\d+))#isDate($2,$3,$4) ? "<date>$1</date>" : $1#e; sub isDate { my($d,$m,$y) = @_; # ... return 1 if these are a valid date, else 0 }
    Where isDate() is left as an exercise.

      cool, that's a good idea, can you just give me a small hint as how to check if say $1 is in the set 10-19 ?
        can you just give me a small hint as how to check if say $1 is in the set 10-19 ?

        Thanks to the outer set of parenthesis, $1 is the complete string matched. It gets substituted for itself if isDate($2,$3,$4) return 0. You can check numbers individually inside of isDate(), where they're available in $d, $m, and $y respectively.

Re: checking dates in strings
by pg (Canon) on Nov 11, 2002 at 00:59 UTC
    I don't think it will be easy to have a single regexp to validate dates, if you really want to validate every detail. Also complex regexp seems to me as a bad habit, as it stops people from understanding and maintaining code. Here is my solution, hope it helps you:
    use strict; my @last_day = (31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); sub is_leap_year { my $year = shift; my $result; if ($year % 4) { $result = 0; } else { $result = 1; if (!($result % 100)) { $result = 0; if (!($result % 400)) { $result = 1; } } } return $result; } sub is_validate_date { my $date = shift; $date =~ m/(\d+)-(\d+)-(\d+)/; my $year = $3; my $month = $2; my $day = $1; my $result = 1; if (($month > 12) || ($month < 1)) { $result = 0; } else { if ($day > $last_day[$month - 1]) { $result = 0; } else { if (!is_leap_year($year) && ($month == 2) && ($day > 28)) +{ $result = 0; } } } return $result; } my $date = "29-02-2000"; print is_validate_date($date);
      I would strongly advise you consider using an existing CPAN module, like Date::Manip. That way, you can:

      1. Avoid having to reinvent code that already exists
      2. Avoid getting bitten by the many special cases in date processing
      3. Easily update your program if you find you need to support more than this particular date format


      And if you want to improve your understanding of date handling, looking at the source of existing modules is a good place to start.

        I fully agree with you. There is also another package we can use for this purpose, but less natural than your suggestion:
        use HTTP::Date qw(parse_date); my ($year, $month, $day, $hour, $$minute, $second, $timezone) = parse_ +date("11-12-2002"); print "year = $year\n"; print "month = $month\n"; print "day = $day\n";