phparrayssortingdate

Sort a flat array of dates formatted as d-m-Y


I am using the array_push and array_unshift methods but when I order it, it combines the 12-2020 in the year 2021, here is an example.

foreach ($lostOpportunities_ as $key => $value) {
    $existDate = array_search($value->fecha, $datesClosed);
            
    if ($existDate === false) {
        if (Carbon::parse($value->fecha)->format('Y') == '2020') {
             array_unshift($datesClosed, $value);
        } else {
             array_push($datesClosed, $value->fecha);
        }
    }
    $_lostOpportunitiesData[$value->fecha] = $value->total;
}

$datesClosed:

Array
(
    [0] => 05-01-2021
    [1] => 06-01-2021
    [2] => 07-01-2021
    [3] => 11-01-2021
    [4] => 12-01-2021
    [5] => 13-01-2021
    [6] => 14-01-2021
    [7] => 15-01-2021
    [8] => 18-01-2021
    [9] => 19-01-2021
    [10] => 20-01-2021
    [11] => 21-01-2021
    [12] => 22-12-2020
    [13] => 23-12-2020
    [14] => 28-12-2020
    [15] => 29-12-2020
    [16] => 30-12-2020
    [17] => 08-01-2021
)

Sorting:

sort($datesClosed, SORT_STRING);

Output:

Array
(
    [0] => 05-01-2021
    [1] => 06-01-2021
    [2] => 07-01-2021
    [3] => 08-01-2021
    [4] => 11-01-2021
    [5] => 12-01-2021
    [6] => 13-01-2021
    [7] => 14-01-2021
    [8] => 15-01-2021
    [9] => 18-01-2021
    [10] => 19-01-2021
    [11] => 20-01-2021
    [12] => 21-01-2021
    [13] => 22-12-2020
    [14] => 23-12-2020
    [15] => 28-12-2020
    [16] => 29-12-2020
    [17] => 30-12-2020
)

As you can see, the ones from December 2020 are at the end, but they should be at the beginning and before 01-2021.


Solution

  • You could do this using usort on your array of date strings. You would compare them e.g. with strotime($a) <=> strtotime($b), or array_reverse(explode('-', $a)) <=> ... $b on all dates. However, this approach would quickly become a very expensive operation, given the cartesian(?) amount of conversions that would be made when each item is compared, unless the conversions were somehow cached. I wouldn't go down this path here.

    In general, it's better to sort your data when the data is still in a more readily comparable format, where at all possible. I don't think you can just usort Carbon objects though (without some overhead, as above, anyway!), so here's a no-frills solution that performs well.

    Assuming the array keys hold no particular meaning for you, you can generate timestamps for keys. You can then scrap all the unshift/push logic, and simply do something like this:

    $timestamp = Carbon::parse($value->fecha)->timestamp;
    $times[$timestamp] = $value;
    

    This will give you an array (here, $times) of date strings with timestamp-indexes. (Adapt the variables to fit your case.) Then it's as trivial as applying ksort($times) to the resulting array, ie. sorting the array by key. Your date strings will be in chronological order.