Home > Blockchain >  Check if time in minutes since start of week is between two values (value in minutes since start of
Check if time in minutes since start of week is between two values (value in minutes since start of

Time:11-26

So i'm using the Zendesk API to fetch the schedule of an instance, the API returns an object that contains an array called intervals which looks like this:

[
  { "start_time": 1980, "end_time": 2460 },
  { "start_time": 3420, "end_time": 3900 },
  { "start_time": 4860, "end_time": 5340 },
  { "start_time": 6300, "end_time": 6780 },
  { "start_time": 7740, "end_time": 8220 }
]

This example just translates to 9AM to 5PM in minutes for each business day of the week with the value being in minutes since the start of the week which is actually Midnight on Sunday (meaning a value of 720 would be noon on Sunday).

I'm trying to implement some server side logic that loops through the intervals and checks if the current time is between the intervals for that given day making it possible to detect if it's currently within business hours or not.

I was thinking the moment.js library might be useful for this and I have been playing around with the .startOf('week') and .diff() functions but I keep getting blocked and I fear it might not be as reliable as I'd like given that i'm unsure if moment starts the week on a Monday or Sunday.

So far i've got

let isBusinessHours = false;

function checkBusinessHours() {
  intervals.map((interval, key) => {
    //offset weekdays to match interval keys
    let currentDay = moment().weekday() -1; 

    //create comparison start & end times based on interval start & end times
    let startTime = moment().startOf('week').add(interval.start_time, 'minutes'); 
    let endTime = moment().startOf('week').add(interval.end_time, 'minutes');

    //check to see if it's business hours
    if (moment().isBetween(startTime, endTime) && currentDay === key) {
      isBusinessHours = true;
    } 
  })
  return isBusinessHours;
}

But i'm unsure if this is the best way to go about checking this?

CodePudding user response:

Using an offset from the start of Sunday doesn't seem like a good idea where daylight saving is observed. Most places use Sunday as the changeover day, so on those days Sunday isn't 24 hours long and all offsets for that week will be ± the DST shift in minutes.

Ignoring that issue, it's fairly simple to convert a date to an offset: subtract the previous Sunday and divide the difference by the milliseconds in one minute. Converting from an offset to Date is the opposite: add the minutes to a Date for the previous Sunday, e.g.

// Return Date for start of Sunday 00:00 before d
function startOfWeek(d = new Date()) {
  return new Date(d.getFullYear(), d.getMonth(), d.getDate() - d.getDay());
}

// Convert a Date to an offset in minutes
// from start of previous Sunday
function dateToOffset(d = new Date()) {
  return Math.floor((d - startOfWeek(d)) / 6e4);  
}

// Convert an offset to date, default is current week
// Week starts on Sunday
function offsetToDate(offset, d = new Date()) {
  let date = startOfWeek(d);
  date.setMinutes(offset);
  return date;
}

// Examples
// Just a helper to format dates
function format(d) {
  return d.toLocaleString('en', {
    weekday: 'short',
    hour: '2-digit',
    hour12: false,
    minute: '2-digit'
  });
}

// Show current offset
let d = new Date();
console.log(`For ${format(d)} the offset is ${dateToOffset(d)}`);

// Convert offsets to dates
let data = [
  { "start_time": 1980, "end_time": 2460 },
  { "start_time": 3420, "end_time": 3900 },
  { "start_time": 4860, "end_time": 5340 },
  { "start_time": 6300, "end_time": 6780 },
  { "start_time": 7740, "end_time": 8220 }
];
data.forEach(o => console.log(
 `Start: ${format(offsetToDate(o.start_time))}  `  
 `End  : ${format(offsetToDate(o.end_time))}`
));

// Find out if dates are between a start and end
[new Date(2021,10,25,12), // Thu 25 Nov 12:00
 new Date(2021,10,27,12), // Sat 25 Nov 12:00
 new Date()               // Now
].forEach(d => {
  let offset = dateToOffset(d);
  console.log(
    `Is ${format(d)} between a start and end? `  
    `${!!data.find(obj => obj.start_time <= offset && obj.end_time > offset)? 'Yes' : 'No'}`
  )
});
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

You can get the start of the week, then add the start_time and end_time minutes to it, which will get you the adjusted Date object, which you can then use to compare with the current Date.

I used date-fns instead of moment.js, but you can probably translate the code if needed.

const { startOfWeek, add, compareAsc, compareDesc } = require("date-fns")

const intervals = [
  { "start_time": 1980, "end_time": 2460 },
  { "start_time": 3420, "end_time": 3900 },
  { "start_time": 4860, "end_time": 5340 },
  { "start_time": 6300, "end_time": 6780 },
  { "start_time": 7740, "end_time": 8220 }
]

const startOfWeekDate = startOfWeek(new Date());
const now = new Date();
let isBusinessHour = false;
for (let i = 0; i < intervals.length; i  ) {
  const startTime = add(startOfWeekDate, { minutes: intervals[i].start_time });
  const endTime = add(startOfWeekDate, { minutes: intervals[i].end_time });
  if (compareAsc(now, startTime) === 1 && compareDesc(now, endTime) === 1) {
    isBusinessHour = true;
  }
}

console.log("isBusinessHour", isBusinessHour)

Note that the startOfWeek function accepts a 2nd argument to specify which day the week starts (usually either Sunday or Monday)

  • Related