All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.hutool.cron.pattern.CronPattern Maven / Gradle / Ivy

There is a newer version: 5.8.33
Show newest version
package cn.hutool.cron.pattern;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.CalendarUtil;
import cn.hutool.cron.pattern.matcher.PatternMatcher;
import cn.hutool.cron.pattern.parser.PatternParser;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.TimeZone;

/**
 * 定时任务表达式
* 表达式类似于Linux的crontab表达式,表达式使用空格分成5个部分,按顺序依次为: *
    *
  1. :范围:0~59
  2. *
  3. :范围:0~23
  4. *
  5. :范围:1~31,"L" 表示月的最后一天
  6. *
  7. :范围:1~12,同时支持不区分大小写的别名:"jan","feb", "mar", "apr", "may","jun", "jul", "aug", "sep","oct", "nov", "dec"
  8. *
  9. :范围:0 (Sunday)~6(Saturday),7也可以表示周日,同时支持不区分大小写的别名:"sun","mon", "tue", "wed", "thu","fri", "sat","L" 表示周六
  10. *
*

* 为了兼容Quartz表达式,同时支持6位和7位表达式,其中:
* *

 * 当为6位时,第一位表示 ,范围0~59,但是第一位不做匹配
 * 当为7位时,最后一位表示 ,范围1970~2099,但是第7位不做解析,也不做匹配
 * 
*

* 当定时任务运行到的时间匹配这些表达式后,任务被启动。
* 注意: * *

 * 当isMatchSecond为{@code true}时才会匹配秒部分
 * 默认都是关闭的
 * 
*

* 对于每一个子表达式,同样支持以下形式: *

    *
  • * :表示匹配这个位置所有的时间
  • *
  • ? :表示匹配这个位置任意的时间(与"*"作用一致)
  • *
  • */2 :表示间隔时间,例如在分上,表示每两分钟,同样*可以使用数字列表代替,逗号分隔
  • *
  • 2-8 :表示连续区间,例如在分上,表示2,3,4,5,6,7,8分
  • *
  • 2,3,5,8 :表示列表
  • *
  • cronA | cronB :表示多个定时表达式
  • *
* 注意:在每一个子表达式中优先级: * *
 * 间隔(/) > 区间(-) > 列表(,)
 * 
*

* 例如 2,3,6/3中,由于“/”优先级高,因此相当于2,3,(6/3),结果与 2,3,6等价
*
*

* 一些例子: *

    *
  • 5 * * * * :每个点钟的5分执行,00:05,01:05……
  • *
  • * * * * * :每分钟执行
  • *
  • */2 * * * * :每两分钟执行
  • *
  • * 12 * * * :12点的每分钟执行
  • *
  • 59 11 * * 1,2 :每周一和周二的11:59执行
  • *
  • 3-18/5 * * * * :3~18分,每5分钟执行一次,即0:03, 0:08, 0:13, 0:18, 1:03, 1:08……
  • *
* * @author Looly */ public class CronPattern { private final String pattern; private final List matchers; /** * 解析表达式为 CronPattern * * @param pattern 表达式 * @return CronPattern * @since 5.8.0 */ public static CronPattern of(String pattern) { return new CronPattern(pattern); } /** * 构造 * * @param pattern 表达式 */ public CronPattern(String pattern) { this.pattern = pattern; this.matchers = PatternParser.parse(pattern); } /** * 给定时间是否匹配定时任务表达式 * * @param millis 时间毫秒数 * @param isMatchSecond 是否匹配秒 * @return 如果匹配返回 {@code true}, 否则返回 {@code false} */ public boolean match(long millis, boolean isMatchSecond) { return match(TimeZone.getDefault(), millis, isMatchSecond); } /** * 给定时间是否匹配定时任务表达式 * * @param timezone 时区 {@link TimeZone} * @param millis 时间毫秒数 * @param isMatchSecond 是否匹配秒 * @return 如果匹配返回 {@code true}, 否则返回 {@code false} */ public boolean match(TimeZone timezone, long millis, boolean isMatchSecond) { final GregorianCalendar calendar = new GregorianCalendar(timezone); calendar.setTimeInMillis(millis); return match(calendar, isMatchSecond); } /** * 给定时间是否匹配定时任务表达式 * * @param calendar 时间 * @param isMatchSecond 是否匹配秒 * @return 如果匹配返回 {@code true}, 否则返回 {@code false} */ public boolean match(Calendar calendar, boolean isMatchSecond) { return match(PatternUtil.getFields(calendar, isMatchSecond)); } /** * 给定时间是否匹配定时任务表达式 * * @param dateTime 时间 * @param isMatchSecond 是否匹配秒 * @return 如果匹配返回 {@code true}, 否则返回 {@code false} * @since 5.8.0 */ public boolean match(LocalDateTime dateTime, boolean isMatchSecond) { return match(PatternUtil.getFields(dateTime, isMatchSecond)); } /** * 返回匹配到的下一个时间 * * @param calendar 时间 * @return 匹配到的下一个时间 */ public Calendar nextMatchAfter(Calendar calendar) { // issue#I9FQUA,当提供的时间已经匹配表达式时,增加1秒以匹配下一个时间 if(match(calendar, true)){ final Calendar newCalendar = Calendar.getInstance(calendar.getTimeZone()); newCalendar.setTimeInMillis(calendar.getTimeInMillis() + 1000); calendar = newCalendar; } return nextMatch(calendar); } /** * 返回匹配到的下一个时间,如果给定时间匹配,直接返回 * * @param calendar 时间 * @return 匹配到的下一个时间 * @since 5.8.30 */ public Calendar nextMatch(final Calendar calendar) { Calendar next = nextMatchAfter(PatternUtil.getFields(calendar, true), calendar.getTimeZone()); if (match(next, true)) { return next; } next.set(Calendar.DAY_OF_MONTH, next.get(Calendar.DAY_OF_MONTH) + 1); next = CalendarUtil.beginOfDay(next); return nextMatch(next); } @Override public String toString() { return this.pattern; } /** * 给定时间是否匹配定时任务表达式 * * @param fields 时间字段值,{second, minute, hour, dayOfMonth, month, dayOfWeek, year} * @return 如果匹配返回 {@code true}, 否则返回 {@code false} */ private boolean match(int[] fields) { for (PatternMatcher matcher : matchers) { if (matcher.match(fields)) { return true; } } return false; } /** * 获取下一个最近的匹配日期时间 * * @param values 时间字段值,{second, minute, hour, dayOfMonth, month, dayOfWeek, year} * @param zone 时区 * @return {@link Calendar},毫秒数为0 */ private Calendar nextMatchAfter(int[] values, TimeZone zone) { final List nextMatches = new ArrayList<>(matchers.size()); for (PatternMatcher matcher : matchers) { nextMatches.add(matcher.nextMatchAfter(values, zone)); } // 返回匹配到的最早日期 return CollUtil.min(nextMatches); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy