Calculate when a cron job will be executed then next time

后端 未结 8 941
庸人自扰
庸人自扰 2020-12-02 08:19

I have a cron \"time definition\"

1 * * * * (every hour at xx:01)
2 5 * * * (every day at 05:02)
0 4 3 * * (every third day of the month at 04:00)
* 2 * * 5          


        
8条回答
  •  再見小時候
    2020-12-02 08:56

    My answer is not unique. Just a replica of @BlaM answer written in java because PHP's date and time is a bit different from Java.

    This program assumes that the CRON expression is simple. It can only contain digits or *.

    Minute = 0-60
    Hour = 0-23
    Day = 1-31
    MONTH = 1-12 where 1 = January.
    WEEKDAY = 1-7 where 1 = Sunday.
    

    Code:

    package main;
    
    import java.util.Calendar;
    import java.util.Date;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class CronPredict
    {
        public static void main(String[] args)
        {
            String cronExpression = "5 3 27 3 3 ls -la > a.txt";
            CronPredict cronPredict = new CronPredict();
            String[] parsed = cronPredict.parseCronExpression(cronExpression);
            System.out.println(cronPredict.getNextExecution(parsed).getTime().toString());
        }
    
        //This method takes a cron string and separates entities like minutes, hours, etc.
        public String[] parseCronExpression(String cronExpression)
        {
            String[] parsedExpression = null;
            String cronPattern = "^([0-9]|[1-5][0-9]|\\*)\\s([0-9]|1[0-9]|2[0-3]|\\*)\\s"
                            + "([1-9]|[1-2][0-9]|3[0-1]|\\*)\\s([1-9]|1[0-2]|\\*)\\s"
                            + "([1-7]|\\*)\\s(.*)$";
            Pattern cronRegex = Pattern.compile(cronPattern);
    
            Matcher matcher = cronRegex.matcher(cronExpression);
            if(matcher.matches())
            {
                String minute = matcher.group(1);
                String hour = matcher.group(2);
                String day = matcher.group(3);
                String month = matcher.group(4);
                String weekday = matcher.group(5);
                String command = matcher.group(6);
    
                parsedExpression = new String[6];
                parsedExpression[0] = minute;
                parsedExpression[1] = hour;
                parsedExpression[2] = day;
                //since java's month start's from 0 as opposed to PHP which starts from 1.
                parsedExpression[3] = month.equals("*") ? month : (Integer.parseInt(month) - 1) + "";
                parsedExpression[4] = weekday;
                parsedExpression[5] = command;
            }
    
            return parsedExpression;
        }
    
        public Calendar getNextExecution(String[] job)
        {
            Calendar cron = Calendar.getInstance();
            cron.add(Calendar.MINUTE, 1);
            cron.set(Calendar.MILLISECOND, 0);
            cron.set(Calendar.SECOND, 0);
    
            int done = 0;
            //Loop because some dates are not valid.
            //e.g. March 29 which is a Friday may never come for atleast next 1000 years.
            //We do not want to keep looping. Also it protects against invalid dates such as feb 30.
            while(done < 100)
            {
                if(!job[0].equals("*") && cron.get(Calendar.MINUTE) != Integer.parseInt(job[0]))
                {
                    if(cron.get(Calendar.MINUTE) > Integer.parseInt(job[0]))
                    {
                        cron.add(Calendar.HOUR_OF_DAY, 1);
                    }
                    cron.set(Calendar.MINUTE, Integer.parseInt(job[0]));
                }
    
                if(!job[1].equals("*") && cron.get(Calendar.HOUR_OF_DAY) != Integer.parseInt(job[1]))
                {
                    if(cron.get(Calendar.HOUR_OF_DAY) > Integer.parseInt(job[1]))
                    {
                        cron.add(Calendar.DAY_OF_MONTH, 1);
                    }
                    cron.set(Calendar.HOUR_OF_DAY, Integer.parseInt(job[1]));
                    cron.set(Calendar.MINUTE, 0);
                }
    
                if(!job[4].equals("*") && cron.get(Calendar.DAY_OF_WEEK) != Integer.parseInt(job[4]))
                {
                    Date previousDate = cron.getTime();
                    cron.set(Calendar.DAY_OF_WEEK, Integer.parseInt(job[4]));
                    Date newDate = cron.getTime();
    
                    if(newDate.before(previousDate))
                    {
                        cron.add(Calendar.WEEK_OF_MONTH, 1);
                    }
    
                    cron.set(Calendar.HOUR_OF_DAY, 0);
                    cron.set(Calendar.MINUTE, 0);
                }
    
                if(!job[2].equals("*") && cron.get(Calendar.DAY_OF_MONTH) != Integer.parseInt(job[2]))
                {
                    if(cron.get(Calendar.DAY_OF_MONTH) > Integer.parseInt(job[2]))
                    {
                        cron.add(Calendar.MONTH, 1);
                    }
                    cron.set(Calendar.DAY_OF_MONTH, Integer.parseInt(job[2]));
                    cron.set(Calendar.HOUR_OF_DAY, 0);
                    cron.set(Calendar.MINUTE, 0);
                }
    
                if(!job[3].equals("*") && cron.get(Calendar.MONTH) != Integer.parseInt(job[3]))
                {
                    if(cron.get(Calendar.MONTH) > Integer.parseInt(job[3]))
                    {
                        cron.add(Calendar.YEAR, 1);
                    }
                    cron.set(Calendar.MONTH, Integer.parseInt(job[3]));
                    cron.set(Calendar.DAY_OF_MONTH, 1);
                    cron.set(Calendar.HOUR_OF_DAY, 0);
                    cron.set(Calendar.MINUTE, 0);
                }
    
                done =  (job[0].equals("*") || cron.get(Calendar.MINUTE) == Integer.parseInt(job[0])) &&
                        (job[1].equals("*") || cron.get(Calendar.HOUR_OF_DAY) == Integer.parseInt(job[1])) &&
                        (job[2].equals("*") || cron.get(Calendar.DAY_OF_MONTH) == Integer.parseInt(job[2])) &&
                        (job[3].equals("*") || cron.get(Calendar.MONTH) == Integer.parseInt(job[3])) &&
                        (job[4].equals("*") || cron.get(Calendar.DAY_OF_WEEK) == Integer.parseInt(job[4])) ? 100 : (done + 1);
            }
    
            return cron;
        }
    }
    

提交回复
热议问题