Search code examples
javascriptdatetimemomentjsmoment-timezone

How to determine if store is open or closed using moment.js and moment timezone?


Am using momentjs in my website to determine whether a store is still open or closed based on the selected open, close time and timezone of the specific store location. The function i made works in some time range but doesn't in some.

JS LIBRARY

/moment.js
/moment-timezone-with-data-10-year-range.js

My Sample code

 function isOpen(openTime, closeTime, timezone){
  var  status = "closed";
  if(openTime != "24HR"){
    const  now = moment().tz(timezone);
    const  storeOpenTime = moment.tz(openTime, "h:mmA", timezone);
    const  storeCloseTime = moment.tz(closeTime, "h:mmA", timezone);
    /* const  storeOpenTime = moment.tz(Date.now(Date(openTime)), "h:mmA", timezone);
    const  storeCloseTime = moment.tz(Date.now(Date(closeTime)), "h:mmA", timezone);*/
    const  check = now.isBetween(storeOpenTime, storeCloseTime);
    if(check || check == true){
      status = "open";
    }
  }else{
    status = "open";
  }
  return status;
}

Let assume that the current time in malaysia kuala Lumpur is 11:34PM, and i run the below code

 isOpen("8:00AM", "12:20AM", "Asia/Kuala_Lumpur") 
 returned output = closed

The expected output for the above code is open, but if run the below code when the current time in malaysia kuala Lumpur is 11:34PM.

isOpen("8:00AM", "10:20PM", "Asia/Kuala_Lumpur")
returned output = closed

The above output is correct.

Please my question is how do i use momentjs to check if time between open and close has passed using the country timezone?


Solution

  • Here is your code corrected and commented:

    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
      // See https://github.com/moment/moment-timezone/issues/119
      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";
    }
    
    // Testing
    const zone = "Asia/Kuala_Lumpur";
    console.log("now", moment.tz(zone).format("h:mmA"));
    console.log("24HR", isOpen("24HR", undefined, zone));
    console.log("2:00AM-8:00AM", isOpen("2:00AM", "8:00AM", zone));
    console.log("8:00AM-2:00PM", isOpen("8:00AM", "2:00PM", zone));
    console.log("2:00PM-8:00PM", isOpen("2:00PM", "8:00PM", zone));
    console.log("8:00PM-2:00AM", isOpen("8:00PM", "2:00AM", 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>

    The main issue you had is that you have to work around the bug described in issue #119, which is that when parsing time-only in a specific time zone, Moment incorrectly applies the UTC date instead of the tz-specific local date.

    Secondarily, you also need to handle the case of the time range spanning over midnight, by checking for the open/close moments being out of sequence. When they are, the comparison needs to be done differently - by checking if the current time is after opening or before closing.