Reputation: 179
The Problem :
If a person has been given 2 hours for a task, the script needs to calculate when it should be done. The planned time should not be after office hours. It should take into account the time that is left today and add the remaining time to the next office hours. But the next day can be a weekend or can be a holiday which needs to be skipped.
What the script does :
Given a date and time, it adds x number of hours. While doing that it skips off-hours and adds the remaining hour to the next day after opening time. If the next day is a weekend or a holiday, it skips that as well.
Where I am getting stuck :
If the number of hours I add makes it go to the next day, the calculation becomes off. For example, if at 17 hours I add 10 hours, the logic breaks.
The code :
function w(d) {
let sheet = ss.getSheetByName("Holidays")
let holidayDates = sheet.getRange(2,1,sheet.getLastRow()-1,1).getValues()
let open_h = 9 //opening time
let close_h = 18 //closing time
let work_h = close_h - open_h //total working hours
let add_h = 2 //time that was given to do the task (in hours) <- If adding this takes the end_date past 00:00:00 the logic breaks.
d.setDate(d.getDate() + (1 + 7 - d.getDay()) % 7);
let end_date = d
if (end_date.getHours() < open_h) {
end_date.setHours(open_h)
}
end_date.setTime(end_date.getTime() + (add_h*60*60*1000))
if (end_date.getHours()>open_h && end_date.getHours()<close_h) {
} else {
end_date.setTime(end_date.getTime()-(work_h*60*60*1000))
if (end_date.getDay() == 6 || end_date.getDay() == 0 ) {end_date.setDate(next_Monday) } else {
end_date.setDate(end_date.getDate() + 1)
}
}
holidayDates.forEach(function(hd) {
let b = new Date(d).setHours(0,0,0,0)
if (hd[0].getTime() === new Date(b).getTime()) {
end_date.setDate(end_date.getDate() + 1)
}
})
return end_date
}
Upvotes: 0
Views: 266
Reputation: 5953
You can refer to this sample code to compute for the end datetime based on the task hours.
var ss = SpreadsheetApp.getActiveSpreadsheet();
function test(){
var startDate = new Date("August 27 2021 17:00:00")
Logger.log(startDate);
var endDate = w(startDate);
Logger.log(endDate);
}
function w(d) {
let sheet = ss.getSheetByName("Holidays")
let holidayDates = sheet.getRange(2,1,sheet.getLastRow()-1,1).getValues().flat();
//convert holiday dates to array string in yyyy-MM-dd format
let holidayDatesStr = holidayDates.map(x => Utilities.formatDate(x, Session.getScriptTimeZone(),"yyyy-MM-dd"));
let open_h = 9 //opening time
let close_h = 18 //closing time
let work_h = close_h - open_h //total working hours
let add_h = 10 //time that was given to do the task (in hours) <- If adding this takes the end_date past 00:00:00 the logic breaks.
//Compute for days and remaining hours needed
let end_date = d
let remain_h = close_h - d.getHours();//remaining hours for the current day
let targetDays = 0;
let targetHrs = 0;
if(remain_h - add_h < 0){
targetDays++; //Task cannot be finished today. Increment target day
targetDays += Math.floor((add_h - remain_h) / work_h); //Get total number of days to complete
targetHrs = (add_h - remain_h) % work_h; //Get remaining hours of the day
if(targetHrs == 0){
//task can be finished on the closing hour. Reduce targetDays by 1
targetDays--;
//Add work_h to the current targetHrs
targetHrs += work_h;
}
Logger.log("Target Days: "+targetDays)
Logger.log("Target Hours: "+targetHrs);
//Increment days (Skip weekends and holidays)
while (targetDays>0){
//Increment end date by 1
end_date.setDate(end_date.getDate()+1);
//Check if end date falls under weekends
if((end_date.getDay() == 0)||(end_date.getDay() == 6)){
continue; //skip current end date
}
//Check if end date is a holiday
let endDateStr = Utilities.formatDate(end_date, Session.getScriptTimeZone(),"yyyy-MM-dd");
if(holidayDatesStr.includes(endDateStr)){
continue; //skip current end date
}
//valid date
targetDays--;
}
//Set hours
end_date.setHours(open_h + targetHrs);
}else{
targetDays = 0;
targetHrs = add_h;
end_date.setHours(end_date.getHours()+add_h); //Add to current hour
}
return end_date
}
If add_h = 10 and startDate = "August 27 2021 17:00:00",
End date will be "August 30, 2021 18:00"
1:07:42 AM Notice Execution started
1:07:43 AM Info Fri Aug 27 17:00:00 GMT+08:00 2021
1:07:43 AM Info Target Days: 1
1:07:43 AM Info Target Hours: 9
1:07:43 AM Info Mon Aug 30 18:00:00 GMT+08:00 2021
1:07:43 AM Notice Execution completed
If add_h = 20 and startDate = "August 27 2021 17:00:00",
End date will be "September 3, 2021 18:00" since 8/31 and 9/2 are a holiday.
1:09:24 AM Notice Execution started
1:09:25 AM Info Fri Aug 27 17:00:00 GMT+08:00 2021
1:09:25 AM Info Target Days: 3
1:09:25 AM Info Target Hours: 1
1:09:25 AM Info Fri Sep 03 10:00:00 GMT+08:00 2021
1:09:25 AM Notice Execution completed
See sample code for floating add hours
var ss = SpreadsheetApp.getActiveSpreadsheet();
function test(){
var startDate = new Date("August 27 2021 17:30:00")
Logger.log(startDate);
var endDate = w(startDate);
Logger.log(endDate);
}
function w(d) {
let sheet = ss.getSheetByName("Holidays")
let holidayDates = sheet.getRange(2,1,sheet.getLastRow()-1,1).getValues().flat();
//convert holiday dates to array string in yyyy-MM-dd format
let holidayDatesStr = holidayDates.map(x => Utilities.formatDate(x, Session.getScriptTimeZone(),"yyyy-MM-dd"));
let open_h = 9 //opening time
let close_h = 18 //closing time
let work_h = close_h - open_h //total working hours
let add_h = 10.25 //time that was given to do the task (in hours) <- If adding this takes the end_date past 00:00:00 the logic breaks.
//Compute for days and remaining hours needed
let end_date = d
let remain_h = close_h - d.getHours();//remaining hours for the current day
let targetDays = 0;
let targetHrs = 0;
let targetMins = 0;
if(remain_h - add_h < 0){
targetDays++; //Task cannot be finished today. Increment target day
targetDays += Math.floor((add_h - remain_h) / work_h); //Get total number of days to complete
targetHrs = (add_h - remain_h) % work_h; //Get remaining hours of the day
if(targetHrs == 0){
//task can be finished on the closing hour. Reduce targetDays by 1
targetDays--;
//Add work_h to the current targetHrs
targetHrs += work_h;
}
targetMins = (targetHrs - Math.floor(targetHrs)) * 60;
Logger.log("Target Days: "+targetDays)
Logger.log("Target Hours: "+targetHrs);
Logger.log("Target Minutes: "+targetMins);
//Increment days (Skip weekends and holidays)
while (targetDays>0){
//Increment end date by 1
end_date.setDate(end_date.getDate()+1);
//Check if end date falls under weekends
if((end_date.getDay() == 0)||(end_date.getDay() == 6)){
continue; //skip current end date
}
//Check if end date is a holiday
let endDateStr = Utilities.formatDate(end_date, Session.getScriptTimeZone(),"yyyy-MM-dd");
if(holidayDatesStr.includes(endDateStr)){
continue; //skip current end date
}
//valid date
targetDays--;
}
//Set hours (decimal ignored)
end_date.setHours(open_h + targetHrs);
//Set minutes
end_date.setMinutes(end_date.getMinutes() + targetMins);
}else{
targetDays = 0;
targetHrs = add_h;
targetMins = (targetHrs - Math.floor(targetHrs)) * 60;
end_date.setHours(end_date.getHours()+add_h); //Add to current hour
end_date.setMinutes(end_date.getMinutes() + targetMins);
}
return end_date
}
Upvotes: 1