cron根据cron表达式计算每天有哪些执行时刻

Posted 恒奇恒毅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cron根据cron表达式计算每天有哪些执行时刻相关的知识,希望对你有一定的参考价值。

      参见 http://gitee.com/xxssyyyyssxx/cron-hms

      我们项目中一般会有很多的定时任务,我们怎么知道这些定时任务是否正常执行了呢?一个基本的想法是,在任务执行前保存一条记录,任务执行后更新此记录的结束时间和标记,异常的时候记录失败标记和异常信息,然后管理员每天登录的时候检查每个任务是否正常执行。如果记录与设置的执行时刻点匹配,说明任务正常执行了,记录不存在或者有失败标记说明任务未正常执行。此谓任务监控。

       定时任务一般地由Quartz或者Spring实现,他们都通过一个cron表达式来指定在什么时刻执行。对于Quartz可以用Aspectj来拦截job,前后记录;对于Spring的Scheduled,可以用AOP拦截@Scheduled注解或者自定义一个注解,前后记录。

       现在的关键问题来了,如何根据cron表达式计算每天的哪些时候执行或者该不该执行?

       我们知道,一般地,cron表达式有六个域,分别代表秒、分、时、日、月、星期。每个域可能出现*、/、,、-、数字等。为了模型简单化,解析每个域即可知道每个域的哪些点应该执行,那么一天中,秒、分、时的笛卡尔积即是每天的执行点。任意给定的日期,我们就能知道这个日期应不应该执行(判断星期、月、日),哪些时刻执行(秒、分、时的笛卡尔积)?

       talk is cheap,show me the code。

思路:

1、切割cron表达式
2、转换每个域
3、计算执行时间点(关键算法,解析cron表达式)
4、计算某一天的哪些时间点执行

      首先设计表达每个域的枚举,可以指定位置参数、最小值、最大值。提供根据位置计算枚举域的静态方法。再聚合一个JavaBean表示一个域。

/**
 * cron表达式某个位置上的一些常量
 * @author xiongshiyan at 2018/11/17 , contact me with email yanshixiong@126.com or phone 15208384257
 */
public enum  CronPosition 
    SECOND(0 , 0 , 59) ,
    MINUTE(1 , 0 , 59) ,
    HOUR  (2 , 0 , 23) ,
    DAY   (3 , 1 , 31) ,
    MONTH (4 , 1 , 12) ,
    WEEK  (5 , 0 , 6)  ,
    YEAR  (6 , 2018 , 2099);
    /**
     * 在cron表达式中的位置
     */
    private int position;
    /**
     * 该域最小值
     */
    private Integer min;
    /**
     * 该域最大值
     */
    private Integer max;

    CronPosition(int position , Integer min , Integer max)
        this.position = position;
        this.min = min;
        this.max = max;
    

    public int getPosition() 
        return position;
    

    public Integer getMin() 
        return min;
    

    public Integer getMax() 
        return max;
    

    public static CronPosition fromPosition(int position)
        CronPosition[] values = CronPosition.values();
        for (CronPosition field : values) 
            if(position == field.position)
                return field;
            
        
        return null;
    

      然后就是切割cron表达式、转换每个域、计算执行时间点(关键算法,解析cron表达式)、计算某一天的哪些时间点执行。

   

/**
     * 1.把cron表达式切成域表达式
     *
     * @param cron cron
     * @return 代表每个域的列表
     */
    public static List<String> cut(String cron) 
        cron = cron.trim();
        String[] split = cron.split(CRON_CUT);
        return Arrays.asList(split);
    
/**
     * 2.cron域表达式转换为域
     */
    public static List<CronField> convertCronField(String cron) 
        List<String> cut = cut(cron);
        int size = cut.size();
        if (CRON_LEN != size && (CRON_LEN + 1) != size) 
            throw new IllegalArgumentException("cron表达式必须有六个域或者七个域(最后为年)");
        
        List<CronField> cronFields = new ArrayList<>(size);
        for (int i = 0; i < size; i++) 
            CronPosition cronPosition = CronPosition.fromPosition(i);
            cronFields.add(new CronField(
                    cronPosition,
                    CronShapingUtil.shaping(cut.get(i), cronPosition)
            ));
        
        return cronFields;
    

