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

@ -174,11 +174,12 @@ public enum Month {
* 解析别名为Month对象别名如jan或者JANUARY不区分大小写 * 解析别名为Month对象别名如jan或者JANUARY不区分大小写
* *
* @param name 别名值 * @param name 别名值
* @return 月份int值 * @return 月份枚举Month非空
* @throws IllegalArgumentException 如果别名无对应的枚举抛出此异常 * @throws IllegalArgumentException 如果别名无对应的枚举抛出此异常
* @since 5.8.0 * @since 5.8.0
*/ */
public static Month of(String name) throws IllegalArgumentException { public static Month of(String name) throws IllegalArgumentException {
Assert.notBlank(name);
Month of = of(ArrayUtil.indexOfIgnoreCase(ALIASES, name)); Month of = of(ArrayUtil.indexOfIgnoreCase(ALIASES, name));
if (null == of) { if (null == of) {
of = Month.valueOf(name.toUpperCase()); of = Month.valueOf(name.toUpperCase());
@ -186,6 +187,16 @@ public enum Month {
return of; return of;
} }
/**
* {@link java.time.Month}转换为Month对象
* @param month {@link java.time.Month}
* @return Month
* @since 5.8.0
*/
public static Month of(java.time.Month month){
return of(month.ordinal());
}
/** /**
* 获得指定月的最后一天 * 获得指定月的最后一天
* *

View File

@ -1,5 +1,6 @@
package cn.hutool.core.date; package cn.hutool.core.date;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import java.time.DayOfWeek; import java.time.DayOfWeek;
@ -165,11 +166,12 @@ public enum Week {
* 解析别名为Week对象别名如sun或者SUNDAY不区分大小写 * 解析别名为Week对象别名如sun或者SUNDAY不区分大小写
* *
* @param name 别名值 * @param name 别名值
* @return int值 * @return 枚举Week非空
* @throws IllegalArgumentException 如果别名无对应的枚举抛出此异常 * @throws IllegalArgumentException 如果别名无对应的枚举抛出此异常
* @since 5.8.0 * @since 5.8.0
*/ */
public static Week of(String name) throws IllegalArgumentException { public static Week of(String name) throws IllegalArgumentException {
Assert.notBlank(name);
Week of = of(ArrayUtil.indexOfIgnoreCase(ALIASES, name)); Week of = of(ArrayUtil.indexOfIgnoreCase(ALIASES, name));
if (null == of) { if (null == of) {
of = Week.valueOf(name.toUpperCase()); of = Week.valueOf(name.toUpperCase());
@ -192,8 +194,9 @@ public enum Week {
* @since 5.7.14 * @since 5.7.14
*/ */
public static Week of(DayOfWeek dayOfWeek) { public static Week of(DayOfWeek dayOfWeek) {
int week = dayOfWeek.ordinal() + 2; Assert.notNull(dayOfWeek);
if (week > 7) { int week = dayOfWeek.ordinal() + 1;
if (7 == week) {
week = 1; week = 1;
} }
return of(week); return of(week);

View File

@ -51,16 +51,19 @@ public class MonthTest {
@Test @Test
public void ofTest(){ public void ofTest(){
Month jan = Month.of("Jan"); Month month = Month.of("Jan");
Assert.assertEquals(Month.JANUARY, jan); Assert.assertEquals(Month.JANUARY, month);
jan = Month.of("JAN"); month = Month.of("JAN");
Assert.assertEquals(Month.JANUARY, jan); Assert.assertEquals(Month.JANUARY, month);
jan = Month.of("FEBRUARY"); month = Month.of("FEBRUARY");
Assert.assertEquals(Month.FEBRUARY, jan); Assert.assertEquals(Month.FEBRUARY, month);
jan = Month.of("February"); month = Month.of("February");
Assert.assertEquals(Month.FEBRUARY, jan); Assert.assertEquals(Month.FEBRUARY, month);
month = Month.of(java.time.Month.FEBRUARY);
Assert.assertEquals(Month.FEBRUARY, month);
} }
} }

View File

@ -37,6 +37,16 @@ public class WeekTest {
Assert.assertEquals(Week.SATURDAY, Week.of("SATURDAY")); Assert.assertEquals(Week.SATURDAY, Week.of("SATURDAY"));
} }
public void ofTest2(){
Assert.assertEquals(Week.SUNDAY, Week.of(DayOfWeek.SUNDAY));
Assert.assertEquals(Week.MONDAY, Week.of(DayOfWeek.MONDAY));
Assert.assertEquals(Week.TUESDAY, Week.of(DayOfWeek.TUESDAY));
Assert.assertEquals(Week.WEDNESDAY, Week.of(DayOfWeek.WEDNESDAY));
Assert.assertEquals(Week.THURSDAY, Week.of(DayOfWeek.THURSDAY));
Assert.assertEquals(Week.FRIDAY, Week.of(DayOfWeek.FRIDAY));
Assert.assertEquals(Week.SATURDAY, Week.of(DayOfWeek.SATURDAY));
}
@Test @Test
public void toJdkDayOfWeekTest(){ public void toJdkDayOfWeekTest(){
Assert.assertEquals(DayOfWeek.MONDAY, Week.MONDAY.toJdkDayOfWeek()); Assert.assertEquals(DayOfWeek.MONDAY, Week.MONDAY.toJdkDayOfWeek());

View File

@ -45,7 +45,7 @@ public class CronConfig {
/** /**
* 是否支持秒匹配 * 是否支持秒匹配
* *
* @return <code>true</code>使用<code>false</code>不使用 * @return {@code true}使用{@code false}不使用
*/ */
public boolean isMatchSecond() { public boolean isMatchSecond() {
return this.matchSecond; 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 * @return this
*/ */
public CronConfig setMatchSecond(boolean isMatchSecond) { public CronConfig setMatchSecond(boolean isMatchSecond) {

View File

@ -6,8 +6,13 @@ import cn.hutool.core.lang.Assert;
import cn.hutool.cron.CronException; import cn.hutool.cron.CronException;
/** /**
* 表达式各个部分的枚举用于限定位置和规则<br> * 表达式各个部分的枚举用于限定在表达式中的位置和规则如最小值和最大值<br>
* {@link #ordinal()}表示此部分在表达式中的位置如0表示秒 * {@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 * @author looly
* @since 5.8.0 * @since 5.8.0

View File

@ -1,19 +1,20 @@
package cn.hutool.cron.pattern.matcher; package cn.hutool.cron.pattern.matcher;
import java.util.List; import java.util.Collection;
import java.util.LinkedHashSet;
/** /**
* 年匹配<br> * 年匹配<br>
* 考虑年数字太大不适合boolean数组单独使用列表遍历匹配 * 考虑年数字太大不适合boolean数组单独使用{@link LinkedHashSet}匹配
* @author Looly
* *
* @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) { public YearValueMatcher(Collection<Integer> intValueList) {
this.valueList = intValueList; this.valueList = new LinkedHashSet<>(intValueList);
} }
@Override @Override

View File

@ -3,7 +3,6 @@ package cn.hutool.cron.pattern.parser;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.Month; import cn.hutool.core.date.Month;
import cn.hutool.core.date.Week; import cn.hutool.core.date.Week;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.CronException; import cn.hutool.cron.CronException;
@ -18,7 +17,18 @@ import java.util.ArrayList;
import java.util.List; 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 * @author looly
* @since 5.8.0 * @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 表达式 * @param value 表达式
* @return {@link ValueMatcher} * @return {@link ValueMatcher}
@ -220,11 +236,6 @@ public class PartParser {
* @throws CronException 当无效数字或无效别名时抛出 * @throws CronException 当无效数字或无效别名时抛出
*/ */
private int parseNumber(String value) throws CronException { private int parseNumber(String value) throws CronException {
if ("L".equalsIgnoreCase(value)) {
// L表示最大值
return part.getMax();
}
int i; int i;
try { try {
i = Integer.parseInt(value); i = Integer.parseInt(value);
@ -233,7 +244,7 @@ public class PartParser {
} }
// 周日可以用0或7表示统一转换为0 // 周日可以用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(); 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 别名 * @param name 别名
* @return 解析int值 * @return 解析int值
* @throws CronException 无匹配别名时抛出异常 * @throws CronException 无匹配别名时抛出异常
*/ */
private int parseAlias(String name) throws CronException { private int parseAlias(String name) throws CronException {
if ("L".equalsIgnoreCase(name)) {
// L表示最大值
return part.getMax();
}
switch (this.part) { switch (this.part) {
case MONTH: case MONTH:
final Month month = Month.of(name);
Assert.notNull(month, () -> new CronException("Invalid month alias: {}", name));
// 月份从1开始 // 月份从1开始
return month.getValueBaseOne(); return Month.of(name).getValueBaseOne();
case DAY_OF_WEEK: case DAY_OF_WEEK:
final Week week = Week.of(name);
Assert.notNull(week, () -> new CronException("Invalid day of week alias: {}", name));
// 周从0开始0表示周日 // 周从0开始0表示周日
return week.ordinal(); return Week.of(name).ordinal();
} }
throw new CronException("Invalid alias value: [{}]", name); throw new CronException("Invalid alias value: [{}]", name);

View File

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