G.Rose
G.Rose

Reputation: 704

How to filter array of objects on date

I have an array of objects I need to filter through and return only the objects closest to today. The issue I'm having is that it's returning the June date and not the one in May. here's the code I'm using:

const findClosest = (data, accessor, target = Date.now()) =>
  data.reduce((prev, curr) => {
    const a = Math.abs(accessor(curr).getTime() - target);
    const b = Math.abs(accessor(prev).getTime() - target);
    return a - b < 0 ? curr : prev;
  });

const getClosestFromDate = (array, key, date) => {
  let arr = array.filter((e) => e[key] == date);
  return arr;
};

const sampleData = [{
    "max_retries_reached": 0,
    "next_charge_scheduled_at": "2022-06-23T00:00:00",
  },
  {
    "max_retries_reached": 0,
    "next_charge_scheduled_at": "2022-06-23T00:00:00",
  },
  {
    "is_swappable": true,
    "max_retries_reached": 0,
    "next_charge_scheduled_at": "2022-06-23T00:00:00",
  },
  {
    "max_retries_reached": 0,
    "next_charge_scheduled_at": "2022-06-23T00:00:00",
  },
  {
    "next_charge_scheduled_at": "2022-05-23T00:00:00",
    "order_day_of_month": null,
  },
  {
    "max_retries_reached": 0,
    "next_charge_scheduled_at": "2022-07-23T00:00:00",
    "order_day_of_month": null,
  },
  {
    "max_retries_reached": 0,
    "next_charge_scheduled_at": "2022-05-23T00:00:00",
    "order_day_of_month": null,
  },
  {
    "max_retries_reached": 0,
    "next_charge_scheduled_at": "2022-05-23T00:00:00",
    "order_day_of_month": null,
  },
  {
    "next_charge_scheduled_at": "2022-07-23T00:00:00",
    "order_day_of_month": null,
  },
];

const processDateString = (dateString) => {
  let date = new Date(dateString);
  let year = date.getFullYear();
  let month = date.getMonth();
  console.log(date.toString());
  return new Date(year, month + 1, date);
};

const closest = findClosest(sampleData, ({
  next_charge_scheduled_at
}) => processDateString(next_charge_scheduled_at), "2022-05-10T03:03:42");

console.log(closest.next_charge_scheduled_at);

console.log(getClosestFromDate(sampleData, "next_charge_scheduled_at", closest.next_charge_scheduled_at));

I got this code from one of the other questions, but for some reason even after trying multiple times to add or subtract from the month variable, I am unable to return the correct date. I'd really appreciate help on this.

Upvotes: 0

Views: 306

Answers (1)

Carsten Massmann
Carsten Massmann

Reputation: 28236

You were making life too hard for yourself:

(I revised my answer after reading OP's latest comment.)

The const acc is a utility function(obj) that will grab the next_charge_scheduled_at property of the obj, turn it into a date object and then return its .getTime() value.

findClosest(sampleData,acc) returns a single object of the given sampleData array closest to the target time (Date.now()). I then store the .getTime()value of this element in the constant closest and use it again to filter through the original input array:

const sampleData = [{
    "max_retries_reached": 0,
    "next_charge_scheduled_at": "2022-06-23T00:00:00",
  },
  {
    "max_retries_reached": 0,
    "next_charge_scheduled_at": "2022-06-23T00:00:00",
  },
  {
    "is_swappable": true,
    "max_retries_reached": 0,
    "next_charge_scheduled_at": "2022-06-23T00:00:00",
  },
  {
    "max_retries_reached": 0,
    "next_charge_scheduled_at": "2022-06-23T00:00:00",
  },
  {
    "next_charge_scheduled_at": "2022-05-23T00:00:00",
    "order_day_of_month": null,
  },
  {
    "max_retries_reached": 0,
    "next_charge_scheduled_at": "2022-07-23T00:00:00",
    "order_day_of_month": null,
  },
  {
    "max_retries_reached": 0,
    "next_charge_scheduled_at": "2022-05-23T00:00:00",
    "order_day_of_month": null,
  },
  {
    "max_retries_reached": 0,
    "next_charge_scheduled_at": "2022-05-23T00:00:00",
    "order_day_of_month": null,
  },
  {
    "next_charge_scheduled_at": "2022-07-23T00:00:00",
    "order_day_of_month": null,
  },
];
const 
 findClosest = (data, accessor, target = Date.now()) =>
  data.reduce((prev, curr) => {
    const a = Math.abs(accessor(curr) - target);
    const b = Math.abs(accessor(prev) - target);
    return a - b < 0 ? curr : prev;
 }),
 acc=obj=>new Date(obj.next_charge_scheduled_at).getTime(),
 closest=acc(findClosest(sampleData,acc));
 
console.log(sampleData.filter(d=>acc(d)===closest));

The following version is even shorter and avoids the repeated calcuation of Date objects:

function getClosest(arr){
  const trg=Date.now() 
   times=sampleData.map((d,i)=>[new Date(d.next_charge_scheduled_at).getTime(),i]),
   closest=times.reduce((p,c) => Math.abs(c[0]-trg) < Math.abs(p[0]-trg) ? c : p)[0];
  return times.reduce((a,[t,i])=>(t==closest&&a.push(arr[i]),a),[]);
}

getClosest() uses a temporary array times to store the calculated .getTime() value and the index i for each object. After finding the closest time to Date.now() the times array is then -reduce()d in order to compile the results from the original input array arr.

Upvotes: 2

Related Questions