CronField是表达一个域的,保存域相关信息,并提供计算执行点的方法。

package top.jfunc.cron.pojo;

import top.jfunc.cron.util.CompareUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * cron表达式的域
 * @author xiongshiyan
 */
public class CronField 
    public static final String STAR = "*";
    public static final String COMMA = ",";
    public static final String HYPHEN = "-";
    public static final String SLASH = "/";

    private CronPosition cronPosition;
    private String express;
    private List<Integer> listCache = null;

    public CronField(CronPosition cronPosition, String express) 
        this.cronPosition = cronPosition;
        this.express = express;
    

    public CronPosition getCronPosition() 
        return cronPosition;
    

    public void setCronPosition(CronPosition cronPosition) 
        this.cronPosition = cronPosition;
    

    public String getExpress() 
        return express;
    

    public void setExpress(String express) 
        this.express = express;
    

    /**
     * 是否包含全部的数值
     */
    public boolean containsAll()
        return STAR.equals(getExpress());
    

    /**
     * 3.计算某域的哪些点
     */
    public List<Integer> points() 
        //缓存计算的
        if(null != listCache)
            return listCache;
        

        listCache = new ArrayList<>(5);

        String express = this.getExpress();
        CronPosition cronPosition = this.getCronPosition();
        Integer min = cronPosition.getMin();
        Integer max = cronPosition.getMax();

        // *这种情况
        if (STAR.equals(express)) 
            for (int i = min; i <= max; i++) 
                listCache.add(i);
            
            return listCache;
        
        // 带有,的情况,分割之后每部分单独处理
        if (express.contains(COMMA)) 
            String[] split = express.split(COMMA);
            for (String part : split) 
                listCache.addAll( new CronField(this.getCronPosition(), part).points());
            
            if (listCache.size() > 1) 
                //去重
                CompareUtil.removeDuplicate(listCache);
                //排序
                Collections.sort(listCache);
            

            return listCache;
        
        // 0-3 0/2 3-15/2 5  模式统一为 (min-max)/step
        Integer left;
        Integer right;
        Integer step = 1;

        //包含-的情况
        if (express.contains(HYPHEN)) 
            String[] strings = express.split(HYPHEN);
            left = Integer.valueOf(strings[0]);
            CompareUtil.assertRange(cronPosition, left);
            //1-32/2的情况
            if (strings[1].contains(SLASH)) 
                String[] split = strings[1].split(SLASH);
                //32
                right = Integer.valueOf(split[0]);
                CompareUtil.assertSize(left, right);
                CompareUtil.assertRange(cronPosition, right);
                //2
                step = Integer.valueOf(split[1]);
             else 
                //1-32的情况
                right = Integer.valueOf(strings[1]);
                CompareUtil.assertSize(left, right);
                CompareUtil.assertRange(cronPosition, right);
            
            //仅仅包含/
         else if (express.contains(SLASH)) 
            String[] strings = express.split(SLASH);
            left = Integer.valueOf(strings[0]);
            CompareUtil.assertRange(cronPosition, left);
            step = Integer.valueOf(strings[1]);
            right = max;
            CompareUtil.assertSize(left, right);
         else 
            // 普通的数字
            Integer single = Integer.valueOf(express);
            //星期域上 7 转换为 0
            if(CronPosition.WEEK == this.cronPosition && 7 == single)
                single = 0;
            
            CompareUtil.assertRange(cronPosition, single);
            listCache.add(single);
            return listCache;
        

        for (int i = left; i <= right; i += step) 
            listCache.add(i);
        
        return listCache;

    

    @Override
    public String toString() 
        return "CronField" +
                "cronPosition=" + cronPosition +
                ", express='" + express + '\\'' +
                '';
    

