1

I'm trying to get the closest date from now from an array and use it in the countdown timer along with that objects associated properties like event.

I've managed to get this far, from looking around on the web, but my code only pulls the last entry from the array not the closest date.

If anyone can help or push me in the right direction that would be great.

<p id="demo"></p>
<p id="celebration"></p>

<script>
  // Get today's date and time
  var now = new Date().getTime();

  var data = [
    {
      date: "04/10/2021",
      event: "event 1",
    },
    {
      date: "08/15/2022",
      event: "event 2",
    },
    {
      date: "09/15/2021",
      event: "event 3",
    },
    {
      date: "01/12/2025",
      event: "event 4",
    },
  ];

  var closest = data.reduce((a, b) => (a.date - now < b.date - now ? a : b));

  console.log(closest.date);

  // Set the date we're counting down to
  var countDownDate = new Date(closest.date);

  // Update the count down every 1 second
  var x = setInterval(function () {
    var now = new Date().getTime();
    // Find the distance between now and the count down date
    var distance = countDownDate - now;

    // Time calculations for days, hours, minutes and seconds
    var days = Math.floor(distance / (1000 * 60 * 60 * 24));
    var hours = Math.floor(
      (distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
    );
    var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
    var seconds = Math.floor((distance % (1000 * 60)) / 1000);

    // Display the result in the element with id="demo"
    document.getElementById("demo").innerHTML =
      days + "d " + hours + "h " + minutes + "m " + seconds + "s ";

    document.getElementById("celebration").innerHTML = closest.event;
    // If the count down is finished, write some text
    if (distance < 0) {
      clearInterval(x);
      document.getElementById("demo").innerHTML = "EXPIRED";
      document.getElementById("celebration").innerHTML = "None";
    }
  }, 1000);
</script>
4
  • 2
    The objects in your array with the property date are strings. To treaat them as dates you'll need to first parse them Commented Jul 19, 2021 at 10:24
  • what if there is expired date. Do you still want that or the next one which is not expired? Commented Jul 19, 2021 at 10:39
  • hi @decpk yeah if a date in the array has past (expired) i wouldn't want to show it and move onto the next one Commented Jul 19, 2021 at 10:43
  • Then just sort it and get the first data that is not expired simple Commented Jul 19, 2021 at 10:44

2 Answers 2

3

The first thing you'll want to do is make sure you have a method to convert your US-format date into a javascript Date instance:

const usFormattedDate = "08/15/2022"

const parseUSDate = str => {
  const parts = str.split("/");
  return new Date(Date.UTC(
    parseInt(parts[2],10),
    parseInt(parts[0],10)-1,
    parseInt(parts[1],10)));
}

console.log(parseUSDate(usFormattedDate))

Why not simply use the Date constructor or Date.parse method? As the docs say:

Note: Parsing of date strings with the Date constructor (and Date.parse(), which works the same way) is strongly discouraged due to browser differences and inconsistencies.

Then you can use this code to parse your date properties - but you probably only want to do this once per object rather than twice per comparison

const parseUSDate = str => {
  const parts = str.split("/");
  return new Date(Date.UTC(
    parseInt(parts[2], 10),
    parseInt(parts[0], 10) - 1,
    parseInt(parts[1], 10)));
}

var now = new Date().getTime();

var data = [{
    date: "04/10/2021",
    event: "event 1",
  },
  {
    date: "08/15/2022",
    event: "event 2",
  },
  {
    date: "09/15/2021",
    event: "event 3",
  },
  {
    date: "01/12/2025",
    event: "event 4",
  },
];

var closest = data
  .map(x => ({ ...x, date: parseUSDate(x.date) })) // Convert date to an actual date
  .filter(x => x.date > now)                       // remove records in the past
  .reduce((a, b) => (a.date - now < b.date - now ? a : b));

console.log(closest);

Note that having done it this way (converting the date property) there is no need for this line:

var countDownDate = new Date(closest.date);

It's just simply

var countDownDate = closest.date;
Sign up to request clarification or add additional context in comments.

2 Comments

thanks so much for doing that and explaining it. i did not take into account that it would show dates that are in the past as closest. how would you edit that so that it doesn't show a date if it has expired (in the past) and then move onto the next closest date
@mike in between the map and reduce use a filter(x => x.date > now) - see updated answer
-1

You can just sort it and find the first element that is not expired

  const sorted = data.sort((a, b) => new Date(a.date) - new Date(b.date))
  const closest = sorted.find(o => new Date(o.date) - now > 0)

<p id="demo"></p>
<p id="celebration"></p>

<script>
  // Get today's date and time
  var now = new Date().getTime();

  var data = [{
      date: "04/10/2021",
      event: "event 1",
    },
    {
      date: "08/15/2022",
      event: "event 2",
    },
    {
      date: "09/15/2021",
      event: "event 3",
    },
    {
      date: "01/12/2025",
      event: "event 4",
    },
  ];

  // var closest = data.reduce( ( a, b ) => ( new Date(a.date) - now < new Date(b.date) - now ? a : b ) );
  const sorted = data.sort((a, b) => new Date(a.date) - new Date(b.date))
  const closest = sorted.find(o => new Date(o.date) - now > 0)

  // Set the date we're counting down to
  var countDownDate = new Date(closest.date);

  // Update the count down every 1 second
  var x = setInterval(function() {
    var now = new Date().getTime();
    // Find the distance between now and the count down date
    var distance = countDownDate - now;

    // Time calculations for days, hours, minutes and seconds
    var days = Math.floor(distance / (1000 * 60 * 60 * 24));
    var hours = Math.floor(
      (distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
    );
    var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
    var seconds = Math.floor((distance % (1000 * 60)) / 1000);

    // Display the result in the element with id="demo"
    document.getElementById("demo").innerHTML =
      days + "d " + hours + "h " + minutes + "m " + seconds + "s ";

    document.getElementById("celebration").innerHTML = closest.event;
    // If the count down is finished, write some text
    if (distance < 0) {
      clearInterval(x);
      document.getElementById("demo").innerHTML = "EXPIRED";
      document.getElementById("celebration").innerHTML = "None";
    }
  }, 1000);
</script>

3 Comments

@mike Note: Parsing of date strings with the Date constructor (and Date.parse(), which works the same way) is strongly discouraged due to browser differences and inconsistencies. - see docs
@Jamiec what to use instead of Date constructor
@decpk see my answer. Or something like date-fns

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.