Ad

How To Check If Open To Close Time Has Elapse Using Timezone In Javascript

I have this below functionin my webapp to check if from OPEN to CLOSE time has elapse using a country timezone and it's working fine. Am trying to optimize my website, so my question is how can i make a function like this in javascript without the use of moment timezone? The moment timezone file is large and this is the only usage of it on my website.

    function isOpen(openTime, closeTime, timezone) {
    
      // handle special case
      if (openTime === "24HR") {
        return "open";
      }
    
      // get the current date and time in the given time zone
      const now = moment.tz(timezone);
    
      // Get the exact open and close times on that date in the given time zone
      const date = now.format("YYYY-MM-DD");
      const storeOpenTime = moment.tz(date + ' ' + openTime, "YYYY-MM-DD h:mmA", timezone);
      const storeCloseTime = moment.tz(date + ' ' + closeTime, "YYYY-MM-DD h:mmA", timezone);
    
      let check;
      if (storeCloseTime.isBefore(storeOpenTime)) {
        // Handle ranges that span over midnight
        check = now.isAfter(storeOpenTime) || now.isBefore(storeCloseTime);
      } else {
        // Normal range check using an inclusive start time and exclusive end time
        check = now.isBetween(storeOpenTime, storeCloseTime, null, '[)');
      }
    
      return check ? "open" : "closed";
    }
    
const zone = "Asia/Kuala_Lumpur";
console.log("24HR", isOpen("24HR", undefined, zone));
console.log("2:00AM-8:00AM", isOpen("2:00AM", "8:00AM", zone));
console.log("8:00AM-10:00AM", isOpen("8:00AM", "10:00PM", zone));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.27/moment-timezone-with-data-10-year-range.min.js"></script>

Ad

Answer

You can use the Intl.DateTimeFormat constructor to do the same thing. As I understand it, you want to know if a store that is open say from 8:00 to 12:00 in say Asia/Kuala_Lumpur is currently open.

It's probably possible to convert your code more or less line by line, but I've just refactored it and simplified the logic (call me lazy…). This way it gets the current time in the desired location, converts it to minutes since midnight, then sees if that is before the start time or on or after the closing time.

For midnight (12:00 AM), the time converts to 0 minutes so if closingTime is 0, it's assumed to be end of day so is set to 1,440 (i.e. midnight at end of day).

The test times only work on the same day, if the open time runs over midnight you'll need to refactor it. I've just tested midnight to noon and noon to midnight so one should always show "open" and the other "closed".

You might also consider using Luxon, it does what moment.js + moment.tz does but uses the Intl object instead of included data.

Edit

To deal with times that go over midnight, you can either include dates in the time (not convenient if you want to use a regular daily schedule) or you can have an "inside" and "outside" test so that if closing time is before the open time, you test if the time is not between open and close times. That can be done by comparing openMin and close times and adjusting the test.

This will not deal with overlapping start and end times, but that doesn't really fit a regular daily schedule (though it might fit a weekly or longer schedule).

/* @param {string} location: IANA representative location
** @param {Date} date: date instance to get time from, default is now
** @returns {string} time in location in h:mm ap format
*/
function getTime(location, date = new Date()) {
  return date.toLocaleString('en', {
    timeZone: location,
    hour  :  'numeric',
    minute: '2-digit',
    dayPeriod: 'short'
  });
}

/* @param {string} time: h:mm A
** @returns {number} time converted to minutes
*/
function timeToMin(time) {
  let [h, m] = time.match(/\d\d?/g);
  h = h%12;
  if (/pm$/i.test(time)) h +=12
  return h * 60 + parseInt(m);
}

/* @param {string} openTime: opening time in h:mm ap format
** @param {string} closeTime: closing time in h:mm ap format
** @param {string} location: IANA representative location
** @return {string} open if current time is within openTime and closeTime in location,
**                  closed otherwise
*/
function isOpen(openTime, closeTime, location) {
  if (openTime == '24HR') return 'open';
  let nowTime = getTime(location);
  let nowMin = timeToMin(nowTime);
  let openMin = timeToMin(openTime);
  let closeMin = timeToMin(closeTime) || 1440;
  // Open and close on same day
  if (openMin < closeMin) {
    return nowMin < openMin || nowMin >= closeMin ? 'closed' : 'open';
  // Close on day after open
  } else {
    return nowMin >= openMin && nowMin < closeMin ? 'open' : 'closed';
  }
}

// Time in KL
let loc = "Asia/Kuala_Lumpur";
console.log(`In ${loc} it's ${getTime(loc)}`);

// Examples
[["24HR", undefined, loc],     // Open 24 hrs
 ["12:00AM", "12:00PM", loc],  // Midnight to noon
 ["12:00PM", "12:00AM", loc],  // Noon to midnight
 ["6:30PM",  "04:00AM", loc],  // Over midnight
].forEach(args => console.log(
  `${args[0]}${args[1]? '-' + args[1] : ''} ${isOpen(...args)}`
));

Ad
source: stackoverflow.com
Ad