然后计算某一天的哪些时刻点执行。

/**
     * 4.计算cron表达式在某一天的那些时间执行,精确到秒
     * 秒 分 时 日 月 周 (年)
     * "0 15 10 ? * *"  每天上午10:15触发
     * "0 0/5 14 * * ?"  在每天下午2点到下午2:55期间的每5分钟触发
     * "0 0-5 14 * * ?"  每天下午2点到下午2:05期间的每1分钟触发
     * "0 10,44 14 ? 3 WED"  三月的星期三的下午2:10和2:44触发
     * "0 15 10 ? * MON-FRI"  周一至周五的上午10:15触发
     * ---------------------
     *
     * @param cron cron表达式
     * @param date 时间,某天
     * @return 这一天的哪些时分秒执行, 不执行的返回空
     */
    public static List<TimeOfDay> calculate(String cron, Date date) 
        List<CronField> cronFields = convertCronField(cron);
        int year = DateUtil.year(date);
        int week = DateUtil.week(date);
        int month = DateUtil.month(date);
        int day = DateUtil.day(date);
        /// 如果包含年域
        if (CRON_LEN_YEAR == cronFields.size()) 
            CronField fieldYear = cronFields.get(CronPosition.YEAR.getPosition());
            if (!assertExecute(year, fieldYear, fieldYear.points())) 
                return Collections.emptyList();
            
        

        CronField fieldWeek = cronFields.get(CronPosition.WEEK.getPosition());
        List<Integer> listWeek = fieldWeek.points();
        CronField fieldMonth = cronFields.get(CronPosition.MONTH.getPosition());
        List<Integer> listMonth = fieldMonth.points();
        CronField fieldDay = cronFields.get(CronPosition.DAY.getPosition());
        List<Integer> listDay = fieldDay.points();
        ///今天不执行就直接返回空
        if (!assertExecute(week, fieldWeek, listWeek)
                || !assertExecute(month, fieldMonth, listMonth)
                || !assertExecute(day, fieldDay, listDay)) 
            return Collections.emptyList();
        

        CronField fieldHour = cronFields.get(CronPosition.HOUR.getPosition());
        List<Integer> listHour = fieldHour.points();
        CronField fieldMinute = cronFields.get(CronPosition.MINUTE.getPosition());
        List<Integer> listMinute = fieldMinute.points();
        CronField fieldSecond = cronFields.get(CronPosition.SECOND.getPosition());
        List<Integer> listSecond = fieldSecond.points();

        List<TimeOfDay> points = new ArrayList<>(listHour.size() * listMinute.size() * listSecond.size());
        for (Integer hour : listHour) 
            for (Integer minute : listMinute) 
                for (Integer second : listSecond) 
                    points.add(new TimeOfDay(hour, minute, second));
                
            
        
        return points;
    

    private static boolean assertExecute(int num, CronField cronField, List<Integer> list) 
        return CronField.STAR.equals(cronField.getExpress()) || CompareUtil.inList(num, list);
    

一些辅助工具类。替换?JAN-DEC、SUN-SAT等字符串的整形工具类。

package top.jfunc.cron.util;

import top.jfunc.cron.pojo.CronPosition;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author xiongshiyan at 2018/10/12 , contact me with email yanshixiong@126.com or phone 15208384257
 */
