Date Comparison Function for `usort()` I am working through a PHP book, and date comparison was mentioned as one of the uses of usort(), so I wrote a date comparison function to use in line with usort(). Writing the function wasn't as easy as I expected (there was a pesky bug which took me a while to identify), so I thought I would submit my comparison code for review.  

dates.php

&lt;?    
    function dateParse($date) 
    {
        return (count(explode("-", $date)) == 3)?(explode("-", $date)):(explode("/", $date));   #Returns the date as an array.
    }

    function dateSort($date1, $date2, $format=1)
    {
        if ($format == 0)   #dd/mm/yyyy format.
        {
            list($day1, $month1, $year1) = dateParse($date1);
            list($day2, $month2, $year2) = dateParse($date2);
        }
        elseif ($format == 1)   #mm/dd/yyyy format.
        {
            list($month1, $day1, $year1) = dateParse($date1);
            list($month2, $day2, $year2) = dateParse($date2);
        }
        elseif ($format == 2)   #yyyy/mm/dd format.
        {
            list($year1, $month1, $day1) = dateParse($date1);
            list($year2, $month2, $day2) = dateParse($date2);
        }
        $day1 = str_pad($day1, 2, "0", STR_PAD_LEFT);   #Adds a leading "0" if the day is a single digit.
        $day2 = str_pad($day2, 2, "0", STR_PAD_LEFT);   #Adds a leading "0" if the day is a single digit.
        $month1 = str_pad($month1, 2, "0", STR_PAD_LEFT);   #Adds a leading "0" if the month is a single digit.
        $month2 = str_pad($month2, 2, "0", STR_PAD_LEFT);   #Adds a leading "0" if the month is a single digit.

        $x1 = $year1.$month1.$day1;
        $x2 = $year2.$month2.$day2;

        return ((int)$x1 &lt;=&gt; (int)$x2);
    }
?&gt;
Magic numbers are a bad code smell and should be avoided. Use a constant instead.


In your definition of dateSort(), your third parameter is format=1. What does 1 mean? Without reviewing the code it isn't clear which makes maintaining the code more difficult. A common way to avoid this is to define constants with human readable names and use them in place of the magic numbers. Note that the names of these constants are arbitrary. Name them in such a way that makes sense to the reader what value they hold or reflect.

 defined('DATE_FORMAT_EU_SLASHES') || define('DATE_FORMAT_EU_SLASHES', 0);
 defined('DATE_FORMAT_US')         || define('DATE_FORMAT_US', 1);
 defined('DATE_FORMAT_YEAR_FIRST') || define('DATE_FORMAT_YEAR_FIRST', 2);



Using date_parse() is okay but working with DateTime() objects is preferred. 


PHP offers a lot of ways of working with dates which can be a good or bad thing. In general using DateTime() objects are preferred as they were designed specifically for this purpose (and is the most powerful). 

Your code can be simplified as DateTime() can parse most date formats natively and also handle not standard formats easily. date_parse() will fail once the format becomes non-standard or irregular.

Additionally, DateTime() objects are comparable so you don't need to output a string variable in a comparable format to do your comparison. Just compare the objects themselves.

$datetime1 = new DateTime($date1);
$datetime2 = new DateTime($date2);
return datetime1 &lt;=&gt; datetime2;


Simpler!    


Use a switch statement instead of a potentially giant if/else    


Because we can have situations where DateTime() can handle the format natively, there is no need to have an if/else statement for every date format. switch allows us to allow conditions to be handled by the same code block. It also offers us a default option which means we no longer need to define our default format in the function signature and can let the switch statement handle it for us.

defined('DATE_FORMAT_EU_SLASHES') || define('DATE_FORMAT_EU_SLASHES', 0);
defined('DATE_FORMAT_US')         || define('DATE_FORMAT_US', 1);
defined('DATE_FORMAT_YEAR_FIRST') || define('DATE_FORMAT_YEAR_FIRST', 2);

function dateSort($date1, $date2, $format = null)
    switch ($format) {
        case DATE_FORMAT_EU_SLASHES :
            // DateTime::createFromFormat() offers us flexibility
            $datetime1 = DateTime::createFromFormat('d/m/Y', $date1);
            $datetime2 = DateTime::createFromFormat('d/m/Y', $date2);
            break;
        case DATE_FORMAT_US :
        case DATE_FORMAT_YEAR_FIRST :
        default :
            // DateTime() can handle both formats natively so no need to handle them 
            // individually. You can also ad formats like YYYY-MM-DD with only a couple 
            // of lines of code
            $datetime1 = new DateTime($date1);
            $datetime2 = new DateTime($date2);
            break;
    }
    return datetime1 &lt;=&gt; datetime2;
}   


If you want to take it a step further, you could simplify your code and only specify when the format is non-standard and handle them specifically. Otherwise, fall to the default date handler:

defined('DATE_FORMAT_EU_SLASHES') || define('DATE_FORMAT_EU_SLASHES', 0);

function dateSort($date1, $date2, $format = null)
    switch ($format) {
        case DATE_FORMAT_EU_SLASHES :
            $datetime1 = DateTime::createFromFormat('d/m/Y', $date1);
            $datetime2 = DateTime::createFromFormat('d/m/Y', $date2);
            break;
        default :
            $datetime1 = new DateTime($date1);
            $datetime2 = new DateTime($date2);
            break;
    }
    return datetime1 &lt;=&gt; datetime2;
}   


*None of this code is tested -- I just wrote it off of the top of my head -- but hopefully it gives you ideas about how to improve this code