0

I've got the array of objects:

const data = [{
  "id": "1",
  "effectiveDate": "2023-01-21"
}, {
  "id": "2",
  "effectiveDate": "2023-02-22"
}, {
  "id": "3",
  "effectiveDate": "2022-05-04"
}, {
  "id": "4",
  "effectiveDate": "2022-05-05"
}, {
  "id": "5",
  "effectiveDate": "2021-01-21"
}, {
  "id": "6",
  "effectiveDate": "2021-02-22"
}];

What I'm after is the way to sort it in the way that the object with the most current date is on index 0 and the rest of the objects are ordered ascending from the oldest to future dates, like this:

[{
  "id": "4",
  "effectiveDate": "2022-05-05"
}, {
  "id": "5",
  "effectiveDate": "2021-01-21"
}, {
  "id": "6",
  "effectiveDate": "2021-02-22"
}, {
  "id": "3",
  "effectiveDate": "2022-05-04"
}, {
  "id": "1",
  "effectiveDate": "2023-01-21"
}, {
  "id": "2",
  "effectiveDate": "2023-02-22"
}]

The way I'm sorting it is:

const orderedDates = data.sort((a, b) => {
  const dateCompareResult = new Date(a.effectiveDate) - new Date(b.effectiveDate);
  return dateCompareResult;
});

which obviously gives me dates sorted ascending from the past dates to the future dates with the most current date somewhere in between. How can I move the most current date object to index 0?

1
  • Negate your sort result value Commented May 11, 2022 at 10:59

2 Answers 2

2

function getItemsInAscendingDateOrderAndClosestToNowFirst(arr) {
  const time = Date.now();

  const [closest, ...rest] = Array
    // create a shallow copy in order to
    // not mutate the original reference.
    .from(arr)
    // sort items by date closest to now.
    .sort((a, b) => {

      const aTime = new Date(a.effectiveDate).getTime();
      const bTime = new Date(b.effectiveDate).getTime();

      const aDelta = Math.abs(time - aTime);
      const bDelta = Math.abs(time - bTime);

      return (aDelta - bDelta);
    });

  return [
    closest,
    ...rest
      // sort all other items in ascending date order.
      .sort((a, b) =>
        new Date(a.effectiveDate).getTime()
        - new Date(b.effectiveDate).getTime()
      ),
  ];
}

const data = [{
  "id": "1",
  "effectiveDate": "2023-01-21"
}, {
  "id": "2",
  "effectiveDate": "2023-02-22"
}, {
  "id": "3",
  "effectiveDate": "2022-05-04"
}, {
  "id": "4",
  "effectiveDate": "2022-05-05"
}, {
  "id": "5",
  "effectiveDate": "2021-01-21"
}, {
  "id": "6",
  "effectiveDate": "2021-02-22"
}];
const sortedData =
  getItemsInAscendingDateOrderAndClosestToNowFirst(data);

console.log({ sortedData });
.as-console-wrapper { min-height: 100%!important; top: 0; }

Sign up to request clarification or add additional context in comments.

Comments

1

I think the simplest way is to sort from oldest to newest, then move the element that's closest to today to the start, e.g.

let data = [{"id": "1","effectiveDate": "2023-01-21"},
            {"id": "2","effectiveDate": "2023-02-22"},
            {"id": "3","effectiveDate": "2022-05-04"},
            {"id": "4","effectiveDate": "2022-05-05"},
            {"id": "5","effectiveDate": "2021-01-21"},
            {"id": "6","effectiveDate": "2021-02-22"}];

// Sort from oldest to youngest
data.sort((a, b) => b.effectiveDate.localeCompare(a.effectiveDate));

// Get today as milliseconds
let today = new Date().toLocaleDateString('en-CA');
let todayMS = Date.parse(today);

// Get index of closest element to today
let closestIndex = data.reduce((acc, obj, index) => {
  let diff = Math.abs(Date.parse(obj.effectiveDate) - todayMS);
  return acc.diff > diff? {diff, index} : acc;
}, {diff: Infinity, index:null}).index;

// Move closest element to start of array
data.unshift(data.splice(closestIndex, 1));

console.log(data);

One of the benefits of ISO 8601 formatted timestamps is that lexical comparisons give correct results. If you don't want to use string comparison then the comparison function can be:

data.sort((a, b) => Date.parse(b) - Date.parse(a))

but only if the timestamps are in one of the 3 formats supported by ECMA-262 (and fortunately, YYYY-MM-DD is one such format). :-)

3 Comments

this is not what I wanted, I didn't want the newest date to be first, I wanted the most current (closest to today) to be first. Peter's solution works perfectly
@dariusz—missed that part of the question, updated.
Just wanted to say that the Date.parse() helped me solve an issue I've been having. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.