This commit is contained in:
Looly
2022-03-27 18:47:41 +08:00
parent fbc4662271
commit c2e1bbafc8
9 changed files with 114 additions and 67 deletions

View File

@@ -45,7 +45,7 @@ public class CronConfig {
/**
* 是否支持秒匹配
*
* @return <code>true</code>使用,<code>false</code>不使用
* @return {@code true}使用,{@code false}不使用
*/
public boolean isMatchSecond() {
return this.matchSecond;
@@ -54,7 +54,7 @@ public class CronConfig {
/**
* 设置是否支持秒匹配,默认不使用
*
* @param isMatchSecond <code>true</code>支持,<code>false</code>不支持
* @param isMatchSecond {@code true}支持,{@code false}不支持
* @return this
*/
public CronConfig setMatchSecond(boolean isMatchSecond) {

View File

@@ -6,8 +6,13 @@ import cn.hutool.core.lang.Assert;
import cn.hutool.cron.CronException;
/**
* 表达式各个部分的枚举,用于限定位置和规则<br>
* {@link #ordinal()}表示此部分在表达式中的位置如0表示秒
* 表达式各个部分的枚举,用于限定在表达式中的位置和规则(如最小值和最大值)<br>
* {@link #ordinal()}表示此部分在表达式中的位置如0表示秒<br>
* 表达式各个部分的枚举位置为:
* <pre>
* 0 1 2 3 4 5 6
* [SECOND] MINUTE HOUR DAY_OF_MONTH MONTH DAY_OF_WEEK [YEAR]
* </pre>
*
* @author looly
* @since 5.8.0

View File

@@ -1,19 +1,20 @@
package cn.hutool.cron.pattern.matcher;
import java.util.List;
import java.util.Collection;
import java.util.LinkedHashSet;
/**
* 年匹配<br>
* 考虑年数字太大不适合boolean数组单独使用列表遍历匹配
* @author Looly
* 考虑年数字太大不适合boolean数组单独使用{@link LinkedHashSet}匹配
*
* @author Looly
*/
public class YearValueMatcher implements ValueMatcher{
public class YearValueMatcher implements ValueMatcher {
private final List<Integer> valueList;
private final LinkedHashSet<Integer> valueList;
public YearValueMatcher(List<Integer> intValueList) {
this.valueList = intValueList;
public YearValueMatcher(Collection<Integer> intValueList) {
this.valueList = new LinkedHashSet<>(intValueList);
}
@Override
@@ -24,7 +25,7 @@ public class YearValueMatcher implements ValueMatcher{
@Override
public int nextAfter(int value) {
for (Integer year : valueList) {
if(year >= value){
if (year >= value) {
return year;
}
}

View File

@@ -3,7 +3,6 @@ package cn.hutool.cron.pattern.parser;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.Month;
import cn.hutool.core.date.Week;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.CronException;
@@ -18,7 +17,18 @@ import java.util.ArrayList;
import java.util.List;
/**
* 定时任务表达式各个部分的解析器
* 定时任务表达式各个部分的解析器,根据{@link Part}指定不同部分,解析为{@link ValueMatcher}<br>
* 每个部分支持:
* <ul>
* <li><strong>*</strong> :表示匹配这个位置所有的时间</li>
* <li><strong>?</strong> :表示匹配这个位置任意的时间(与"*"作用一致)</li>
* <li><strong>L</strong> :表示匹配这个位置允许的最大值</li>
* <li><strong>*&#47;2</strong> :表示间隔时间,例如在分上,表示每两分钟,同样*可以使用数字列表代替,逗号分隔</li>
* <li><strong>2-8</strong> 表示连续区间例如在分上表示2,3,4,5,6,7,8分</li>
* <li><strong>2,3,5,8</strong> :表示列表</li>
* <li><strong>wed</strong> :表示周别名</li>
* <li><strong>jan</strong> :表示月别名</li>
* </ul>
*
* @author looly
* @since 5.8.0
@@ -46,7 +56,13 @@ public class PartParser {
}
/**
* 将表达式解析为{@link ValueMatcher}
* 将表达式解析为{@link ValueMatcher}<br>
* <ul>
* <li>* 或者 ? 返回{@link AlwaysTrueValueMatcher}</li>
* <li>{@link Part#DAY_OF_MONTH} 返回{@link DayOfMonthValueMatcher}</li>
* <li>{@link Part#YEAR} 返回{@link YearValueMatcher}</li>
* <li>其他 返回{@link BoolArrayValueMatcher}</li>
* </ul>
*
* @param value 表达式
* @return {@link ValueMatcher}
@@ -220,11 +236,6 @@ public class PartParser {
* @throws CronException 当无效数字或无效别名时抛出
*/
private int parseNumber(String value) throws CronException {
if ("L".equalsIgnoreCase(value)) {
// L表示最大值
return part.getMax();
}
int i;
try {
i = Integer.parseInt(value);
@@ -233,7 +244,7 @@ public class PartParser {
}
// 周日可以用0或7表示统一转换为0
if(this.part == Part.DAY_OF_WEEK && Week.SUNDAY.getIso8601Value() == i){
if(Part.DAY_OF_WEEK.equals(this.part) && Week.SUNDAY.getIso8601Value() == i){
i = Week.SUNDAY.ordinal();
}
@@ -241,24 +252,29 @@ public class PartParser {
}
/**
* 解析别名,只支持{@link Part#MONTH}和{@link Part#DAY_OF_WEEK}
* 解析别名支持包括:<br>
* <ul>
* <li><strong>L 表示最大值</strong></li>
* <li>{@link Part#MONTH}和{@link Part#DAY_OF_WEEK}别名</li>
* </ul>
*
* @param name 别名
* @return 解析int值
* @throws CronException 无匹配别名时抛出异常
*/
private int parseAlias(String name) throws CronException {
if ("L".equalsIgnoreCase(name)) {
// L表示最大值
return part.getMax();
}
switch (this.part) {
case MONTH:
final Month month = Month.of(name);
Assert.notNull(month, () -> new CronException("Invalid month alias: {}", name));
// 月份从1开始
return month.getValueBaseOne();
return Month.of(name).getValueBaseOne();
case DAY_OF_WEEK:
final Week week = Week.of(name);
Assert.notNull(week, () -> new CronException("Invalid day of week alias: {}", name));
// 周从0开始0表示周日
return week.ordinal();
return Week.of(name).ordinal();
}
throw new CronException("Invalid alias value: [{}]", name);

View File

@@ -1,7 +1,6 @@
package cn.hutool.cron.pattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.cron.CronException;
import org.junit.Assert;
import org.junit.Test;
@@ -17,22 +16,21 @@ public class CronPatternTest {
public void matchAllTest() {
CronPattern pattern;
// 任何时间匹配
pattern = new CronPattern("* * * * * *");
ThreadUtil.sleep(600);
Assert.assertTrue(pattern.match(DateUtil.current(), true));
Assert.assertTrue(pattern.match(DateUtil.current(), false));
pattern = CronPattern.of("* * * * * *");
assertMatch(pattern, DateUtil.now());
}
@Test
public void matchAllTest2() {
// 在5位表达式中秒部分并不是任意匹配而是一个固定值
// 在5位表达式中秒部分并不是任意匹配而是一个固定值0
// 因此此处匹配就不能匹配秒
CronPattern pattern;
// 任何时间匹配
pattern = new CronPattern("* * * * *");
for (int i = 0; i < 1; i++) {
Assert.assertTrue(pattern.match(DateUtil.current(), false));
}
// 分 时 天 月 周
pattern = CronPattern.of("* * * * *");
// 测试时,秒归零,则任意时间匹配
assertMatch(pattern, DateUtil.beginOfMinute(DateUtil.date()).toString());
}
@Test
@@ -40,11 +38,11 @@ public class CronPatternTest {
CronPattern pattern;
// 12:11匹配
pattern = new CronPattern("39 11 12 * * *");
pattern = CronPattern.of("39 11 12 * * *");
assertMatch(pattern, "12:11:39");
// 每5分钟匹配匹配分钟为[0,5,10,15,20,25,30,35,40,45,50,55]
pattern = new CronPattern("39 */5 * * * *");
pattern = CronPattern.of("39 */5 * * * *");
assertMatch(pattern, "12:00:39");
assertMatch(pattern, "12:05:39");
assertMatch(pattern, "12:10:39");
@@ -59,28 +57,28 @@ public class CronPatternTest {
assertMatch(pattern, "12:55:39");
// 2:01,3:01,4:01
pattern = new CronPattern("39 1 2-4 * * *");
pattern = CronPattern.of("39 1 2-4 * * *");
assertMatch(pattern, "02:01:39");
assertMatch(pattern, "03:01:39");
assertMatch(pattern, "04:01:39");
// 2:01,3:01,4:01
pattern = new CronPattern("39 1 2,3,4 * * *");
pattern = CronPattern.of("39 1 2,3,4 * * *");
assertMatch(pattern, "02:01:39");
assertMatch(pattern, "03:01:39");
assertMatch(pattern, "04:01:39");
// 08-07, 08-06
pattern = new CronPattern("39 0 0 6,7 8 *");
pattern = CronPattern.of("39 0 0 6,7 8 *");
assertMatch(pattern, "2016-08-07 00:00:39");
assertMatch(pattern, "2016-08-06 00:00:39");
// 别名忽略大小写
pattern = new CronPattern("39 0 0 6,7 Aug *");
pattern = CronPattern.of("39 0 0 6,7 Aug *");
assertMatch(pattern, "2016-08-06 00:00:39");
assertMatch(pattern, "2016-08-07 00:00:39");
pattern = new CronPattern("39 0 0 7 aug *");
pattern = CronPattern.of("39 0 0 7 aug *");
assertMatch(pattern, "2016-08-07 00:00:39");
}
@@ -104,34 +102,34 @@ public class CronPatternTest {
@SuppressWarnings("ConstantConditions")
@Test
public void CronPatternTest2() {
CronPattern pattern = new CronPattern("0/30 * * * *");
CronPattern pattern = CronPattern.of("0/30 * * * *");
Assert.assertTrue(pattern.match(DateUtil.parse("2018-10-09 12:00:00").getTime(), false));
Assert.assertTrue(pattern.match(DateUtil.parse("2018-10-09 12:30:00").getTime(), false));
pattern = new CronPattern("32 * * * *");
pattern = CronPattern.of("32 * * * *");
Assert.assertTrue(pattern.match(DateUtil.parse("2018-10-09 12:32:00").getTime(), false));
}
@Test
public void patternTest() {
CronPattern pattern = new CronPattern("* 0 4 * * ?");
CronPattern pattern = CronPattern.of("* 0 4 * * ?");
assertMatch(pattern, "2017-02-09 04:00:00");
assertMatch(pattern, "2017-02-19 04:00:33");
// 6位Quartz风格表达式
pattern = new CronPattern("* 0 4 * * ?");
pattern = CronPattern.of("* 0 4 * * ?");
assertMatch(pattern, "2017-02-09 04:00:00");
assertMatch(pattern, "2017-02-19 04:00:33");
}
@Test
public void rangePatternTest() {
CronPattern pattern = new CronPattern("* 20/2 * * * ?");
CronPattern pattern = CronPattern.of("* 20/2 * * * ?");
assertMatch(pattern, "2017-02-09 04:20:00");
assertMatch(pattern, "2017-02-09 05:20:00");
assertMatch(pattern, "2017-02-19 04:22:33");
pattern = new CronPattern("* 2-20/2 * * * ?");
pattern = CronPattern.of("* 2-20/2 * * * ?");
assertMatch(pattern, "2017-02-09 04:02:00");
assertMatch(pattern, "2017-02-09 05:04:00");
assertMatch(pattern, "2017-02-19 04:20:33");
@@ -140,23 +138,23 @@ public class CronPatternTest {
@Test
public void lastTest() {
// 每月最后一天的任意时间
CronPattern pattern = new CronPattern("* * * L * ?");
CronPattern pattern = CronPattern.of("* * * L * ?");
assertMatch(pattern, "2017-07-31 04:20:00");
assertMatch(pattern, "2017-02-28 04:20:00");
// 最后一个月的任意时间
pattern = new CronPattern("* * * * L ?");
pattern = CronPattern.of("* * * * L ?");
assertMatch(pattern, "2017-12-02 04:20:00");
// 任意天的最后时间
pattern = new CronPattern("L L L * * ?");
pattern = CronPattern.of("L L L * * ?");
assertMatch(pattern, "2017-12-02 23:59:59");
}
@Test(expected = CronException.class)
public void rangeYearTest() {
// year的范围是1970~2099年超出报错
new CronPattern("0/1 * * * 1/1 ? 2020-2120");
CronPattern.of("0/1 * * * 1/1 ? 2020-2120");
}
/**