简体   繁体   中英

Sort array of objects by closest date

I have an array of objects in PHP with one key - date. I have future dates as well as past dates. I need to sort them in by most current date.

Here is my array from var_dump()

array (size=15)
  0 => 
    object(stdClass)[7852]
      public 'date' => string '20200417' (length=8)
  1 => 
    object(stdClass)[7846]
      public 'date' => string '20200302' (length=8)
  2 => 
    object(stdClass)[7856]
      public 'date' => string '20200224' (length=8)
  3 => 
    object(stdClass)[7853]
      public 'date' => string '20200220' (length=8)
  4 => 
    object(stdClass)[7847]
      public 'date' => string '20200213' (length=8)
  5 => 
    object(stdClass)[7845]
      public 'date' => string '20200211' (length=8)
  ...

Is there a way to sort this so that the first object would be the 20200302, then 20200224 and so on. but the future dates would be at the very end of the array.

I've tried this:

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

But this code doesn't care about the current date, it just sorts them as dates. I have also tried a workaround with calculating interval from the date('Ymd') - $arr->date and setting that as a part of an object, but strcmp() in usrot function gives virtually the same result, because future date will give negative number and in ascending order negative number will come before positive numbers. Meaning, the most future date will be first, not the most current date.

Any help is much appreciated.

What you need to do is work out how far each date is away from today and use this to sort the items, there may be a more elegant way, but this (I think) works. Basically use abs() to ensure all differences are +ve and take each date away from today...

usort($arr, function($a, $b) {
    return (abs(strtotime('today') - strtotime($a->date))
        - (abs(strtotime('today') - strtotime($b->date))));
});

Nigel's answer was a big help, but it produced uneven results, sometimes the dates would be all over the place, I have no idea why. So, I figured a workaround, perhaps it will be of help to someone on the internet.

I've added one more key/value to an object - interval , value for this key I calculated in the following manner.

$interval_raw = date("Ymd") - get_field('date_nachalo') + 1;
    if($interval_raw < 0) {
        $interval_raw += 10000;
    }

So, if I get a negative number which is any future date, I'll add 10000 which is like 30 years in advance, a bit overkill I guess because no normal human schedules events that far into the future. Also, added + 1 so that the next upcoming date would be first. If I remove that, then the first date will be the date from the past. Basically, if today is march 10th and the last event was on march 1st and the next event event is on march 11th, without the + 1 the first event date would be the march 1st not the march 11th.

If anyone knows more elegant approach to this, do let the world know.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM