如何高效计算距离商家开门的时长?(JavaScript)
如何高效计算距离商家下次开门的时长(无需遍历)
问题描述
我需要计算任意时间点距离商家下次开门的时长(若当前商家已开门则返回0)。目前我通过遍历每一小时的方式实现了功能,想问问有没有不用遍历、更高效的JavaScript实现方案?
现有实现代码
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);
高效实现方案
原代码的问题在于遍历168小时(一周),不仅效率低,还存在时间计算错误(比如把9:30转成9.30作为数字,实际是9.5小时而非9.3小时)。下面是无需遍历的高效实现,核心思路是直接计算当前时间与各营业时段的时间差,而非逐小时检查:
// 辅助函数:将小时格式的数字(如9.30)转换成当天的分钟数 function timeToMinutes(time) { const hours = Math.floor(time); const minutes = Math.round((time - hours) * 100); // 处理9.30这类格式为9小时30分 return hours * 60 + minutes; } // 辅助函数:给日期添加指定分钟数 function addMinutes(date, minutes) { const newDate = new Date(date); newDate.setMinutes(newDate.getMinutes() + minutes); return newDate; } function calcNextOpenTime(inputDate, schedule) { const now = new Date(inputDate); const currentDay = now.getDay(); const currentMinutes = now.getHours() * 60 + now.getMinutes(); const oneDayMinutes = 24 * 60; // 先检查当前日期是否在营业中 const todaySchedule = schedule[currentDay]; if (todaySchedule.length > 1) { // 处理多个营业时段 for (let i = 1; i < todaySchedule.length; i += 2) { const openTime = timeToMinutes(todaySchedule[i]); const closeTime = timeToMinutes(todaySchedule[i + 1]); // 如果当前时间在营业时段内,返回当前时间 if (currentMinutes >= openTime && currentMinutes < closeTime) { return new Date(now); } } } // 计算当天是否还有未开始的营业时段 if (todaySchedule.length > 1) { for (let i = 1; i < todaySchedule.length; i += 2) { const openTime = timeToMinutes(todaySchedule[i]); if (currentMinutes < openTime) { // 当天还有开门时间,计算时间差 const delayMinutes = openTime - currentMinutes; return addMinutes(now, delayMinutes); } } } // 当天已无营业时段,检查后续日期 for (let dayOffset = 1; dayOffset < 7; dayOffset++) { const targetDay = (currentDay + dayOffset) % 7; const targetSchedule = schedule[targetDay]; if (targetSchedule.length > 1) { // 取该天第一个营业时段的开始时间 const firstOpenTime = timeToMinutes(targetSchedule[1]); // 计算距离该时段的总分钟数:(dayOffset天的分钟数) + 当天开始到开门的分钟数 const delayMinutes = dayOffset * oneDayMinutes + (firstOpenTime - currentMinutes); return addMinutes(now, delayMinutes); } } // 如果一周都没营业(极端情况),返回null return null; } // 测试代码 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 = calcNextOpenTime(inDate, schedule); console.log('Input Date: ' + inDate); console.log('Next Open Date: ' + outDate);
方案优势
- 无逐小时遍历:最多循环7天(一周),远低于原168次循环,效率大幅提升
- 时间计算精准:将时间统一转换成分钟数比较,避免了原代码中
9.30作为数字的精度错误 - 逻辑清晰:分三步处理:当前时段检查、当天剩余时段检查、后续日期检查,覆盖所有场景
内容的提问来源于stack exchange,提问作者DDulla
相关产品推荐
相关产品推荐