public class CronShapingUtil 
    private static final Map<String , String> MONTH_MAP = new HashMap<>(12);
    private static final Map<String , String> WEEK_MAP  = new HashMap<>(7);
    static 
        MONTH_MAP.put("JAN" , "1");
        MONTH_MAP.put("FEB" , "2");
        MONTH_MAP.put("MAR" , "3");
        MONTH_MAP.put("APR" , "4");
        MONTH_MAP.put("May" , "5");
        MONTH_MAP.put("JUN" , "6");
        MONTH_MAP.put("JUL" , "7");
        MONTH_MAP.put("AUG" , "8");
        MONTH_MAP.put("SEP" , "9");
        MONTH_MAP.put("OCT" , "10");
        MONTH_MAP.put("NOV" , "11");
        MONTH_MAP.put("DEC" , "12");

        WEEK_MAP.put("SUN" , "0");
        WEEK_MAP.put("MON" , "1");
        WEEK_MAP.put("TUE" , "2");
        WEEK_MAP.put("WED" , "3");
        WEEK_MAP.put("THU" , "4");
        WEEK_MAP.put("FRI" , "5");
        WEEK_MAP.put("SAT" , "6");
    

    /**
     * 域整形,把某些英文字符串像JAN/SUN等转换为相应的数字
     */
    public static String shaping(String express , CronPosition cronPosition)
        if(cronPosition == CronPosition.MONTH)
            express = shapingMonth(express);
        

        if(cronPosition == CronPosition.WEEK)
            express = shapingWeek(express);
            express = express.replace("?" , "*");
        

        if(cronPosition == CronPosition.DAY)
            express = express.replace("?" , "*");
        
        return express;
    

    private static String shapingMonth(String express)
        Set<Map.Entry<String, String>> entrySet = MONTH_MAP.entrySet();
        for (Map.Entry<String, String> entry : entrySet) 
            if(express.toUpperCase().contains(entry.getKey()))
                express = express.toUpperCase().replace(entry.getKey() , entry.getValue());
            
        
        return express;
    

    private static String shapingWeek(String express)
        Set<Map.Entry<String, String>> entrySet = WEEK_MAP.entrySet();
        for (Map.Entry<String, String> entry : entrySet) 
            if(express.toUpperCase().contains(entry.getKey()))
                express = express.toUpperCase().replace(entry.getKey() , entry.getValue());
            
        
        return express;
    

时间计算等工具类。

package top.jfunc.cron.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * @author xiongshiyan at 2018/11/18 , contact me with email yanshixiong@126.com or phone 15208384257
 */
public class DateUtil 
    public static final String SDF_DATETIME       = "yyyy-MM-dd HH:mm:ss";
    public static final String SDF_DATETIME_SHORT = "yyyyMMddHHmmss";
    public static final String SDF_DATETIME_MS    = "yyyyMMddHHmmssSSS";
    public static final String SDF_DATE           = "yyyy-MM-dd";

    /**
     * 字符串转日期
     * @param dateStr 日期字符串
     * @return 日期 yyyy-MM-dd HH:mm:ss
     */
    public static Date toDate(String dateStr) 
        return toDate(dateStr, null);
    

    /**
     * 日期转字符串
     * @param date 日期
     * @return 字符串 yyyy-MM-dd HH:mm:ss
     */
    public static String toStr(Date date) 
        return toStr(date, SDF_DATETIME);
    

    /**
     * 日期转字符串
     * @param date 日期
     * @param format 格式化字符串
     * @return 字符串
     */
    public static String toStr(Date date, String format) 
        SimpleDateFormat sdf = null;
        if (null != format && !"".equals(format)) 
            sdf = new SimpleDateFormat(format);
            return sdf.format(date);
         else 
            sdf = new SimpleDateFormat(SDF_DATETIME);
            return sdf.format(date);
        
    

    /**
     * 字符串转日期
     * @param dateStr 日期字符串
     * @param pattern 格式化字符串
     * @return 日期
     */
    public static Date toDate(String dateStr, String pattern) 
        try 
            if (null != pattern && !"".equals(pattern)) 
                return new SimpleDateFormat(pattern).parse(dateStr);
             else 
                return new SimpleDateFormat(SDF_DATETIME).parse(dateStr);
            
         catch (ParseException e) 
            throw new RuntimeException(e);
        
    
    /**
     * 计算某一天是一个月的哪一天
     * @param date 日期
     * @return 1-31
     */
    public static int day(Date date)
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.DAY_OF_MONTH);
    
    /**
     * 计算某一天是星期几
     * @param date 日期
     * @return 星期几,星期1是1,星期天是0  0-6
     */
    public static int week(Date date)
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.DAY_OF_WEEK) - 1;
    
    /**
     * 计算某一天的月份
     * @param date 日期
     * @return 月份,1开始
     */
    public static int month(Date date)
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.MONTH) + 1;
    
    /**
     * 计算某一天的年
     * @param date 日期
     * @return 年
     */
    public static int year(Date date)
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.YEAR);
    
    /**
     * 计算某一天的时
     * @param date 日期
     * @return 时 0-23
     */
    public static int hour(Date date)
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.HOUR_OF_DAY);
    
    /**
     * 计算某一天的分
     * @param date 日期
     * @return 秒 0-59
     */
    public static int minute(Date date)
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.MINUTE);
    
    /**
     * 计算某一天的秒
     * @param date 日期
     * @return 秒 0-59
     */
    public static int second(Date date)
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.SECOND);
    

