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?
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'}`
)
});