phparrayssortingtimeusort

Sort a 2d array based on a column containing AM/PM-formatted time ranges


I have a 2D array named $props, the structure is as follows,

$props = [
    ['name' => 'Mathmatics', 'time' => '03:01:PM - 04:50:PM'],
    ['name' => 'History', 'time' => '11:30:AM - 01:30:PM'],
    ['name' => 'French', 'time' => '01:31:PM - 03:00:PM'],
];

I need to sort the array by 'time' key, to get the following result:

[
    ['name' => 'History', 'time' => '11:30:AM - 01:30:PM'],
    ['name' => 'French', 'time' => '01:31:PM - 03:00:PM'],
    ['name' => 'Mathmatics', 'time' => '03:01:PM - 04:50:PM'],
];

I have found a solution with usort, the solution is as follows:

usort($props, function ($a, $b) {
    return $a["time"] - $b["time"];
});

However, this is not working maybe because of special format of my time (but I will have to follow this specific time format.) and shows an error and do nothing to the array. The error:

Notice: A non well formed numeric value encountered in C:\xampp.....


Solution

  • This solution uses usort with a special sorting function. Date objects are created using substr and DateTime::createFromFormat. The spaceship operator is use for comparison.

    $arr = [
      ['name' => 'Mathmatics', 'time' => '03:01:PM - 04:50:PM'],
      ['name' => 'History', 'time' => '11:30:AM - 01:30:PM'],
      ['name' => 'French', 'time' => '01:31:PM - 03:00:PM'],
    ];
    
    usort($arr,function($a,$b){
      $dta = DateTime::createFromFormat('h:i:A',substr($a['time'],0,8));
      $dtb = DateTime::createFromFormat('h:i:A',substr($b['time'],0,8));
      return $dta <=> $dtb;
    });
    
    print_r($arr);
    

    Try self: https://3v4l.org/Fq9U5

    This variant sorts by the start of the time interval. If only the end is required you can use

    DateTime::createFromFormat('h:i:A - h:i:A',$a['time']); //same with $b