Order Collection of Objects by Ascending Date(s) from Current Date

Viewed 64

In PHP, I have an object array and I need to sort it starting with the most recent date from today and going out. The dates are stored as strings with only month and day.

I can use usort with function like below to get it sorted chronologically but I'm struggling with how to get it to sort when compared against today's date.

function date_sort($a, $b) {
  return strtotime($a->bday) - strtotime($b->bday);
}

usort($users, "date_sort");

The original array looks like this:

$users = array(
    [0] => stdClass Object
        (
            [name] => Tim
            [bday] => September 13
        )
    [1] => stdClass Object
        (
            [name] => Scott
            [bday] => November 8
        )
    [2] => stdClass Object
        (
            [name] => Bob
            [bday] => October 13
        )
    [3] => stdClass Object
        (
            [name] => Dan
            [bday] => February 2
        )
    [4] => stdClass Object
        (
            [name] => Jack
            [bday] => July 11
        ) 
)

If today is October 8, I need the sorted array to look like:

$users = array(
    [0] => stdClass Object
        (
            [name] => Bob
            [bday] => October 13
        )
    [1] => stdClass Object
        (
            [name] => Scott
            [bday] => November 8
        )
    [2] => stdClass Object
        (
            [name] => Dan
            [bday] => February 2
        )
    [3] => stdClass Object
        (
            [name] => Jack
            [bday] => July 11
        ) 
    [4] => stdClass Object
        (
            [name] => Tim
            [bday] => September 13
        )
)
2 Answers

Inside your comparison function, you compare the timestamps from strtotime() to the timestamp for the current date. Since by default it will use the current year for days without years, if the timestamp is less than the current timestamp, add a year. Do this for both $a->bday and $b->bday`. Then do your comparison.

function date_sort($a, $b) {
    if(strtotime($a->bday) < strtotime(date("Y-m-d")))
    {
        $adate = strtotime(date("Y-m-d", strtotime($a->bday)) . " +1 year");
    }
    else
    {
        $adate = strtotime($a->bday);
    }
    if(strtotime($b->bday) < strtotime(date("Y-m-d")))
    {
        $bdate = strtotime(date("Y-m-d", strtotime($b->bday)) . " +1 year");
    }
    else
    {
        $bdate = strtotime($b->bday);
    }
  return $adate - $bdate;
}

DEMO

Another option (perhaps better performance-wise) would be to iterate through the array, compare to the current day, adjust the dates as needed, and then call usort() on the adjusted array.

Sorting function can be something like this:

$now = new DateTime();

usort($users, function($a, $b) use ($now) {
    $aDate = new DateTime($a->bday);
    if ($aDate < $now) {
        $aDate->add(new DateInterval('P1Y'));
    }

    $bDate = new DateTime($b->bday);
    if ($bDate < $now) { 
        $bDate->add(new DateInterval('P1Y'));
    }

    return $aDate > $bDate;  
});

Of course, converting to DateTime objects can be performed once in a separate while loop so as to reduce redundancy.

Sample fiddle https://3v4l.org/u3U80.

Related