Nadine
Nadine

Reputation: 273

Sort array of objects by datetime values formatted as Y-n-d H:i:s

How can I re-arrange an array of objects like this:

 [495] => stdClass Object
        (
         [date] => 2009-10-31 18:24:09
         ...
        )
 [582] => stdClass Object
        (
         [date] => 2010-2-11 12:01:42
         ...
        )
 ...

by the date key, oldest first?

Upvotes: 26

Views: 37660

Answers (6)

mickmackusa
mickmackusa

Reputation: 47894

Because your month -- and possibly your day -- values are not zero-padded, you cannot instantly compare the dates as simple strings. You should use strtotime() to convert the dates to unix time integers -- these will be suitable for reliable comparisons.

Also, it seems important to not lose the associative relationship between the first level keys and their objects. To sort and retain the keys, call uasort(). In modern php, the spaceship operator is the go-to utility for making 3-way comparisons (returns -1, 0, or 1).

All approaches below will work identically even if the 2d array is an array of arrays instead of an array of objects (you'll only need to change the ->date syntax to ['date'].

Code:

uasort(
    $array,
    function($a, $b) {
        return strtotime($a->date) <=> strtotime($b->date);
    }
);

Or in PHP7.4, there is arrow function syntax:

uasort(
    $array,
    fn($a, $b) => strtotime($a->date) <=> strtotime($b->date)
);

The only minor drawback with using function calls in u*sort()'s body is that it will do greater than n sets of function calls to break ties and otherwise determine the correct order. An alternative sorting technique that avoids these redundant function calls is array_multisort(). It can be fed a column of data which has had exactly n function calls performed -- this effectively makes it more efficient. However, this sorting function has its own caveat -- it will lose the numeric first level keys. This is probably not a tolerable loss for this case.

Code:

array_multisort(
    array_map('strtotime', array_column($array, 'date')),
    $array
);

Here is a demo of both techniques.

For anyone who is sorting date, time, or datetime values that can be naturally compared as basic strings (so-called Big-endian formats such as Y-m-d H:i:s, H:i, m/d, Y-m-d, etc., then see this answer for more efficient techniques.

Upvotes: 2

shjiemon
shjiemon

Reputation: 21

When working with DateTime objects as properties of your Entity, this worked for me:

$myArray = $entityRepository->findAll();

usort($myArray, function($a, $b) {
    return $a->getDate()->getTimestamp() - $b->getDate()->getTimestamp();
        });

Upvotes: 0

Naqued
Naqued

Reputation: 39

I wanted to expand on arnaud576875 and Michael Irigoyen.

Same issue with object containing dateTime with Symphony.

I coudn't use $a['date'] because it was not an key array.

usort($verifications, function($a, $b) {
   return $a->getDate()->format('U') - $b->getDate()->format('U');
});

This solved my problem

Upvotes: 0

MythThrazz
MythThrazz

Reputation: 1647

Since the original question is about sorting arrays of stdClass() objects, here's the code which would work if $a and $b are objects:

usort($array, function($a, $b) {
    return strtotime($a->date) - strtotime($b->date);
});

Or if you don't have PHP 5.3:

function cb($a, $b) {
    return strtotime($a->date) - strtotime($b->date);
}
usort($array, 'cb');

Upvotes: 24

Michael Irigoyen
Michael Irigoyen

Reputation: 22947

I wanted to expand on arnaud576875's answer. I ran across this same issue, but with using DateTime objects. This is how I was able to accomplish the same thing.

usort($array, function($a, $b) {
    return $a['date']->format('U') - $b['date']->format('U');
});

Upvotes: 4

Arnaud Le Blanc
Arnaud Le Blanc

Reputation: 99909

usort($array, function($a, $b) {
    return strtotime($a['date']) - strtotime($b['date']);
});

Or if you don't have PHP 5.3:

function cb($a, $b) {
    return strtotime($a['date']) - strtotime($b['date']);
}
usort($array, 'cb');

Upvotes: 53

Related Questions