skip to Main Content

I’m trying to calculate the number of hours between some arbitrary time and when the business will open (or 0 if already open). Is there a more efficientt way to do this without iterating through everything?

function calcOpen(inputDate, scheduleObj){
  var d = inputDate;
  var n = d.getDay();
  var now = d.getHours() + "." + d.getMinutes();
  var delayHours = 0;

  for (let i = 0; i < 168; i++) {
    d = addHours(new Date(), i);
    n = d.getDay();
    now = d.getHours() + "." + d.getMinutes();
    day = scheduleObj[n];
    if (now > day[1] && now < day[2] || now > day[3] && now < day[4]) { 
        delayHours = i;
        break; 
        }
  }
 return addHours(new Date(), delayHours);
}

function addHours(date, hours) {
    date.setHours(date.getHours() + hours);
    return date;
}


var schedule = [
        ["Sunday", 9.30, 12.00, 15.30,22.00],
        ["Monday", 8.30, 12.00, 15.30,19.00],
        ["Tuesday", 8.30, 12.00, 15.30,19.00],
        ["Wednesday", 8.30, 12.00, 15.30,19.00],
        ["Thursday", 8.30, 12.00, 15.30,19.00],
        ["Friday",],
        ["Saturday", 8.00, 13.00]
        ];

var inDate = new Date();
var outdate = new Date();
outdate = calcOpen(inDate, schedule)
console.log('Input Date: ' + inDate);
console.log('Output Date: ' + outDate);

2

Answers


  1. You can use getTime() method for each Date object and compare the values.
    The getTime() method of a Date instance returns the number of milliseconds for that date.
    Read More

    Login or Signup to reply.
  2. Yes, you can make it much more efficient by converting the schedule to single time slots where each slot consists of an open and close time as dates objects.

    To find out if we are open or closed then becomes quite trivial 🙂

    But I threw in some nice formatting for human readability and to calculate time left until close, and time left until open…

    (~~ does the same thing as Math.floor() – me being lazy…)

    Example output:

    It is Thursday, April 27, 2023 at 10:05 AM and we are open for business.
    We will close Thursday, April 27, 2023 at 12:00 PM.
    So we’re open for another 1 hour and 55 minutes.

    It is Saturday, April 29, 2023 at 1:10 PM and we are currently closed.
    We will open again Sunday, April 30, 2023 at 9:30 AM.
    That’s in 20 hours and 20 minutes.

    The code:

    const schedule = [ /* from Sunday to Saturday */
      ["Sunday", 9.30, 12.00, 15.30, 22.00],
      ["Monday", 8.30, 12.00, 15.30, 19.00],
      ["Tuesday", 8.30, 12.00, 15.30, 19.00],
      ["Wednesday", 8.30, 12.00, 15.30, 19.00],
      ["Thursday", 8.30, 12.00, 15.30, 19.00],
      ["Friday"],
      ["Saturday", 8.00, 13.00]
    ];
    
    const timeFormat = [
      'en-US',
      {
        weekday: 'long', year: 'numeric', month: 'long',
        day: 'numeric', hour: 'numeric', minute: 'numeric'
      }
    ];
    
    // convert schedule to a more 'machine readable' format, an array
    // where each item is a time slot: {opens: dateObj, closes: dateObj}
    // and also sort it by date/time
    function parseSchedule(d) {
      return schedule
        .map((x, day) => x.slice(1)
          .map((x, i, a) => i % 2 ? null :
            { day, opens: x, closes: a[i + 1] })
          .filter(x => x)).flat()
        .map(({ day, opens: o, closes: c }) => {
          let opens = new Date(d.getTime() + 24 * 60 * 60 * 1000 *
            ((day < d.getDay() ? day + 7 : day) - d.getDay()));
          let closes = new Date(opens);
          [opens, closes, o, c].forEach((x, i, a, z = a[i + 2]) =>
            i < 2 && x.setHours(~~z) && x.setMinutes((z - ~~z) * 100));
          return { opens, closes };
        }).sort((a, b) => a.opens - b.opens);
    }
    
    // make the answer 'human readable'
    function humanize(d, { open, opens, closes }) {
      const f = x => x.toLocaleString(...timeFormat);
      let x = `It is ${f(d)} and we are ${open ? 'open for business' :
        'currently closed'}.n`;
      !open && (x += `We will open again ${f(opens)}.n`);
      !open && (x += `That's in ${timeDifference(opens, d)}`);
      open && (x += `We will close ${f(closes)}.n`);
      open && (x += `So we're open for another ${timeDifference(closes, d)}`);
      return x + 'n';
    }
    
    // time difference between two dates
    function timeDifference(d1, d2) {
      let diff = Math.abs(d2 - d1);
      let days = ~~(diff / (24 * 60 * 60 * 1000));
      let hours = ~~(diff / (60 * 60 * 1000)) - days * 24;
      let minutes = ~~(diff / (60 * 1000)) - hours * 60;
      return `${days ? days + `day${days === 1 ? '' : 's'}, ` : ''}`
        + `${hours ? hours + ` hour${hours === 1 ? '' : 's'} and ` : ''}`
        + `${minutes} minute${minutes === 1 ? '' : 's'}.`;
    }
    
    // main function
    function openedOrClosed(d = new Date()) {
      let s = parseSchedule(d);
      let isOpen = s.find(({ opens, closes }) => d >= opens && d <= closes);
      if (isOpen) { return humanize(d, { open: true, ...isOpen }); }
      let nextOpen = s.find(({ opens }) => opens > d);
      return humanize(d, { open: false, ...nextOpen });
    }
    
    // Try it out with different dates (remember months are zero-based)
    console.log(openedOrClosed(new Date(2023, 3, 27, 10, 5)));
    console.log(openedOrClosed(new Date(2023, 3, 29, 13, 10)));
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search