Should I check dates with DateTime or regex?

7

I've seen two different ways to check if a date is valid.

In a "modern" way, with DateTime :

$date="2014-02-04";
$dt = DateTime::createFromFormat("Y-m-d", $date);

return $dt !== false && !array_sum($dt->getLastErrors());

And using a regular expression:

$date="2014-02-04";

// regex bem simples, apenas para demonstrar a situação.
return (preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/",$date));

I did not find much comparative information about these methods. I know that DateTime is more modern, but is that enough to consider it more recommendable? What are the advantages and disadvantages of each method?

    
asked by anonymous 04.02.2014 / 19:42

5 answers

9

Dates are in the bottom numbers. Even if you declare in string form, it is more efficient to represent them as integers.

The class DateTime is specialized, so it has all possible optimizations for working with dates.

Regular expressions are commonly used and process strings. Usually, they have a high computational cost (they are usually O (n²)).

Add to this the fact that it is much easier for a computer to interpret integers than strings and you have your answer.

As a rule: whenever there is an alternative to regular expressions, use it. Regular expressions are like a Swiss Army Knife: always useful, but if you have a real plier, why use those pliers more or less coming in the pocket knife?

    
04.02.2014 / 20:18
4

No need to complicate. Use the native checkdate function of PHP:

link

Example:

if (checkdate(2, 29, 2014)) {
    echo 'Data válida';
}
else {
    echo 'Data inválida';
}

This will print on screen: Invalid date. Because 2014 is not leap year.

    
05.02.2014 / 01:44
4

It's best to use DateTime :: createFromFormat () yourself. It was made for this and treats conditions that its regular expression does not treat.

I can not tell you which is the fastest (vote in DateTime) because this will depend on the implementation and version of PHP.

For versions of PHP smaller than 5.3, the documentation presents this alternative code for DateTime :: createFromFormat ():

static function createFromFormat ($format, $time){
assert ($format!="");
if($time==""){ 
    return new DateClass();
}

    $regexpArray['Y'] = "(?P<Y>19|20\d\d)";        
    $regexpArray['m'] = "(?P<m>0[1-9]|1[012])";
    $regexpArray['d'] = "(?P<d>0[1-9]|[12][0-9]|3[01])";
    $regexpArray['-'] = "[-]";
    $regexpArray['.'] = "[\. /.]";
    $regexpArray[':'] = "[:]";            
    $regexpArray['space'] = "[\s]";
    $regexpArray['H'] = "(?P<H>0[0-9]|1[0-9]|2[0-3])";
    $regexpArray['i'] = "(?P<i>[0-5][0-9])";
    $regexpArray['s'] = "(?P<s>[0-5][0-9])";

    $formatArray = str_split ($format);
    $regex = "";

    // create the regular expression
    foreach($formatArray as $character){
        if ($character==" ") $regex = $regex.$regexpArray['space'];
        elseif (array_key_exists($character, $regexpArray)) $regex = $regex.$regexpArray[$character];
    }
    $regex = "/".$regex."/";

    // get results for regualar expression
    preg_match ($regex, $time, $result);

    // create the init string for the new DateTime
    $initString = $result['Y']."-".$result['m']."-".$result['d'];

// if no value for hours, minutes and seconds was found add 00:00:00
    if (isset($result['H'])) $initString = $initString." ".$result['H'].":".$result['i'].":".$result['s'];
    else {$initString = $initString." 00:00:00";}

    $newDate = new DateClass ($initString);
    return $newDate;
    }    
}

And as you can see they also use regex (not in versions 5.3+). But, regex by regex, use DateTime :: createFromFormat () same.

    
05.02.2014 / 02:05
2

The regular expression is not very good for date validation, since you do not only want to validate if there are numbers or dashes, you also want to validate the date.

The expression you put

^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$

It would be responsible for validating the date "2014-02-31" , and that date does not exist.

One option would be to use a more complex regular expression (valid between 1800-2099 with leap years)

^((?:18|19|20)[0-9]{2})-(?:0[13578]|1[02])-31|(?:18|19|20)[0-9]{2}-(?:01|0[3-9]|1[1-2])-(?:29|30)|(?:18|19|20)[0-9]{2}-(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:(?:(?:(?:18|19|20)(?:04|08|[2468][048]|[13579][26]))|2000)-02-29)$

But the larger the regular expression the larger the processing, so it is recommended to turn text into type Data as the best option, so the conversion prevents it from being done with invalid dates.

    
04.02.2014 / 21:37
-2

I recommend using the link , as well as specializing in regular expression dates should be used in the latter case, since it is very costly both to work with them and to the server. It can in some cases cause slowness.

    
04.02.2014 / 21:45