查找下一个繁忙时间的免费小时

使用Google Calendar API时,需要:

start (epoch时间) end (epoch时间) timeZone (即America/Los_Angeles

响应是一个名为busy的数组,其中包含{ start <Date>, end<Date>}

我的目标:findstartend之间的下一个空闲时间。

有以下限制:

  • 必须在工作日(星期一至星期五)
  • 必须在工作时间(上午9时至下午5时)

这是我试过的:

  1. 从上午9点到下午5点,每天手动创build更多busy对象
  2. 手动为周六和周日创build更多busy对象
  3. 合并所有busy街区,所以不会有交集

现在采取相反的时间,这是free时间。

第一个空闲时间对象( {start <Date>,end <Date>} ),其startend > = 1 hour

是下一个空闲时间。 如果没有free对象大于1小时,则在startend之间不存在空闲时间


这个问题听起来太多了,我想听听build议


这是我的代码到目前为止(工作):

 const moment=require('moment-timezone'); const chrono = require('chrono-node'); const ms = require('ms'); /** * given start and end dates and list of busy dates, return the next free hour * @param {Number} start - epoch date * @param {Number} end - epoch date * @param {String} timeZone - to get the actual date data (like day of week for the start,end dates) * @param {Array} epochBusyRanges - [{start,end},{start,end}...] all epoch dates * @return {Number|null} if number, this is the start of the next available free hour */ function nextAvailableHour(start, end, timeZone, epochBusyRanges) { //SOME SETTINGS const minMeetingTimeMS = ms('1 hour'); const startWorkDayAM = 9; const endWorkDayPM = 5; const weekendStartDateTime = 'friday 23:59'; const weekendEndDateTime = 'sunday 23:59'; //manually put "busy" hours (work days (Monday to Friday) + work hours (9 to 17) are free,else busy) const momentStart = moment.tz(start, timeZone); const momentEnd = moment.tz(end, timeZone); let next5pm = moment.tz(chrono.parseDate(`${endWorkDayPM}pm`, momentStart), timeZone); let next9am; while (Number(next5pm) < Number(momentEnd)) { next9am = moment.tz(chrono.parseDate(`tomorrow ${startWorkDayAM}am`, next5pm), timeZone); epochBusyRanges.push({start: Number(next5pm), end: Number(next9am)}); next5pm = moment.tz(chrono.parseDate(`${endWorkDayPM}pm`, next9am), timeZone); } //we need to put also yesterday's 5pm-9am is the start is before 9am, otherwise it will make a "false" free time.. if (momentStart.hour() < startWorkDayAM) { const yesterday5pm = moment.tz(chrono.parseDate(`yesterday ${endWorkDayPM}pm`, momentStart), timeZone); const today9am = moment.tz(chrono.parseDate(`tomorrow ${startWorkDayAM}am`, yesterday5pm), timeZone); epochBusyRanges.push({start: Number(yesterday5pm), end: Number(today9am)}); } //insert weekends manually let nextWeekendStart = moment.tz(chrono.parseDate(`this ${weekendStartDateTime}`, momentStart), timeZone); let nextWeekendEnd; while (Number(nextWeekendStart) < Number(momentEnd)) { nextWeekendEnd = moment.tz(chrono.parseDate(`next ${weekendEndDateTime}`, nextWeekendStart), timeZone); epochBusyRanges.push({start: Number(nextWeekendStart), end: Number(nextWeekendEnd)}); nextWeekendStart = moment.tz(chrono.parseDate(`this ${weekendStartDateTime}`, nextWeekendEnd), timeZone); } //we need also last weekend if we happen to be inside it. if (momentStart.day() === 0 || momentStart.day() === 6) { const lastWeekendStart = moment.tz(chrono.parseDate(weekendStartDateTime, momentStart), timeZone); const lastWeekendEnd = moment.tz(chrono.parseDate(`next ${weekendEndDateTime}`, lastWeekendStart), timeZone); epochBusyRanges.push({start: Number(lastWeekendStart), end: Number(lastWeekendEnd)}); } //sort the times epochBusyRanges.sort((o1, o2) => o1.start > o2.start); //merge busy blocks epochBusyRanges = merge(epochBusyRanges.map(o => [o.start, o.end])); //map again to our format epochBusyRanges = epochBusyRanges.map(o => {return {start: o[0], end: o[1]}}); //find next hour for (let i = 0; i < epochBusyRanges.length; i++) { const _start = i === 0 ? start : epochBusyRanges[i - 1].end; const _end = epochBusyRanges[i].start; if ((_end - _start) >= minMeetingTimeMS) { return _start; } } //maybe there is a free time after the last busy block if (epochBusyRanges.length > 0) { const _start = epochBusyRanges[epochBusyRanges.length - 1].end; if ((end - _start) >= minMeetingTimeMS) { return _start } } //not busy time at all. so just check for the duration between start and end if (epochBusyRanges.length === 0) { if ((end - start) >= minMeetingTimeMS) { return start; } } return null; } //helper function: given [[10,20],[12,30],[40,50]] --- > [[10,30],[40,50]] function merge(arr) { // copy and sort the array const result = arr.slice().sort((a, b) => a[0] > b[0]); let i = 0; while (i < result.length - 1) { const current = result[i], next = result[i + 1]; // check if there is an overlapping if (current[1] >= next[0]) { current[1] = Math.max(current[1], next[1]); // remove next result.splice(i + 1, 1); } else { // move to next i++; } } return result; } 

使用时间戳或范围通常不是一件容易的事情,而且您正在努力做到这一点。

这就是说,你可能能够简化你的逻辑与moment-range 。 它支持基本的算术(加,减,重叠,交叉,…)和迭代。