2
\$\begingroup\$

I have this array with dates. All the dates are checked before creating the array with preg_match and check_dates.

GoodDates (
[0] => 2021-09-01
[1] => 2021-09-02
[2] => 2021-09-03
[3] => 2021-09-06
[4] => 2021-09-07
[5] => 2021-09-08
[6] => 2021-09-09
[7] => 2021-09-10
[8] => 2021-08-11
[9] => 2021-09-11
[10] => 2021-09-12
[11] => 2021-08-13
[12] => 2021-08-16
[13] => 2021-08-17
[14] => 2021-08-18
[15] => 2021-08-19
[16] => 2021-08-20
[17] => 2021-08-21
[18] => 2021-08-23
[19] => 2021-08-24
[20] => 2021-08-27
[21] => 2021-08-28
[22] => 2021-08-29
[23] => 2021-08-30
[24] => 2021-08-31 )

First, I wrote this to rsort the array $GoodDates and it works fine.

    foreach ($GoodDates as $dateitem){
$strtotimeGoodDates[] = strtotime($dateitem);
}

rsort($strtotimeGoodDates);

    foreach ($strtotimeGoodDates as $DatesForstrftime){
$GoodDatesSorted[] = strftime("%Y-%d-%B",$DatesForstrftime);
}
print_r($GoodDatesSorted);

I find this method and it works too.

$compare_function = function($a,$b) {
        $a_timestamp = strtotime($a);
        $b_timestamp = strtotime($b);
            return $b_timestamp <=> $a_timestamp;
                    };
    usort($GoodDates, $compare_function);
print_r($GoodDates);

Is my solution a good practice or it is better to use usort and why ?

\$\endgroup\$
1
  • \$\begingroup\$ With all your answers - I can delete my checkdate loop. - I have a better comprehension of how to sort a date array and some differents methods to do that. Thanks to everybody. \$\endgroup\$ Sep 16 at 9:00
3
\$\begingroup\$

Your date format is Y-m-d which means that you can safely sort these values as simple strings.

rsort() is all that you require. A native function will always be more concise and efficient than a custom (non-native) function.

If your date string were not zero-padded or the date units were not arranged with descending unit values, then additional work would be required.


If the date format was, say, d.m.Y, then strtotime() would standardize/stabilize the values.

usort($GoodDates, fn($a, $b) => strtotime($b) <=> strtotime($a));

Or

array_multisort(
    array_map('strtotime',$GoodDates),
    SORT_DESC, 
    $GoodDates
);
\$\endgroup\$
2
  • \$\begingroup\$ Thanks for this explanation \$\endgroup\$ Sep 15 at 14:38
  • \$\begingroup\$ @NastyPhoenix If I were obsessed with performance, which of course may be premature, I'd say that parsing those dates with strtotime in the usort callback is an issue. Whatever the sort implementation, Instead of parsing each of the n date strings once, you parse some of them (probably most of them) multiple times - the number of parsing is proportional to the sort time complexity which is no better then O(n * log(n)) in worst case. \$\endgroup\$
    – slepic
    Sep 17 at 5:24
0
\$\begingroup\$

You could also use the PHP DateTime class together with array_map. This would remove the need for checking dates and writing your own sort function.

<?php

$input = [
    "2021-01-01",
    "2019-05-23",
    "2022-09-13",
];

$dates = array_map(
    function (string $dateString) {
        // Also validates the input, no need for pregmatch
        return new \DateTimeImmutable($dateString); 
    },
    $input
);

sort($dates); // Use rsort() for descending order

$output = array_map(
    function (\DateTimeImmutable $date) {
        return $date->format("Y-m-d");
    },
    $dates
);

var_dump($output);

I do not know about performance, but this seems more

PHP fiddle of this working.

\$\endgroup\$
6
  • \$\begingroup\$ Hi. Welcome to Code Review! Note that answers that concentrate on the code to be reviewed explicitly are often received better here. Here, you implicitly suggest that the code does more work than necessary to check the dates. You might consider editing to make that observation explicit, grounded in the code from the question. Note: I'm not suggesting that you remove anything from the existing answer. Everything that is here is perfectly appropriate. I'm just saying that you might want to add an explicit observation about the existing code. \$\endgroup\$
    – mdfst13
    Sep 15 at 20:31
  • \$\begingroup\$ Thanks. Your answer is really interesting. \$\endgroup\$ Sep 16 at 8:23
  • \$\begingroup\$ With all your answers - I can delete my checkdate loop. - I have a better comprehension of how to sort a date array and some differents methods to do that. Thanks to everybody. \$\endgroup\$ Sep 16 at 8:59
  • \$\begingroup\$ Why run another loop after sorting? 3v4l.org/m5hd9 \$\endgroup\$ Sep 16 at 10:28
  • 1
    \$\begingroup\$ @mickmackusa Here are the reasons which made me choose 2 loops: 1. With an array of DateTimeImmutable, one could perform other operations with the dates. 2. A second loop would not cause a huge performance cost. From O(n) to O(2n) \$\endgroup\$
    – mariosimao
    Sep 17 at 3:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.