Jython example: calculate next window for a scheduled task (weekly)

I was faced with the task to schedule a deployment during planned weekly deployment windows. The solution should be a general approach such as that as soon as an approval is in place the deployment is to be scheduled for the next possible window. So it was not possible to just schedule a start date with the “Scheduled start date” option inside a task. Also, to schedule all possible deploy windows (two per week) in the calendar would be too much of a manual task. A Jython script to the rescue!
Sharing it here in case it is useful for someone.

The main part of the logic has to be to know the current day and calculate the difference to the next possible day:

def getDeployDateTime(day, hour, minute):
    current = Calendar.getInstance()
    #get current date&time
    current.setTime(Date())

    #calculate: in how many days is "day". Need to add 7 in case we are already past that day in the week
    dayDiff = (day - current.get(Calendar.DAY_OF_WEEK) + 7) % 7

    #check if we are already past the window in the day, if yes, need to wait one week
    if dayDiff == 0 and current.get(Calendar.HOUR_OF_DAY) >= hour:
        dayDiff = 7
    current.add(Calendar.DAY_OF_WEEK, dayDiff)
    current.set(Calendar.HOUR_OF_DAY, hour)
    current.set(Calendar.MINUTE, minute)
    return current

So this function will return a date in the future for the next down time.
E.g. if today is Tuesday and my my deployment window is Wednesday at 4 am, the function will return a date which is one day in the future, at 3am. Or if today is Wednesday at 5pm it will return a date 7 days in the future at 3am.

In my case if was even faced with the task for two possible deployment windows in the week, so here is the complete script in case anyone is interested. Let me know if you have any questions :slight_smile:

from java.util import Calendar, Date

deployDay1 = Calendar.MONDAY
deployDay2 = Calendar.FRIDAY
deployHour = 22
deployMinute = 0

def nextTask():
  phase = getCurrentPhase()
  index = 0
  for item in phase.tasks:
    if item.id == task.id:
      break
    index = index + 1
  return task.getPhase().tasks[index+1]



def getDeployDateTime(day, hour, minute):
    current = Calendar.getInstance()
    current.setTime(Date())
    
    #calculate: in how many days is "day"
    dayDiff = (day - current.get(Calendar.DAY_OF_WEEK) + 7) % 7
    
    #check if we are already past the window in the day, if yes, need to wait one week
    if dayDiff == 0 and current.get(Calendar.HOUR_OF_DAY) >= hour:
        dayDiff = 7
    current.add(Calendar.DAY_OF_WEEK, dayDiff)
    current.set(Calendar.HOUR_OF_DAY, hour)
    current.set(Calendar.MINUTE, minute)
    return current
    

taskToSchedule = nextTask()

date1 = getDeployDateTime(deployDay1, deployHour, deployMinute)
date2 = getDeployDateTime(deployDay2, deployHour, deployMinute)

print ("Next date for deploy day one:")
print (date1.getTime())
print ("Next date for deploy day two:")
print (date2.getTime())


if date1.before(date2):
    print("Date one comes next, scheduling task " + taskToSchedule.title + " for that day.")
    taskToSchedule.setScheduledStartDate(date1.getTime())
else:
    print("Date two comes next, scheduling task " + taskToSchedule.title + " for that day.")
    taskToSchedule.setScheduledStartDate(date2.getTime())

taskApi.updateTask(taskToSchedule)