除开解析L、W、C等,至此完成。

https://blog.csdn.net/weixin_40426638/article/details/78959972

https://blog.csdn.net/dabing69221/article/details/19012581

https://blog.csdn.net/ukulelepku/article/details/54310035

项目地址见:

https://gitee.com/xxssyyyyssxx/cron-hms

 

单元测试:

package top.jfunc.cron;

import org.junit.Assert;
import org.junit.Test;
import top.jfunc.cron.pojo.CronField;
import top.jfunc.cron.pojo.TimeOfDay;
import top.jfunc.cron.util.CronUtil;
import top.jfunc.cron.util.DateUtil;

import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * @author xiongshiyan at 2018/11/17 , contact me with email yanshixiong@126.com or phone 15208384257
 */
public class CronTest 
    @Test
    public void testCalculate() 
        Date date = DateUtil.toDate("2018-11-17 12:00:12");
        Assert.assertEquals(2018, DateUtil.year(date));
        Assert.assertEquals(11, DateUtil.month(date));
        Assert.assertEquals(6, DateUtil.week(date));
        Assert.assertEquals(17, DateUtil.day(date));
        Assert.assertEquals(12, DateUtil.hour(date));
        Assert.assertEquals(0, DateUtil.minute(date));
        Assert.assertEquals(12, DateUtil.second(date));

        date = DateUtil.toDate("2018-11-18 12:00:12");
        Assert.assertEquals(0, DateUtil.week(date));
    

    @Test
    public void testCut() 
        String cron = "0     15    10   ? *    *   ";
        Assert.assertEquals(
                Arrays.asList("0", "15", "10", "?", "*", "*"),
                CronUtil.cut(cron));
    

    @Test
    public void testConvertField() 
        List<CronField> cronFields = CronUtil.convertCronField("0 0-5 14/2 * * ?");
        for (int i = 0; i < 6; i++) 
            CronField field = cronFields.get(i);
            Assert.assertEquals(field.getCronPosition().getPosition(), i);
        
        Assert.assertEquals("0" , cronFields.get(0).getExpress());
        Assert.assertEquals("0-5" , cronFields.get(1).getExpress());
        Assert.assertEquals("14/2" , cronFields.get(2).getExpress());
        Assert.assertEquals("*" , cronFields.get(3).getExpress());
        Assert.assertEquals("*" , cronFields.get(4).getExpress());
        Assert.assertEquals("*" , cronFields.get(5).getExpress());
        List<CronField> fields = CronUtil.convertCronField("0 15 10 ? JAN-NOV MON-FRI");
        for (int i = 0; i < 6; i++) 
            CronField field = fields.get(i);
            Assert.assertEquals(field.getCronPosition().getPosition(), i);
        
        Assert.assertEquals("0" , fields.get(0).getExpress());
        Assert.assertEquals("15" , fields.get(1).getExpress());
        Assert.assertEquals("10" , fields.get(2).getExpress());
        Assert.assertEquals("*" , fields.get(3).getExpress());
        Assert.assertEquals("1-11" , fields.get(4).getExpress());
        Assert.assertEquals("1-5" , fields.get(5).getExpress());


        //包含年域的情况
        cronFields = CronUtil.convertCronField("0 15 10 ? JAN-NOV MON-FRi 2018");
        System.out.println(cronFields);
    
    @Test
    public void testConvertCronField()
        List<CronField> cronFields = CronUtil.convertCronField("1 0-5 1/3 1,3,4 1-11/2 ?");
        Assert.assertEquals(Collections.singletonList(1) , cronFields.get(0).points());
        Assert.assertEquals(Arrays.asList(0,1,2,3,4,5) , cronFields.get(1).points());
        Assert.assertEquals(Arrays.asList(1,4,7,10,13,16,19,22) , cronFields.get(2).points());
        Assert.assertEquals(Arrays.asList(1,3,4) , cronFields.get(3).points());
        Assert.assertEquals(Arrays.asList(1,3,5,7,9,11) , cronFields.get(4).points());
        Assert.assertEquals(Arrays.asList(0,1,2,3,4,5,6) , cronFields.get(5).points());
    

    @Test
    public void testCal()
        Date date = DateUtil.toDate("2018-11-18 12:00:12");
        List<TimeOfDay> calculate = CronUtil.calculate("0 15 10 ? * *", date);
        Assert.assertEquals(Collections.singletonList(new TimeOfDay(10 , 15 , 0)) , calculate);

        calculate = CronUtil.calculate("0-5 15 10 ? * *", date);
        Assert.assertEquals(Arrays.asList(
                new TimeOfDay(10 , 15 , 0),
                new TimeOfDay(10 , 15 , 1),
                new TimeOfDay(10 , 15 , 2),
                new TimeOfDay(10 , 15 , 3),
                new TimeOfDay(10 , 15 , 4),
                new TimeOfDay(10 , 15 , 5)) , calculate);

        calculate = CronUtil.calculate("0 1/10 10 ? * *", date);
        Assert.assertEquals(Arrays.asList(
                new TimeOfDay(10 , 1 , 0),
                new TimeOfDay(10 , 11 , 0),
                new TimeOfDay(10 , 21 , 0),
                new TimeOfDay(10 , 31 , 0),
                new TimeOfDay(10 , 41 , 0),
                new TimeOfDay(10 , 51 , 0)) , calculate);

        calculate = CronUtil.calculate("0 1,4,6,8,10,50 10 ? * *", date);
        Assert.assertEquals(Arrays.asList(
                new TimeOfDay(10 , 1 , 0),
                new TimeOfDay(10 , 4 , 0),
                new TimeOfDay(10 , 6 , 0),
                new TimeOfDay(10 , 8 , 0),
                new TimeOfDay(10 , 10 , 0),
                new TimeOfDay(10 , 50 , 0)) , calculate);

        calculate = CronUtil.calculate("0 1-30/5 10 ? * *", date);
        Assert.assertEquals(Arrays.asList(
                new TimeOfDay(10 , 1 , 0),
                new TimeOfDay(10 , 6 , 0),
                new TimeOfDay(10 , 11 , 0),
                new TimeOfDay(10 , 16 , 0),
                new TimeOfDay(10 , 21 , 0),
                new TimeOfDay(10 , 26 , 0)) , calculate);

        calculate = CronUtil.calculate("0 1-30/5 10 ? * SUN", date);
        Assert.assertEquals(Arrays.asList(
                new TimeOfDay(10 , 1 , 0),
                new TimeOfDay(10 , 6 , 0),
                new TimeOfDay(10 , 11 , 0),
                new TimeOfDay(10 , 16 , 0),
                new TimeOfDay(10 , 21 , 0),
                new TimeOfDay(10 , 26 , 0)) , calculate);

        calculate = CronUtil.calculate("0 1-30/5 10 ? 11 *", date);
        Assert.assertEquals(Arrays.asList(
                new TimeOfDay(10 , 1 , 0),
                new TimeOfDay(10 , 6 , 0),
                new TimeOfDay(10 , 11 , 0),
                new TimeOfDay(10 , 16 , 0),
                new TimeOfDay(10 , 21 , 0),
                new TimeOfDay(10 , 26 , 0)) , calculate);

        calculate = CronUtil.calculate("0 1-4,43 10 ? 11 *", date);
        Assert.assertEquals(Arrays.asList(
                new TimeOfDay(10 , 1 , 0),
                new TimeOfDay(10 , 2 , 0),
                new TimeOfDay(10 , 3 , 0),
                new TimeOfDay(10 , 4 , 0),
                new TimeOfDay(10 , 43 , 0)) , calculate);

        calculate = CronUtil.calculate("0 1-10/2,43 10 ? 11 *", date);
        Assert.assertEquals(Arrays.asList(
                new TimeOfDay(10 , 1 , 0),
                new TimeOfDay(10 , 3 , 0),
                new TimeOfDay(10 , 5 , 0),
                new TimeOfDay(10 , 7 , 0),
                new TimeOfDay(10 , 9 , 0),
                new TimeOfDay(10 , 43 , 0)) , calculate);

        calculate = CronUtil.calculate("0 7,1-5/2,5,6 10 ? 11 *", date);
        Assert.assertEquals(Arrays.asList(
                new TimeOfDay(10 , 1 , 0),
                new TimeOfDay(10 , 3 , 0),
                new TimeOfDay(10 , 5 , 0),
                new TimeOfDay(10 , 6 , 0),
                new TimeOfDay(10 , 7 , 0)) , calculate);

        calculate = CronUtil.calculate("0 1-6/2,12-27/5 10 ? 11 *", date);
        Assert.assertEquals(Arrays.asList(
                new TimeOfDay(10 , 1 , 0),
                new TimeOfDay(10 , 3 , 0),
                new TimeOfDay(10 , 5 , 0),
                new TimeOfDay(10 , 12 , 0),
                new TimeOfDay(10 , 17 , 0),
                new TimeOfDay(10 , 22 , 0),
                new TimeOfDay(10 , 27 , 0)) , calculate);

        ///星期一到星期六执行,星期天不执行就返回空集合
        calculate = CronUtil.calculate("0 1-30/5 10 ? * MON-SAT", date);
        Assert.assertEquals(Collections.emptyList(), calculate);
    
    @Test(expected = IllegalArgumentException.class)
    public void testException1()
        Date date = DateUtil.toDate("2018-11-18 12:00:12");
        CronUtil.calculate("5-0 15 10 ? * *", date);
    
    @Test(expected = IllegalArgumentException.class)
    public void testException2()
        Date date = DateUtil.toDate("2018-11-18 12:00:12");
        CronUtil.calculate("1-62 15 10 ? * *", date);
    
    @Test(expected = IllegalArgumentException.class)
    public void testException3()
        Date date = DateUtil.toDate("2018-11-18 12:00:12");
        CronUtil.calculate("1 2-78 10 ? * *", date);
    
    @Test(expected = IllegalArgumentException.class)
    public void testException4()
        Date date = DateUtil.toDate("2018-11-18 12:00:12");
        CronUtil.calculate("2 15 25 ? * *", date);
    
    @Test(expected = IllegalArgumentException.class)
    public void testException5()
        Date date = DateUtil.toDate("2018-11-18 12:00:12");
        CronUtil.calculate("2 15 23 2-32 * *", date);
    
    @Test(expected = IllegalArgumentException.class)
    public void testException6()
        Date date = DateUtil.toDate("2018-11-18 12:00:12");
        CronUtil.calculate("2 15 23 3 1-13/2 *", date);
    

 

以上是关于cron根据cron表达式计算每天有哪些执行时刻的主要内容,如果未能解决你的问题,请参考以下文章

如何根据cron表达式获取下个执行时间

cron表达式0 * * * * ?啥意思

Cron表达式范例:每隔5秒执行一次:*/5 * * * * ?

Cron表达式

Cron表达式

Cron表达式范例