/* * Copyright (c) 2016 EMC Corporation * All Rights Reserved */ package com.emc.sa.model.util; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; import com.emc.storageos.db.client.model.uimodels.ExecutionWindow; import com.emc.storageos.db.client.model.uimodels.ExecutionWindowType; import com.emc.storageos.db.client.util.ExecutionWindowHelper; import com.emc.vipr.model.catalog.ScheduleInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ScheduleTimeHelper { private static final Logger log = LoggerFactory.getLogger(ScheduleTimeHelper.class); // During schedule event creation, we make sure schedule time match with execution window except // in the case of HOURLY scheduler which would not completely match with any execution window. // In this case, we need to retry during schedule concrete orders. public static final int SCHEDULE_TIME_RETRY_THRESHOLD = 24; /** * Get the first desired scheduled time which consists of start day and start hour/min of that day. * @param scheduleInfo * @return * @throws Exception */ public static Calendar getScheduledStartTime(ScheduleInfo scheduleInfo) throws Exception { DateFormat formatter = new SimpleDateFormat(ScheduleInfo.FULL_DAY_FORMAT); Date date = formatter.parse(scheduleInfo.getStartDate()); Calendar startTime = Calendar.getInstance(TimeZone.getTimeZone("UTC")); startTime.setTime(date); startTime.set(Calendar.HOUR_OF_DAY, scheduleInfo.getHourOfDay()); startTime.set(Calendar.MINUTE, scheduleInfo.getMinuteOfHour()); startTime.set(Calendar.SECOND, 0); log.info("The first desired scheduled time: {}", startTime.toString()); return startTime; } /** * Get the last desired scheduled time which consists of start day, * start hour/min of that day, cycleType, cycleFrequency and reoccurrence. * @param scheduleInfo * @return * @throws Exception */ public static Calendar getScheduledEndTime(ScheduleInfo scheduleInfo) throws Exception { if (scheduleInfo.getReoccurrence() == 0) { return null; } Calendar startTime = getScheduledStartTime(scheduleInfo); Calendar endTime = startTime; if (scheduleInfo.getReoccurrence() == 1) { return endTime; } int timeToIncrease = scheduleInfo.getCycleFrequency() * (scheduleInfo.getReoccurrence() - 1); switch (scheduleInfo.getCycleType()) { case MONTHLY: endTime.add(Calendar.MONTH, timeToIncrease); break; case WEEKLY: endTime.add(Calendar.WEEK_OF_MONTH, timeToIncrease); break; case DAILY: endTime.add(Calendar.DAY_OF_MONTH, timeToIncrease); break; case HOURLY: endTime.add(Calendar.HOUR_OF_DAY, timeToIncrease); break; case MINUTELY: endTime.add(Calendar.MINUTE, timeToIncrease); break; default: log.error("not expected schedule cycle."); } log.info("The last desired scheduled time: {}", endTime.toString()); return endTime; } /** * Get the first desired and AVAILABLE schedule time based on current time, start time and schedule schema * @param scheduleInfo schedule schema * @return calendar for the first desired and AVAILABLE schedule time * @throws Exception */ public static Calendar getFirstScheduledTime(ScheduleInfo scheduleInfo) throws Exception{ Calendar scheduledTime = getScheduledStartTime(scheduleInfo); if (scheduleInfo.getReoccurrence() == 1) { return scheduledTime; } Calendar currTime = Calendar.getInstance(TimeZone.getTimeZone("UTC")); log.debug("currTime: {}", currTime.toString()); if (scheduledTime.after(currTime)) { return scheduledTime; } int day; switch (scheduleInfo.getCycleType()) { case MONTHLY: day = Integer.valueOf(scheduleInfo.getSectionsInCycle().get(0)); scheduledTime.set(Calendar.DAY_OF_MONTH, day); break; case WEEKLY: day = Integer.valueOf(scheduleInfo.getSectionsInCycle().get(0)); int daysDiff = (day%7 + 1) - scheduledTime.get(Calendar.DAY_OF_WEEK); // java dayOfWeek starts from Sun. scheduledTime.add(Calendar.DAY_OF_WEEK, daysDiff); break; case DAILY: case HOURLY: case MINUTELY: break; default: log.error("not expected schedule cycle."); } while (scheduledTime != null && scheduledTime.before(currTime)) { scheduledTime = getNextScheduledTime(scheduledTime, scheduleInfo); } if (scheduledTime != null) { log.debug("scheduledTime: {}", scheduledTime.toString()); } return scheduledTime; } /** * Get next desired schedule time based on the previous one and schedule schema * @param scheduledTime previous schedule time * @param scheduleInfo schedule schema * @return 1) next scheduled time or 2) null if there is no need to schedule again. */ public static Calendar getNextScheduledTime(Calendar scheduledTime, ScheduleInfo scheduleInfo) throws Exception{ do { switch (scheduleInfo.getCycleType()) { case MONTHLY: scheduledTime.add(Calendar.MONTH, scheduleInfo.getCycleFrequency()); break; case WEEKLY: scheduledTime.add(Calendar.WEEK_OF_MONTH, scheduleInfo.getCycleFrequency()); break; case DAILY: scheduledTime.add(Calendar.DAY_OF_MONTH, scheduleInfo.getCycleFrequency()); break; case HOURLY: scheduledTime.add(Calendar.HOUR_OF_DAY, scheduleInfo.getCycleFrequency()); break; case MINUTELY: scheduledTime.add(Calendar.MINUTE, scheduleInfo.getCycleFrequency()); break; default: log.error("not expected schedule cycle."); } } while (isExceptionTime(scheduledTime, scheduleInfo)); Calendar endTime = getScheduledEndTime(scheduleInfo); if (endTime != null && scheduledTime.after(endTime)) { return null; } return scheduledTime; } /** * Check if the schedule time is in exception list * @param scheduleTime */ public static boolean isExceptionTime(Calendar scheduleTime, ScheduleInfo scheduleInfo) throws Exception{ if (scheduleInfo.getDateExceptions() != null) { for (String dateException: scheduleInfo.getDateExceptions()) { DateFormat formatter = new SimpleDateFormat(ScheduleInfo.FULL_DAYTIME_FORMAT); Date date = formatter.parse(scheduleInfo.getStartDate()); Calendar exceptionTime = Calendar.getInstance(TimeZone.getTimeZone("UTC")); exceptionTime.setTime(date); if (exceptionTime.equals(scheduleTime)) { log.info("The scheduled time {} is in exception list", scheduleTime.toString()); return true; } } } return false; } /** * Convert a Calendar to a readable time string. * @param cal * @return * @throws Exception */ public static String convertCalendarToStr(Calendar cal) throws Exception { SimpleDateFormat format = new SimpleDateFormat(ScheduleInfo.FULL_DAYTIME_FORMAT); String formatted = format.format(cal.getTime()); log.debug("converted calendar time:{}", formatted); return formatted; } /** * Convert a readable time string to Calendar * @param formattedTime * @return * @throws Exception */ public static Calendar convertStrToCalendar(String formattedTime) { Calendar cal = Calendar.getInstance(); try { SimpleDateFormat sdf = new SimpleDateFormat(ScheduleInfo.FULL_DAYTIME_FORMAT); cal.setTime(sdf.parse(formattedTime)); } catch (Exception e) { log.info(e.getMessage()); } return cal; } }