PHP Sort a multidimensional array by element containing Y-m-d H:i:s date

PhpDatetimeArraysSorting

Php Problem Overview


I have an array such as:

Array
(
[0] => Array
    (
        [id] => 2
        [type] => comment
        [text] => hey
        [datetime] => 2010-05-15 11:29:45
    )

[1] => Array
    (
        [id] => 3
        [type] => status
        [text] => oi
        [datetime] => 2010-05-26 15:59:53
    )

[2] => Array
    (
        [id] => 4
        [type] => status
        [text] => yeww
        [datetime] => 2010-05-26 16:04:24
    )

)

Can anyone suggest a way to sort/order this based on the datetime element?

Php Solutions


Solution 1 - Php

Use usort() and a custom comparison function:

function date_compare($a, $b)
{
    $t1 = strtotime($a['datetime']);
    $t2 = strtotime($b['datetime']);
    return $t1 - $t2;
}    
usort($array, 'date_compare');

EDIT: Your data is organized in an array of arrays. To better distinguish those, let's call the inner arrays (data) records, so that your data really is an array of records.

usort will pass two of these records to the given comparison function date_compare() at a a time. date_compare then extracts the "datetime" field of each record as a UNIX timestamp (an integer), and returns the difference, so that the result will be 0 if both dates are equal, a positive number if the first one ($a) is larger or a negative value if the second argument ($b) is larger. usort() uses this information to sort the array.

Solution 2 - Php

This should work. I converted the date to unix time via strtotime.

  foreach ($originalArray as $key => $part) {
       $sort[$key] = strtotime($part['datetime']);
  }
  array_multisort($sort, SORT_DESC, $originalArray);

One-liner version would be using multiple array methods:

array_multisort(array_map('strtotime',array_column($originalArray,'datetime')),
                SORT_DESC, 
                $originalArray);

Solution 3 - Php

From php7 you can use the Spaceship operator:

usort($array, function($a, $b) {
  return new DateTime($a['datetime']) <=> new DateTime($b['datetime']);
});

Solution 4 - Php

http://us2.php.net/manual/en/function.array-multisort.php see third example:

<?php

$data[] = array('volume' => 67, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 1);
$data[] = array('volume' => 85, 'edition' => 6);
$data[] = array('volume' => 98, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 6);
$data[] = array('volume' => 67, 'edition' => 7);

foreach ($data as $key => $row) {
    $volume[$key]  = $row['volume'];
    $edition[$key] = $row['edition'];
}

array_multisort($volume, SORT_DESC, $edition, SORT_ASC, $data);

?>

fyi, using a unix (seconds from 1970) or mysql timestamp (YmdHis - 20100526014500) would be be easier for the parser but i think in your case it makes no difference.

Solution 5 - Php

$array = Array
(
  [0] => Array
   (
    [id] => 2
    [type] => comment
    [text] => hey
    [datetime] => 2010-05-15 11:29:45
   )

 [1] => Array
  (
    [id] => 3
    [type] => status
    [text] => oi
    [datetime] => 2010-05-26 15:59:53
  )

  [2] => Array
   (
    [id] => 4
    [type] => status
    [text] => yeww
    [datetime] => 2010-05-26 16:04:24
   )

   );
   print_r($array);   
   $name = 'datetime';
   usort($array, function ($a, $b) use(&$name){
      return $a[$name] - $b[$name];});

   print_r($array);

Solution 6 - Php

You can simply solve this problem using usort() with callback function. No need to write any custom function.

$your_date_field_name = 'datetime';
usort($your_given_array_name, function ($a, $b) use (&$your_date_field_name) {
    return strtotime($a[$your_date_field_name]) - strtotime($b[$your_date_field_name]);
});

Solution 7 - Php

Sorting array of records/assoc_arrays by specified mysql datetime field and by order:

function build_sorter($key, $dir='ASC') {
    return function ($a, $b) use ($key, $dir) {
        $t1 = strtotime(is_array($a) ? $a[$key] : $a->$key);
        $t2 = strtotime(is_array($b) ? $b[$key] : $b->$key);
        if ($t1 == $t2) return 0;
        return (strtoupper($dir) == 'ASC' ? ($t1 < $t2) : ($t1 > $t2)) ? -1 : 1;
    };
}

   
// $sort - key or property name 
// $dir - ASC/DESC sort order or empty
usort($arr, build_sorter($sort, $dir));

Solution 8 - Php

Most of the earlier answers failed to acknowledge the available shortcut of comparing the datetime values as simple strings. Other answers that realized that strtotime() was unnecessary did not spell out why did what they did ...so I will.

Because your datetime values are formatted with units in descending size (Y, m, d, H, i, s) AND because each unit is consistently expressed with the same number of characters (4, 2, 2, 2, 2, 2) AND because the delimiting characters are all identical from string to string, you can simply compare them character-by-character from left to right (naturally). This would not be true for a date string formatted as, say, d/m/Y.

