protected void createTimerForDelayedExecution(
     CommandContext commandContext, List<ProcessDefinitionEntity> processDefinitions) {
   for (ProcessDefinitionEntity processDefinition : processDefinitions) {
     TimerEntity timer = new TimerEntity();
     timer.setProcessDefinitionId(processDefinition.getId());
     timer.setDuedate(executionDate);
     timer.setJobHandlerType(getDelayedExecutionJobHandlerType());
     timer.setJobHandlerConfiguration(
         TimerChangeProcessDefinitionSuspensionStateJobHandler.createJobHandlerConfiguration(
             includeProcessInstances));
     commandContext.getJobEntityManager().schedule(timer);
   }
 }
  public TimerEntity prepareTimerEntity(ExecutionEntity executionEntity) {
    BusinessCalendar businessCalendar =
        Context.getProcessEngineConfiguration()
            .getBusinessCalendarManager()
            .getBusinessCalendar(type.calendarName);

    if (description == null) {
      // Prevent NPE from happening in the next line
      throw new ActivitiIllegalArgumentException(
          "Timer '"
              + executionEntity.getActivityId()
              + "' was not configured with a valid duration/time");
    }

    String endDateString = null;
    String dueDateString = null;
    Date duedate = null;
    Date endDate = null;

    // ACT-1415: timer-declaration on start-event may contain expressions NOT
    // evaluating variables but other context, evaluating should happen nevertheless
    VariableScope scopeForExpression = executionEntity;
    if (scopeForExpression == null) {
      scopeForExpression = NoExecutionVariableScope.getSharedInstance();
    }

    if (endDateExpression != null && !(scopeForExpression instanceof NoExecutionVariableScope)) {
      Object endDateValue = endDateExpression.getValue(scopeForExpression);
      if (endDateValue instanceof String) {
        endDateString = (String) endDateValue;
      } else if (endDateValue instanceof Date) {
        endDate = (Date) endDateValue;
      } else if (endDateValue instanceof DateTime) {
        // Joda DateTime support
        duedate = ((DateTime) endDateValue).toDate();
      } else {
        throw new ActivitiException(
            "Timer '"
                + executionEntity.getActivityId()
                + "' was not configured with a valid duration/time, either hand in a java.util.Date or a String in format 'yyyy-MM-dd'T'hh:mm:ss'");
      }

      if (endDate == null) {
        endDate = businessCalendar.resolveEndDate(endDateString);
      }
    }

    Object dueDateValue = description.getValue(scopeForExpression);
    if (dueDateValue instanceof String) {
      dueDateString = (String) dueDateValue;
    } else if (dueDateValue instanceof Date) {
      duedate = (Date) dueDateValue;
    } else if (dueDateValue instanceof DateTime) {
      // Joda DateTime support
      duedate = ((DateTime) dueDateValue).toDate();
    } else if (dueDateValue != null) {
      // dueDateValue==null is OK - but unexpected class type must throw an error.
      throw new ActivitiException(
          "Timer '"
              + executionEntity.getActivityId()
              + "' was not configured with a valid duration/time, either hand in a java.util.Date or a String in format 'yyyy-MM-dd'T'hh:mm:ss'");
    }

    if (duedate == null && dueDateString != null) {
      duedate = businessCalendar.resolveDuedate(dueDateString);
    }

    TimerEntity timer = null;
    // if dueDateValue is null -> this is OK - timer will be null and job not scheduled
    if (duedate != null) {
      timer = new TimerEntity(this);
      timer.setDuedate(duedate);
      timer.setEndDate(endDate);

      if (executionEntity != null) {
        timer.setExecution(executionEntity);
        timer.setProcessDefinitionId(executionEntity.getProcessDefinitionId());
        timer.setProcessInstanceId(executionEntity.getProcessInstanceId());

        // Inherit tenant identifier (if applicable)
        if (executionEntity != null && executionEntity.getTenantId() != null) {
          timer.setTenantId(executionEntity.getTenantId());
        }
      }

      if (type == TimerDeclarationType.CYCLE) {

        // See ACT-1427: A boundary timer with a cancelActivity='true', doesn't need to repeat
        // itself
        boolean repeat = !isInterruptingTimer;

        // ACT-1951: intermediate catching timer events shouldn't repeat according to spec
        if (TimerCatchIntermediateEventJobHandler.TYPE.equals(jobHandlerType)) {
          repeat = false;
          if (endDate != null) {
            long endDateMiliss = endDate.getTime();
            long dueDateMiliss = duedate.getTime();
            long dueDate = Math.min(endDateMiliss, dueDateMiliss);
            timer.setDuedate(new Date(dueDate));
          }
        }

        if (repeat) {
          String prepared = prepareRepeat(dueDateString);
          timer.setRepeat(prepared);
        }
      }
    }
    return timer;
  }