如何使用 javascript 中的时区检查打开到关闭时间是否已过

How to check if open to close time has elapse using timezone in javascript

我在我的网络应用程序中有以下功能,使用国家/地区时区检查从 OPENCLOSE 的时间是否已经过去,并且工作正常。我正在尝试优化我的网站,所以我的问题是如何在不使用时刻时区的情况下在 javascript 中实现这样的功能?时区文件很大,这是我网站上的唯一用法。

    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>

您可以使用 Intl.DateTimeFormat constructor 来做同样的事情。据我了解,您想知道从 8:00 到 12:00 的商店是否正在营业,例如 Asia/Kuala_Lumpur 当前是否营业。

可能可以或多或少地逐行转换您的代码,但我只是重构了它并简化了逻辑(叫我懒惰......)。通过这种方式,它可以获取所需位置的当前时间,将其转换为自午夜以来的分钟数,然后查看它是在开始时间之前还是在结束时间之后。

对于午夜 (12:00 AM),时间转换为 0 分钟,因此如果 closingTime 为 0,则假定为一天结束,因此设置为 1,440 (即一天结束时的午夜)。

测试时间只在同一天有效,如果开放时间超过午夜则需要重构它。我刚刚测试了午夜到中午和中午到午夜,所以一个应该总是显示 "open" 而另一个 "closed".

您也可以考虑使用 Luxon,它的作用与 moment.js + moment.tz 相同,但使用 Intl 对象而不是包含的数据。

编辑

要处理超过午夜的时间,您可以在时间中包含日期(如果您想使用固定的每日时间表则不方便),或者您可以使用 "inside" 和 "outside" 测试,如果关闭时间早于打开时间,则测试时间是否在打开时间和关闭时间之间 而不是 。这可以通过比较 openMin 和 close 时间并调整测试来完成。

这不会处理重叠的开始和结束时间,但这并不真正适合常规的每日时间表(尽管它可能适合每周或更长的时间表)。

/* @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)}`
));