Web Development for 2012

Alexander Dickson - Web Developer covering PHP, jQuery / Javascript, XHTML, CSS, more

Validating an Australian date with PHP

Published on Wednesday, 13th October 2010.

An often annoying thing with being an Australian PHP developer are the dates formats which follows the American standard, i.e. mm/dd/yyyy.

This means we can't easily accept an outside date in Australian format without doing some string manipulation on it to get it into a nice format for native functions like strtotime().

When accepting a date in PHP such as dd/mm/yyyy, we often want to validate it for...

  • Syntax - does it match dd/mm/yyyy ?

  • Correctness - is it a valid date, i.e. do the digits correspond to real dates ?
  • Future - has the date passed already ?

Of course, the last rule does not need to be always be checked, but I often find myself needing to ensure that it has passed.

I've put together a little function that can validate an Australian date, based on the criteria above.

Round 1

function validateDate($str) { preg_match_all('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/', (string) $str, $matches);   // Validate syntax if ( ! isset($matches[0][0])) { return FALSE; }   $year = (int) $matches[3][0]; $month = (int) $matches[2][0]; $day = (int) $matches[1][0];   // Make sure date is correct if ( ! checkdate($month, $day, $year)) { return FALSE; }   // Make sure date hasn't passed if (mktime(0, 0, 0, $month, $day, $year) <= time()) { return FALSE; }   return TRUE; }

But wait? Regex? checkdate() and mktime()? Doesn't PHP now provide an easy OO way to play with dates? Well, yes, it does sir!

Round 2

function validateDate($str) { $date = DateTime::createFromFormat('j/m/Y', $str);   $errors = $date->getLastErrors(); if (isset($errors['warning_count']) AND $errors['warning_count'] > 0 OR isset($errors['errors_count']) AND $errors['errors_count'] > 0 ) { return FALSE; }   $diff = $date->diff(new DateTime()); if ($diff->invert === 0) { return FALSE; } return TRUE; }

Ahh... much better!

Often, knowing if a date failed validation isn't enough, we want to know why. This is where a validation library comes in handy - you can pass this function as a callback to it, and then call the library's add error method upon finding an error, to accurately inform the end user as to why their entered date did not pass validation.

Being a Kohana 3 man myself, I find its validation library incredibly helpful. I'm sure you can use your imagination to adapt it for a callback for the validation library.

Comments

  • Ricardo

    Posted on Wednesday, 20th October 2010 @ 2:45am.

    Test done with a small change on my code.

    $val --> in this case, receives a date field in the format dd/mm/yyyy

    [code]
    if( preg_match('@^(\d{2}\/\d{2}\/\d{4}|\d{4}-\d{2}\-d{2})$@', $val) ) {

    $data = preg_split("/[\s\/] /", $val);
    if(!checkdate($data[1],$data[0],$data[2])){
    self::stackError( $errors, $fieldName, $array['message']);
    }
    }

    [/code]

    Tested with Selenium. Used 71/02/1998 (typo) and 10/22/1998 (10/22 could be interpreted as 22/10). Plus, 10-02/1998, 10/**/1998 and 10/AA/1998 also fails.

    Cheers!

  • Ricardo

    Posted on Wednesday, 20th October 2010 @ 2:10am.

    I will test your suggested OO check date. So far, I can validate a date with checkdate. The problem relies where PHP consider correct both 31/10/2010 and 10/31/2010, because it understand both formats. Nevertheless, thank you for your help!

  • Alexander Dickson

    Posted on Sunday, 17th October 2010 @ 7:53pm.

    @Russel Dias

    From what I just tested, the DateTime object does not throw an exception if there is an error or warning present.

    If it did, a try/catch block would indeed be more succinct.

    However, let me know if I am wrong! Cheers.

  • Russell Dias

    Posted on Sunday, 17th October 2010 @ 4:47pm.

    Not too sure about the DateTime library. So correct me if I'm wrong.

    But, couldn't that verbose error checking be reduced by a simple try / catch construct?


    try {
    $date = DateTime::createFromFormat('j/m/Y', $str)
    } catch (Exception $e) {
    //$e->getMessage();
    }

    Can't test this out at the moment; I will mess around with it tonight.

Leave a Comment

Comment Details

Your email will never be displayed. If you have a gravatar, it will be displayed.

Note: Your comment may require approval before it is posted to the site.

Stack Overflow Profile

view full profile »

About

I'm a web developer from the Sunshine Coast, Australia. more »