There are two functions that are ideal for this task, I'll demonstrate ASC and DESC versions for both.

Demo Link

  • usort() by date column DESC:

    usort($array, function($a, $b) { return $b['datetime'] <=> $a['datetime']; });
    
  • usort() by date column ASC:

    usort($array, function($a, $b) { return $a['datetime'] <=> $b['datetime']; });
    
  • usort() by date column ASC in >= PHP7.4:

    usort($array, fn($a, $b) => $a['datetime'] <=> $b['datetime']);
    
  • array_multisort() by date column DESC:

     array_multisort(array_column($array, 'datetime'), SORT_DESC, $array);
    
  • array_multisort() by date column ASC:

    array_multisort(array_column($array, 'datetime'), $array);
    

All of these techniques modify by reference, so the function provide no real valuable return value.

array_multisort():

  • doesn't need a custom function
  • it does need the datetime column to be isolated by some looping mechanism
  • it will lose numeric keys, but fortunately they are not valuable for this question

usort():

  • doesn't use sorting direction constants, so developers must understand that $a before $b (on either side of the spaceship operator) means ASC and $b before $a means DESC
  • requires a custom function
  • can be adjusted to preserve first level keys by calling uasort() instead

For anyone who truly DOES need a date or datetime string to be parsed because its format does not permit instant string comparisons, here is an answer devoted to explaining the caveats of that task.

Solution 9 - Php

I came across to this post but I wanted to sort by time when returning the items inside my class and I got an error.

So I research the php.net website and end up doing this:

class MyClass {
   public function getItems(){
      usort( $this->items, array("MyClass", "sortByTime") );
      return $this->items;
   }
   public function sortByTime($a, $b){
      return $b["time"] - $a["time"];
   }
}

You can find very useful examples in the http://www.php.net/manual/en/function.usort.php">PHP.net website

My array looked like this:

  'recent' => 
    array
      92 => 
        array
          'id' => string '92' (length=2)
          'quantity' => string '1' (length=1)
          'time' => string '1396514041' (length=10)
      52 => 
        array
          'id' => string '52' (length=2)
          'quantity' => string '8' (length=1)
          'time' => string '1396514838' (length=10)
      22 => 
        array
          'id' => string '22' (length=2)
          'quantity' => string '1' (length=1)
          'time' => string '1396514871' (length=10)
      81 => 
        array
          'id' => string '81' (length=2)
          'quantity' => string '2' (length=1)
          'time' => string '1396514988' (length=10)

Solution 10 - Php

For those still looking a solved it this way inside a class with a function sortByDate, see the code below

<?php

class ContactsController 
{
    public function __construct()
    {
    //
    }


    function sortByDate($key)
    {
        return function ($a, $b) use ($key) {
            $t1 = strtotime($a[$key]);
            $t2 = strtotime($b[$key]);
            return $t2-$t1;
        };
                
    }

    public function index()
    {
        
        $data[] = array('contact' => '434343434', 'name' => 'dickson','updated_at' =>'2020-06-11 12:38:23','created_at' =>'2020-06-11 12:38:23');
        $data[] = array('contact' => '434343434', 'name' => 'dickson','updated_at' =>'2020-06-16 12:38:23','created_at' =>'2020-06-10 12:38:23');
        $data[] = array('contact' => '434343434', 'name' => 'dickson','updated_at' =>'2020-06-7 12:38:23','created_at' =>'2020-06-9 12:38:23');

            
        usort($data, $this->sortByDate('updated_at'));

        //usort($data, $this->sortByDate('created_at'));
        echo $data;

    }
}

Solution 11 - Php

For 'd/m/Y' dates:

usort($array, function ($a, $b, $i = 'datetime') { 
    $t1 = strtotime(str_replace('/', '-', $a[$i]));
    $t2 = strtotime(str_replace('/', '-', $b[$i]));
    
    return $t1 > $t2;
});

where $i is the array index

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTimView Question on Stackoverflow
Solution 1 - PhpFerdinand BeyerView Answer on Stackoverflow
Solution 2 - PhpDave NoneView Answer on Stackoverflow
Solution 3 - PhpFederkunView Answer on Stackoverflow
Solution 4 - PhpTobyView Answer on Stackoverflow
Solution 5 - PhpAjit KumarView Answer on Stackoverflow
Solution 6 - PhpFaisalView Answer on Stackoverflow
Solution 7 - PhpfalkoView Answer on Stackoverflow
Solution 8 - PhpmickmackusaView Answer on Stackoverflow
Solution 9 - PhpImmutable BrickView Answer on Stackoverflow
Solution 10 - PhpDickson GodwinView Answer on Stackoverflow
Solution 11 - PhpBorjovskyView Answer on Stackoverflow