diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/PropDesc.java b/hutool-core/src/main/java/cn/hutool/core/bean/PropDesc.java
index c9ea67472..af0d9edef 100644
--- a/hutool-core/src/main/java/cn/hutool/core/bean/PropDesc.java
+++ b/hutool-core/src/main/java/cn/hutool/core/bean/PropDesc.java
@@ -251,7 +251,7 @@ public class PropDesc {
* @param value 属性值,可以为任意类型
* @param ignoreNull 是否忽略{@code null}值,true表示忽略
* @param ignoreError 是否忽略错误,包括转换错误和注入错误
- * @param override 是否覆盖目标值,如果不覆盖,会先读取bean的值,非{@code null}则写,否则忽略。如果覆盖,则不判断直接写
+ * @param override 是否覆盖目标值,如果不覆盖,会先读取bean的值,{@code null}则写,否则忽略。如果覆盖,则不判断直接写
* @return this
* @since 5.7.17
*/
diff --git a/hutool-core/src/main/java/cn/hutool/core/date/Week.java b/hutool-core/src/main/java/cn/hutool/core/date/Week.java
index c047dd5e7..7fd20abae 100644
--- a/hutool-core/src/main/java/cn/hutool/core/date/Week.java
+++ b/hutool-core/src/main/java/cn/hutool/core/date/Week.java
@@ -1,5 +1,7 @@
package cn.hutool.core.date;
+import cn.hutool.core.util.ArrayUtil;
+
import java.time.DayOfWeek;
import java.util.Calendar;
@@ -48,6 +50,12 @@ public enum Week {
SATURDAY(Calendar.SATURDAY);
// ---------------------------------------------------------------
+ /**
+ * Weeks aliases.
+ */
+ private static final String[] ALIASES = {"sun", "mon", "tue", "wed", "thu", "fri", "sat"};
+ private static final Week[] ENUMS = Week.values();
+
/**
* 星期对应{@link Calendar} 中的Week值
*/
@@ -71,6 +79,20 @@ public enum Week {
return this.value;
}
+ /**
+ * 获取ISO8601规范的int值,from 1 (Monday) to 7 (Sunday).
+ *
+ * @return ISO8601规范的int值
+ * @since 5.8.0
+ */
+ public int getIso8601Value(){
+ int iso8601IntValue = getValue() -1;
+ if(0 == iso8601IntValue){
+ iso8601IntValue = 7;
+ }
+ return iso8601IntValue;
+ }
+
/**
* 转换为中文名
*
@@ -109,6 +131,16 @@ public enum Week {
}
}
+ /**
+ * 转换为{@link DayOfWeek}
+ *
+ * @return {@link DayOfWeek}
+ * @since 5.8.0
+ */
+ public DayOfWeek toJdkDayOfWeek() {
+ return DayOfWeek.of(getIso8601Value());
+ }
+
/**
* 将 {@link Calendar}星期相关值转换为Week枚举对象
*
@@ -123,24 +155,26 @@ public enum Week {
* @see #SATURDAY
*/
public static Week of(int calendarWeekIntValue) {
- switch (calendarWeekIntValue) {
- case Calendar.SUNDAY:
- return SUNDAY;
- case Calendar.MONDAY:
- return MONDAY;
- case Calendar.TUESDAY:
- return TUESDAY;
- case Calendar.WEDNESDAY:
- return WEDNESDAY;
- case Calendar.THURSDAY:
- return THURSDAY;
- case Calendar.FRIDAY:
- return FRIDAY;
- case Calendar.SATURDAY:
- return SATURDAY;
- default:
- return null;
+ if (calendarWeekIntValue >= ENUMS.length || calendarWeekIntValue < 0) {
+ return null;
}
+ return ENUMS[calendarWeekIntValue];
+ }
+
+ /**
+ * 解析别名为Week对象,别名如:sun或者SUNDAY,不区分大小写
+ *
+ * @param name 别名值
+ * @return 周int值
+ * @throws IllegalArgumentException 如果别名无对应的枚举,抛出此异常
+ * @since 5.8.0
+ */
+ public static Week of(String name) throws IllegalArgumentException {
+ Week of = of(ArrayUtil.indexOfIgnoreCase(ALIASES, name));
+ if (null == of) {
+ of = Week.valueOf(name.toUpperCase());
+ }
+ return of;
}
/**
diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/Range.java b/hutool-core/src/main/java/cn/hutool/core/lang/Range.java
index dbee96127..fc71955b6 100644
--- a/hutool-core/src/main/java/cn/hutool/core/lang/Range.java
+++ b/hutool-core/src/main/java/cn/hutool/core/lang/Range.java
@@ -188,7 +188,7 @@ public class Range implements Iterable, Iterator, Serializable {
}
/**
- * 重置{@link Range}
+ * 重置Range
*
* @return this
*/
diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableLong.java b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableLong.java
index e508e1eda..5895325a8 100644
--- a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableLong.java
+++ b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableLong.java
@@ -3,7 +3,7 @@ package cn.hutool.core.lang.mutable;
import cn.hutool.core.util.NumberUtil;
/**
- * 可变 long 类型
+ * 可变 {@code long} 类型
*
* @see Long
* @since 3.0.1
@@ -21,6 +21,7 @@ public class MutableLong extends Number implements Comparable, Muta
/**
* 构造
+ *
* @param value 值
*/
public MutableLong(final long value) {
@@ -29,6 +30,7 @@ public class MutableLong extends Number implements Comparable, Muta
/**
* 构造
+ *
* @param value 值
*/
public MutableLong(final Number value) {
@@ -37,6 +39,7 @@ public class MutableLong extends Number implements Comparable, Muta
/**
* 构造
+ *
* @param value String值
* @throws NumberFormatException 数字转换错误
*/
@@ -51,6 +54,7 @@ public class MutableLong extends Number implements Comparable, Muta
/**
* 设置值
+ *
* @param value 值
*/
public void set(final long value) {
@@ -63,8 +67,10 @@ public class MutableLong extends Number implements Comparable, Muta
}
// -----------------------------------------------------------------------
+
/**
* 值+1
+ *
* @return this
*/
public MutableLong increment() {
@@ -74,6 +80,7 @@ public class MutableLong extends Number implements Comparable, Muta
/**
* 值减一
+ *
* @return this
*/
public MutableLong decrement() {
@@ -82,8 +89,10 @@ public class MutableLong extends Number implements Comparable, Muta
}
// -----------------------------------------------------------------------
+
/**
* 增加值
+ *
* @param operand 被增加的值
* @return this
*/
@@ -94,6 +103,7 @@ public class MutableLong extends Number implements Comparable, Muta
/**
* 增加值
+ *
* @param operand 被增加的值,非空
* @return this
* @throws NullPointerException if the object is null
@@ -148,16 +158,17 @@ public class MutableLong extends Number implements Comparable, Muta
}
// -----------------------------------------------------------------------
+
/**
* 相等需同时满足如下条件:
*
* - 非空
- * - 类型为 {@link MutableLong}
+ * - 类型为 MutableLong
* - 值相等
*
*
* @param obj 比对的对象
- * @return 相同返回true,否则 false
+ * @return 相同返回true,否则 {@code false}
*/
@Override
public boolean equals(final Object obj) {
@@ -173,10 +184,11 @@ public class MutableLong extends Number implements Comparable, Muta
}
// -----------------------------------------------------------------------
+
/**
* 比较
*
- * @param other 其它 {@link MutableLong} 对象
+ * @param other 其它 MutableLong 对象
* @return x==y返回0,x<y返回-1,x>y返回1
*/
@Override
diff --git a/hutool-core/src/main/java/cn/hutool/core/util/EnumUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/EnumUtil.java
index aa7c788d1..018baa3dd 100644
--- a/hutool-core/src/main/java/cn/hutool/core/util/EnumUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/util/EnumUtil.java
@@ -1,5 +1,10 @@
package cn.hutool.core.util;
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.lang.func.Func1;
+import cn.hutool.core.lang.func.LambdaUtil;
+import cn.hutool.core.map.MapUtil;
+
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
@@ -9,11 +14,6 @@ import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
-import cn.hutool.core.lang.Assert;
-import cn.hutool.core.lang.func.Func1;
-import cn.hutool.core.lang.func.LambdaUtil;
-import cn.hutool.core.map.MapUtil;
-
/**
* 枚举工具类
*
@@ -56,7 +56,7 @@ public class EnumUtil {
}
/**
- * 字符串转枚举,调用{@link Enum#valueOf(Class, String)}
+ * 获取给定位置的枚举值
*
* @param 枚举类型泛型
* @param enumClass 枚举类
diff --git a/hutool-core/src/test/java/cn/hutool/core/date/WeekTest.java b/hutool-core/src/test/java/cn/hutool/core/date/WeekTest.java
new file mode 100644
index 000000000..3eb9d3f86
--- /dev/null
+++ b/hutool-core/src/test/java/cn/hutool/core/date/WeekTest.java
@@ -0,0 +1,50 @@
+package cn.hutool.core.date;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.time.DayOfWeek;
+
+public class WeekTest {
+
+ @Test
+ public void ofTest(){
+ //测试别名及大小写
+ Assert.assertEquals(Week.SUNDAY, Week.of("sun"));
+ Assert.assertEquals(Week.SUNDAY, Week.of("SUN"));
+ Assert.assertEquals(Week.SUNDAY, Week.of("Sun"));
+ //测试全名及大小写
+ Assert.assertEquals(Week.SUNDAY, Week.of("sunday"));
+ Assert.assertEquals(Week.SUNDAY, Week.of("Sunday"));
+ Assert.assertEquals(Week.SUNDAY, Week.of("SUNDAY"));
+
+ Assert.assertEquals(Week.MONDAY, Week.of("Mon"));
+ Assert.assertEquals(Week.MONDAY, Week.of("Monday"));
+
+ Assert.assertEquals(Week.TUESDAY, Week.of("tue"));
+ Assert.assertEquals(Week.TUESDAY, Week.of("tuesday"));
+
+ Assert.assertEquals(Week.WEDNESDAY, Week.of("wed"));
+ Assert.assertEquals(Week.WEDNESDAY, Week.of("WEDNESDAY"));
+
+ Assert.assertEquals(Week.THURSDAY, Week.of("thu"));
+ Assert.assertEquals(Week.THURSDAY, Week.of("THURSDAY"));
+
+ Assert.assertEquals(Week.FRIDAY, Week.of("fri"));
+ Assert.assertEquals(Week.FRIDAY, Week.of("FRIDAY"));
+
+ Assert.assertEquals(Week.SATURDAY, Week.of("sat"));
+ Assert.assertEquals(Week.SATURDAY, Week.of("SATURDAY"));
+ }
+
+ @Test
+ public void toJdkDayOfWeekTest(){
+ Assert.assertEquals(DayOfWeek.MONDAY, Week.MONDAY.toJdkDayOfWeek());
+ Assert.assertEquals(DayOfWeek.TUESDAY, Week.TUESDAY.toJdkDayOfWeek());
+ Assert.assertEquals(DayOfWeek.WEDNESDAY, Week.WEDNESDAY.toJdkDayOfWeek());
+ Assert.assertEquals(DayOfWeek.THURSDAY, Week.THURSDAY.toJdkDayOfWeek());
+ Assert.assertEquals(DayOfWeek.FRIDAY, Week.FRIDAY.toJdkDayOfWeek());
+ Assert.assertEquals(DayOfWeek.SATURDAY, Week.SATURDAY.toJdkDayOfWeek());
+ Assert.assertEquals(DayOfWeek.SUNDAY, Week.SUNDAY.toJdkDayOfWeek());
+ }
+}
diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/CronPattern.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/CronPattern.java
index 2ce7154b3..80e6e1d26 100644
--- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/CronPattern.java
+++ b/hutool-cron/src/main/java/cn/hutool/cron/pattern/CronPattern.java
@@ -1,7 +1,7 @@
package cn.hutool.cron.pattern;
import cn.hutool.cron.pattern.matcher.MatcherTable;
-import cn.hutool.cron.pattern.parser.CronPatternParser;
+import cn.hutool.cron.pattern.parser.PatternParser;
import java.util.Calendar;
import java.util.GregorianCalendar;
@@ -68,6 +68,17 @@ public class CronPattern {
private final String pattern;
private final MatcherTable matcherTable;
+ /**
+ * 解析表达式为 CronPattern
+ *
+ * @param pattern 表达式
+ * @return CronPattern
+ * @since 5.8.0
+ */
+ public static CronPattern of(String pattern) {
+ return new CronPattern(pattern);
+ }
+
/**
* 构造
*
@@ -75,10 +86,11 @@ public class CronPattern {
*/
public CronPattern(String pattern) {
this.pattern = pattern;
- this.matcherTable = CronPatternParser.parse(pattern);
+ this.matcherTable = PatternParser.parse(pattern);
}
// --------------------------------------------------------------------------------------- match start
+
/**
* 给定时间是否匹配定时任务表达式
*
@@ -104,6 +116,24 @@ public class CronPattern {
return match(calendar, isMatchSecond);
}
+ /**
+ * 返回匹配到的下一个时间
+ *
+ * @param calendar 时间
+ * @return 匹配到的下一个时间
+ */
+ public Calendar nextMatchAfter(Calendar calendar) {
+ final int second = calendar.get(Calendar.SECOND);
+ final int minute = calendar.get(Calendar.MINUTE);
+ final int hour = calendar.get(Calendar.HOUR_OF_DAY);
+ final int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
+ final int month = calendar.get(Calendar.MONTH) + 1;// 月份从1开始
+ final int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1; // 星期从0开始,0和7都表示周日
+ final int year = calendar.get(Calendar.YEAR);
+
+ return this.matcherTable.nextMatchAfter(second, minute, hour, dayOfMonth, month, dayOfWeek, year, calendar.getTimeZone());
+ }
+
/**
* 给定时间是否匹配定时任务表达式
*
@@ -111,7 +141,7 @@ public class CronPattern {
* @param isMatchSecond 是否匹配秒
* @return 如果匹配返回 {@code true}, 否则返回 {@code false}
*/
- public boolean match(GregorianCalendar calendar, boolean isMatchSecond) {
+ public boolean match(Calendar calendar, boolean isMatchSecond) {
final int second = isMatchSecond ? calendar.get(Calendar.SECOND) : -1;
final int minute = calendar.get(Calendar.MINUTE);
final int hour = calendar.get(Calendar.HOUR_OF_DAY);
diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/CronPatternBuilder.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/CronPatternBuilder.java
new file mode 100644
index 000000000..02eb6db0f
--- /dev/null
+++ b/hutool-cron/src/main/java/cn/hutool/cron/pattern/CronPatternBuilder.java
@@ -0,0 +1,23 @@
+package cn.hutool.cron.pattern;
+
+import cn.hutool.core.builder.Builder;
+import cn.hutool.core.util.StrUtil;
+
+public class CronPatternBuilder implements Builder {
+
+ final String[] parts = new String[7];
+
+ public static CronPatternBuilder of(){
+ return new CronPatternBuilder();
+ }
+
+ public CronPatternBuilder set(Part part, String value){
+ parts[part.ordinal()] = value;
+ return this;
+ }
+
+ @Override
+ public String build() {
+ return StrUtil.join(StrUtil.SPACE, (Object[]) parts);
+ }
+}
diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/Part.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/Part.java
new file mode 100644
index 000000000..5cfd5435a
--- /dev/null
+++ b/hutool-cron/src/main/java/cn/hutool/cron/pattern/Part.java
@@ -0,0 +1,73 @@
+package cn.hutool.cron.pattern;
+
+import cn.hutool.core.date.Month;
+import cn.hutool.core.date.Week;
+import cn.hutool.core.lang.Assert;
+import cn.hutool.cron.CronException;
+
+/**
+ * 表达式各个部分的枚举,用于限定位置和规则
+ * {@link #ordinal()}表示此部分在表达式中的位置,如0表示秒
+ *
+ * @author looly
+ * @since 5.8.0
+ */
+public enum Part {
+ SECOND(0, 59),
+ MINUTE(0, 59),
+ HOUR(0, 23),
+ DAY_OF_MONTH(1, 31),
+ MONTH(Month.JANUARY.getValueBaseOne(), Month.DECEMBER.getValueBaseOne()),
+ DAY_OF_WEEK(Week.SUNDAY.ordinal(), Week.SATURDAY.ordinal()),
+ YEAR(1970, 2099);
+
+ private final int min;
+ private final int max;
+
+ /**
+ * 构造
+ *
+ * @param min 限定最小值(包含)
+ * @param max 限定最大值(包含)
+ */
+ Part(int min, int max) {
+ if (min > max) {
+ this.min = max;
+ this.max = min;
+ } else {
+ this.min = min;
+ this.max = max;
+ }
+ }
+
+ /**
+ * 获取最小值
+ *
+ * @return 最小值
+ */
+ public int getMin() {
+ return this.min;
+ }
+
+ /**
+ * 获取最大值
+ *
+ * @return 最大值
+ */
+ public int getMax() {
+ return this.max;
+ }
+
+ /**
+ * 检查单个值是否有效
+ *
+ * @param value 值
+ * @return 检查后的值
+ * @throws CronException 检查无效抛出此异常
+ */
+ public int checkValue(int value) throws CronException {
+ Assert.checkBetween(value, min, max,
+ () -> new CronException("Value {} out of range: [{} , {}]", value, min, max));
+ return value;
+ }
+}
diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/matcher/DayOfMonthValueMatcher.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/matcher/DayOfMonthValueMatcher.java
index d92a436df..7969871b7 100644
--- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/matcher/DayOfMonthValueMatcher.java
+++ b/hutool-cron/src/main/java/cn/hutool/cron/pattern/matcher/DayOfMonthValueMatcher.java
@@ -31,8 +31,8 @@ public class DayOfMonthValueMatcher extends BoolArrayValueMatcher {
*/
public boolean match(int value, int month, boolean isLeapYear) {
return (super.match(value) // 在约定日范围内的某一天
- //匹配器中用户定义了最后一天(32表示最后一天)
- || (value > 27 && match(32) && isLastDayOfMonth(value, month, isLeapYear)));
+ //匹配器中用户定义了最后一天(31表示最后一天)
+ || (value > 27 && match(31) && isLastDayOfMonth(value, month, isLeapYear)));
}
/**
diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/matcher/MatcherTable.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/matcher/MatcherTable.java
index 1e04f36b8..87a09d9c5 100644
--- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/matcher/MatcherTable.java
+++ b/hutool-cron/src/main/java/cn/hutool/cron/pattern/matcher/MatcherTable.java
@@ -1,10 +1,13 @@
package cn.hutool.cron.pattern.matcher;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Console;
+import cn.hutool.core.lang.mutable.MutableBool;
-import java.time.LocalDateTime;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.List;
+import java.util.TimeZone;
/**
* 时间匹配表,用于存放定时任务表达式解析后的结构信息
@@ -28,54 +31,107 @@ public class MatcherTable {
matchers = new ArrayList<>(size);
}
- public LocalDateTime nextMatchAfter(int second, int minute, int hour, int dayOfMonth, int month, int dayOfWeek, int year) {
- List nextMatchs = new ArrayList<>(second);
+ /**
+ * 获取下一个最近的匹配日期时间
+ *
+ * @param second 秒
+ * @param minute 分
+ * @param hour 时
+ * @param dayOfMonth 天
+ * @param month 月(从0开始)
+ * @param dayOfWeek 周
+ * @param year 年
+ * @param zone 时区
+ * @return {@link Calendar}
+ */
+ public Calendar nextMatchAfter(int second, int minute, int hour, int dayOfMonth, int month, int dayOfWeek, int year, TimeZone zone) {
+ List nextMatchs = new ArrayList<>(second);
for (DateTimeMatcher matcher : matchers) {
nextMatchs.add(singleNextMatchAfter(matcher, second, minute, hour,
- dayOfMonth, month, dayOfWeek, year));
+ dayOfMonth, month, dayOfWeek, year, zone));
}
- // 返回最先匹配到的日期
+ // 返回匹配到的最早日期
return CollUtil.min(nextMatchs);
}
- private static LocalDateTime singleNextMatchAfter(DateTimeMatcher matcher, int second, int minute, int hour,
- int dayOfMonth, int month, int dayOfWeek, int year){
- boolean isNextNotEquals = true;
+ /**
+ * 获取下一个匹配日期时间
+ *
+ * @param matcher 匹配器
+ * @param second 秒
+ * @param minute 分
+ * @param hour 时
+ * @param dayOfMonth 天
+ * @param month 月(从0开始)
+ * @param dayOfWeek 周
+ * @param year 年
+ * @param zone 时区
+ * @return {@link Calendar}
+ */
+ private static Calendar singleNextMatchAfter(DateTimeMatcher matcher, int second, int minute, int hour,
+ int dayOfMonth, int month, int dayOfWeek, int year, TimeZone zone) {
+
+ Calendar calendar = Calendar.getInstance(zone);
+
+ // 上一个字段不一致,说明产生了新值,下一个字段使用最小值
+ MutableBool isNextEquals = new MutableBool(true);
// 年
- final int nextYear = matcher.yearMatcher.nextAfter(year);
- isNextNotEquals &= (year != nextYear);
+ final int nextYear = nextAfter(matcher.yearMatcher, year, isNextEquals);
+ calendar.set(Calendar.YEAR, nextYear);
// 周
- int nextDayOfWeek;
- if(isNextNotEquals){
- // 上一个字段不一致,说明产生了新值,本字段使用最小值
- nextDayOfWeek = ((BoolArrayValueMatcher)matcher.dayOfWeekMatcher).getMinValue();
- }else{
- nextDayOfWeek = matcher.dayOfWeekMatcher.nextAfter(dayOfWeek);
- isNextNotEquals &= (dayOfWeek != nextDayOfWeek);
- }
+ final int nextDayOfWeek = nextAfter(matcher.dayOfWeekMatcher, dayOfWeek, isNextEquals);
+ calendar.set(Calendar.DAY_OF_WEEK, nextDayOfWeek);
// 月
- int nextMonth;
- if(isNextNotEquals){
- // 上一个字段不一致,说明产生了新值,本字段使用最小值
- nextMonth = ((BoolArrayValueMatcher)matcher.monthMatcher).getMinValue();
- }else{
- nextMonth = matcher.monthMatcher.nextAfter(dayOfWeek);
- isNextNotEquals &= (month != nextMonth);
- }
+ final int nextMonth = nextAfter(matcher.monthMatcher, month + 1, isNextEquals);
+ calendar.set(Calendar.MONTH, nextMonth - 1);
// 日
- int nextDayOfMonth;
- if(isNextNotEquals){
- // 上一个字段不一致,说明产生了新值,本字段使用最小值
- nextDayOfMonth = ((BoolArrayValueMatcher)matcher.dayOfMonthMatcher).getMinValue();
- }else{
- nextDayOfMonth = matcher.dayOfMonthMatcher.nextAfter(dayOfWeek);
- isNextNotEquals &= (dayOfMonth != nextDayOfMonth);
- }
+ final int nextDayOfMonth = nextAfter(matcher.dayOfMonthMatcher, dayOfMonth, isNextEquals);
+ calendar.set(Calendar.DAY_OF_MONTH, nextDayOfMonth);
- return null;
+ // 时
+ final int nextHour = nextAfter(matcher.hourMatcher, hour, isNextEquals);
+ calendar.set(Calendar.HOUR, nextHour);
+
+ // 分
+ int nextMinute = nextAfter(matcher.minuteMatcher, minute, isNextEquals);
+ calendar.set(Calendar.MINUTE, nextMinute);
+
+ // 秒
+ final int nextSecond = nextAfter(matcher.secondMatcher, second, isNextEquals);
+ calendar.set(Calendar.SECOND, nextSecond);
+
+ Console.log(nextYear, nextDayOfWeek, nextMonth, nextDayOfMonth, nextHour, nextMinute, nextSecond);
+ return calendar;
+ }
+
+ /**
+ * 获取对应字段匹配器的下一个值
+ *
+ * @param matcher 匹配器
+ * @param value 值
+ * @param isNextEquals 是否下一个值和值相同。不同获取初始值,相同获取下一值,然后修改。
+ * @return 下一个值,-1标识匹配所有值的情况,应获取整个字段的最小值
+ */
+ private static int nextAfter(ValueMatcher matcher, int value, MutableBool isNextEquals) {
+ int nextValue;
+ if (isNextEquals.get()) {
+ // 上一层级得到相同值,下级获取下个值
+ nextValue = matcher.nextAfter(value);
+ isNextEquals.set(nextValue == value);
+ } else {
+ // 上一层级的值得到了不同值,下级的所有值使用最小值
+ if (matcher instanceof AlwaysTrueValueMatcher) {
+ nextValue = value;
+ } else if (matcher instanceof BoolArrayValueMatcher) {
+ nextValue = ((BoolArrayValueMatcher) matcher).getMinValue();
+ } else {
+ throw new IllegalArgumentException("Invalid matcher: " + matcher.getClass().getName());
+ }
+ }
+ return nextValue;
}
/**
@@ -85,8 +141,8 @@ public class MatcherTable {
* @param minute 分钟
* @param hour 小时
* @param dayOfMonth 天
- * @param month 月
- * @param dayOfWeek 周几
+ * @param month 月,从1开始
+ * @param dayOfWeek 周,从0开始,0和7都表示周日
* @param year 年
* @return 如果匹配返回 {@code true}, 否则返回 {@code false}
*/
diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/DayOfMonthValueParser.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/DayOfMonthValueParser.java
deleted file mode 100644
index db8e86228..000000000
--- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/DayOfMonthValueParser.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package cn.hutool.cron.pattern.parser;
-
-import cn.hutool.cron.CronException;
-import cn.hutool.cron.pattern.matcher.DayOfMonthValueMatcher;
-import cn.hutool.cron.pattern.matcher.ValueMatcher;
-
-import java.util.List;
-
-/**
- * 每月的几号值处理
- * 每月最多31天,32和“L”都表示最后一天
- *
- * @author Looly
- *
- */
-public class DayOfMonthValueParser extends AbsValueParser {
-
- /**
- * 构造
- */
- public DayOfMonthValueParser() {
- super(1, 31);
- }
-
- @Override
- public int parse(String value) throws CronException {
- if ("L".equalsIgnoreCase(value) || "32".equals(value)) {// 每月最后一天
- return 32;
- } else {
- return super.parse(value);
- }
- }
-
- @Override
- protected ValueMatcher buildValueMatcher(List values) {
- //考虑每月的天数不同,且存在闰年情况,日匹配单独使用
- return new DayOfMonthValueMatcher(values);
- }
-}
diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/DayOfWeekValueParser.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/DayOfWeekValueParser.java
deleted file mode 100644
index 40b2d4eaf..000000000
--- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/DayOfWeekValueParser.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package cn.hutool.cron.pattern.parser;
-
-import cn.hutool.cron.CronException;
-
-/**
- * 星期值处理
- * 1表示星期一,2表示星期二,依次类推,0和7都可以表示星期日
- * {@code L}表示周六
- *
- * @author Looly
- */
-public class DayOfWeekValueParser extends AbsValueParser {
-
- /**
- * Weeks aliases.
- */
- private static final String[] ALIASES = {"sun", "mon", "tue", "wed", "thu", "fri", "sat"};
-
- public DayOfWeekValueParser() {
- super(0, 7);
- }
-
- /**
- * 对于星期提供转换
- * 1表示星期一,2表示星期二,依次类推,0和7都可以表示星期日
- */
- @Override
- public int parse(String value) throws CronException {
- try {
- return super.parse(value) % 7;
- } catch (Exception e) {
- return parseAlias(value);
- }
- }
-
- /**
- * 解析别名
- *
- * @param value 别名值
- * @return 月份int值
- * @throws CronException 无效别名抛出此异常
- */
- private int parseAlias(String value) throws CronException {
- if ("L".equalsIgnoreCase(value)) {
- //最后一天为星期六
- return ALIASES.length - 1;
- }
-
- for (int i = 0; i < ALIASES.length; i++) {
- if (ALIASES[i].equalsIgnoreCase(value)) {
- return i;
- }
- }
- throw new CronException("Invalid month alias: {}", value);
- }
-}
diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/HourValueParser.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/HourValueParser.java
deleted file mode 100644
index d2211870a..000000000
--- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/HourValueParser.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package cn.hutool.cron.pattern.parser;
-
-/**
- * 小时值处理
- * 小时被限定在0-23
- *
- * @author Looly
- */
-public class HourValueParser extends AbsValueParser {
- public HourValueParser() {
- super(0, 23);
- }
-}
diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/MinuteValueParser.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/MinuteValueParser.java
deleted file mode 100644
index c81156f7b..000000000
--- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/MinuteValueParser.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package cn.hutool.cron.pattern.parser;
-
-/**
- * 分钟值处理
- * 限定于0-59
- *
- * @author Looly
- */
-public class MinuteValueParser extends AbsValueParser {
- /**
- * 构造
- */
- public MinuteValueParser() {
- super(0, 59);
- }
-}
diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/MonthValueParser.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/MonthValueParser.java
deleted file mode 100644
index 089afed63..000000000
--- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/MonthValueParser.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package cn.hutool.cron.pattern.parser;
-
-import cn.hutool.core.date.Month;
-import cn.hutool.core.lang.Assert;
-import cn.hutool.cron.CronException;
-
-/**
- * 月份值处理
- * 限定于1-12,1表示一月,支持别名(忽略大小写),如一月是{@code jan}
- *
- * @author Looly
- */
-public class MonthValueParser extends AbsValueParser {
-
- public MonthValueParser() {
- super(1, 12);
- }
-
- @Override
- public int parse(String value) throws CronException {
- try {
- return super.parse(value);
- } catch (Exception e) {
- return parseAlias(value);
- }
- }
-
- /**
- * 解析别名
- *
- * @param monthName 别名值
- * @return 月份int值,从1开始
- * @throws CronException 无效月别名抛出此异常
- */
- private int parseAlias(String monthName) throws CronException {
- final Month month = Month.of(monthName);
- Assert.notNull(month, () -> new CronException("Invalid month alias: {}", monthName));
- return month.getValueBaseOne();
- }
-}
diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/AbsValueParser.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PartParser.java
similarity index 55%
rename from hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/AbsValueParser.java
rename to hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PartParser.java
index a436e78de..0972aab65 100644
--- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/AbsValueParser.java
+++ b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PartParser.java
@@ -1,109 +1,75 @@
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;
+import cn.hutool.cron.pattern.Part;
import cn.hutool.cron.pattern.matcher.AlwaysTrueValueMatcher;
import cn.hutool.cron.pattern.matcher.BoolArrayValueMatcher;
+import cn.hutool.cron.pattern.matcher.DayOfMonthValueMatcher;
import cn.hutool.cron.pattern.matcher.ValueMatcher;
+import cn.hutool.cron.pattern.matcher.YearValueMatcher;
import java.util.ArrayList;
import java.util.List;
/**
- * 简易值转换器。将给定String值转为int,并限定最大值和最小值
- * 此类同时识别{@code L} 为最大值。
+ * 定时任务表达式各个部分的解析器
*
- * @author Looly
+ * @author looly
+ * @since 5.8.0
*/
-public abstract class AbsValueParser implements ValueParser {
+public class PartParser {
+
+ private final Part part;
/**
- * 最小值(包括)
+ * 创建解析器
+ *
+ * @param part 对应解析的部分枚举
+ * @return 解析器
*/
- protected int min;
- /**
- * 最大值(包括)
- */
- protected int max;
+ public static PartParser of(Part part) {
+ return new PartParser(part);
+ }
/**
* 构造
- *
- * @param min 最小值(包括)
- * @param max 最大值(包括)
+ * @param part 对应解析的部分枚举
*/
- public AbsValueParser(int min, int max) {
- if (min > max) {
- this.min = max;
- this.max = min;
- } else {
- this.min = min;
- this.max = max;
- }
- }
-
- @Override
- public int parse(String value) throws CronException {
- if ("L".equalsIgnoreCase(value)) {
- // L表示最大值
- return max;
- }
-
- int i;
- try {
- i = Integer.parseInt(value);
- } catch (NumberFormatException e) {
- throw new CronException(e, "Invalid integer value: '{}'", value);
- }
- if (i < min || i > max) {
- throw new CronException("Value {} out of range: [{} , {}]", i, min, max);
- }
- return i;
- }
-
- @Override
- public int getMin() {
- return this.min;
- }
-
- @Override
- public int getMax() {
- return this.max;
+ public PartParser(Part part) {
+ this.part = part;
}
/**
- * 处理定时任务表达式每个时间字段
- * 多个时间使用逗号分隔
+ * 将表达式解析为{@link ValueMatcher}
*
- * @param value 某个时间字段
- * @return List
+ * @param value 表达式
+ * @return {@link ValueMatcher}
*/
- @Override
public ValueMatcher parseAsValueMatcher(String value) {
if (isMatchAllStr(value)) {
//兼容Quartz的"?"表达式,不会出现互斥情况,与"*"作用相同
return new AlwaysTrueValueMatcher();
}
- List values = parseArray(value);
+ final List values = parseArray(value);
if (values.size() == 0) {
- throw new CronException("Invalid field: [{}]", value);
+ throw new CronException("Invalid part value: [{}]", value);
}
- return buildValueMatcher(values);
- }
-
- /**
- * 根据解析的数字值列表构建{@link ValueMatcher}
- * 默认为{@link BoolArrayValueMatcher},如果有特殊实现,子类须重写此方法
- *
- * @param values 数字值列表
- * @return {@link ValueMatcher}
- */
- protected ValueMatcher buildValueMatcher(List values){
- return new BoolArrayValueMatcher(values);
+ switch (this.part) {
+ case DAY_OF_MONTH:
+ return new DayOfMonthValueMatcher(values);
+ case YEAR:
+ return new YearValueMatcher(values);
+ default:
+ return new BoolArrayValueMatcher(values);
+ }
}
/**
@@ -113,10 +79,11 @@ public abstract class AbsValueParser implements ValueParser {
* a 或 *
* a,b,c,d
*
+ *
* @param value 子表达式值
* @return 值列表
*/
- private List parseArray(String value){
+ private List parseArray(String value) {
final List values = new ArrayList<>();
final List parts = StrUtil.split(value, StrUtil.C_COMMA);
@@ -146,7 +113,7 @@ public abstract class AbsValueParser implements ValueParser {
if (size == 1) {// 普通形式
results = parseRange(value, -1);
} else if (size == 2) {// 间隔形式
- final int step = parse(parts.get(1));
+ final int step = parseNumber(parts.get(1));
if (step < 1) {
throw new CronException("Non positive divisor for field: [{}]", value);
}
@@ -168,7 +135,7 @@ public abstract class AbsValueParser implements ValueParser {
*
*
* @param value 范围表达式
- * @param step 步进
+ * @param step 步进
* @return List
*/
private List parseRange(String value, int step) {
@@ -177,22 +144,22 @@ public abstract class AbsValueParser implements ValueParser {
// 全部匹配形式
if (value.length() <= 2) {
//根据步进的第一个数字确定起始时间,类似于 12/3则从12(秒、分等)开始
- int minValue = getMin();
- if(false == isMatchAllStr(value)) {
- minValue = Math.max(minValue, parse(value));
- }else {
+ int minValue = part.getMin();
+ if (false == isMatchAllStr(value)) {
+ minValue = Math.max(minValue, parseNumber(value));
+ } else {
//在全匹配模式下,如果步进不存在,表示步进为1
- if(step < 1) {
+ if (step < 1) {
step = 1;
}
}
- if(step > 0) {
- final int maxValue = getMax();
- if(minValue > maxValue) {
+ if (step > 0) {
+ final int maxValue = part.getMax();
+ if (minValue > maxValue) {
throw new CronException("Invalid value {} > {}", minValue, maxValue);
}
//有步进
- for (int i = minValue; i <= maxValue; i+=step) {
+ for (int i = minValue; i <= maxValue; i += step) {
results.add(i);
}
} else {
@@ -206,26 +173,26 @@ public abstract class AbsValueParser implements ValueParser {
List parts = StrUtil.split(value, '-');
int size = parts.size();
if (size == 1) {// 普通值
- final int v1 = parse(value);
- if(step > 0) {//类似 20/2的形式
- NumberUtil.appendRange(v1, getMax(), step, results);
- }else {
+ final int v1 = parseNumber(value);
+ if (step > 0) {//类似 20/2的形式
+ NumberUtil.appendRange(v1, part.getMax(), step, results);
+ } else {
results.add(v1);
}
} else if (size == 2) {// range值
- final int v1 = parse(parts.get(0));
- final int v2 = parse(parts.get(1));
- if(step < 1) {
+ final int v1 = parseNumber(parts.get(0));
+ final int v2 = parseNumber(parts.get(1));
+ if (step < 1) {
//在range模式下,如果步进不存在,表示步进为1
step = 1;
}
if (v1 < v2) {// 正常范围,例如:2-5
NumberUtil.appendRange(v1, v2, step, results);
} else if (v1 > v2) {// 逆向范围,反选模式,例如:5-2
- NumberUtil.appendRange(v1, getMax(), step, results);
- NumberUtil.appendRange(getMin(), v2, step, results);
+ NumberUtil.appendRange(v1, part.getMax(), step, results);
+ NumberUtil.appendRange(part.getMin(), v2, step, results);
} else {// v1 == v2,此时与单值模式一致
- NumberUtil.appendRange(v1, getMax(), step, results);
+ NumberUtil.appendRange(v1, part.getMax(), step, results);
}
} else {
throw new CronException("Invalid syntax of field: [{}]", value);
@@ -244,4 +211,56 @@ public abstract class AbsValueParser implements ValueParser {
private static boolean isMatchAllStr(String value) {
return (1 == value.length()) && ("*".equals(value) || "?".equals(value));
}
+
+ /**
+ * 解析单个int值,支持别名
+ *
+ * @param value 被解析的值
+ * @return 解析结果
+ * @throws CronException 当无效数字或无效别名时抛出
+ */
+ private int parseNumber(String value) throws CronException {
+ if ("L".equalsIgnoreCase(value)) {
+ // L表示最大值
+ return part.getMax();
+ }
+
+ int i;
+ try {
+ i = Integer.parseInt(value);
+ } catch (NumberFormatException ignore) {
+ i = parseAlias(value);
+ }
+
+ // 周日可以用0或7表示,统一转换为0
+ if(this.part == Part.DAY_OF_WEEK && Week.SUNDAY.getIso8601Value() == i){
+ i = Week.SUNDAY.ordinal();
+ }
+
+ return part.checkValue(i);
+ }
+
+ /**
+ * 解析别名,只支持{@link Part#MONTH}和{@link Part#DAY_OF_WEEK}
+ *
+ * @param name 别名
+ * @return 解析int值
+ * @throws CronException 无匹配别名时抛出异常
+ */
+ private int parseAlias(String name) throws CronException {
+ switch (this.part) {
+ case MONTH:
+ final Month month = Month.of(name);
+ Assert.notNull(month, () -> new CronException("Invalid month alias: {}", name));
+ // 月份从1开始
+ return month.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();
+ }
+
+ throw new CronException("Invalid alias value: [{}]", name);
+ }
}
diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/CronPatternParser.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PatternParser.java
similarity index 64%
rename from hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/CronPatternParser.java
rename to hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PatternParser.java
index ad36b0646..fedfc094f 100644
--- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/CronPatternParser.java
+++ b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PatternParser.java
@@ -1,8 +1,9 @@
package cn.hutool.cron.pattern.parser;
-import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.CronException;
+import cn.hutool.cron.pattern.Part;
import cn.hutool.cron.pattern.matcher.AlwaysTrueValueMatcher;
import cn.hutool.cron.pattern.matcher.DateTimeMatcher;
import cn.hutool.cron.pattern.matcher.MatcherTable;
@@ -16,15 +17,15 @@ import java.util.List;
* @author looly
* @since 5.8.0
*/
-public class CronPatternParser {
+public class PatternParser {
- private static final ValueParser SECOND_VALUE_PARSER = new SecondValueParser();
- private static final ValueParser MINUTE_VALUE_PARSER = new MinuteValueParser();
- private static final ValueParser HOUR_VALUE_PARSER = new HourValueParser();
- private static final ValueParser DAY_OF_MONTH_VALUE_PARSER = new DayOfMonthValueParser();
- private static final ValueParser MONTH_VALUE_PARSER = new MonthValueParser();
- private static final ValueParser DAY_OF_WEEK_VALUE_PARSER = new DayOfWeekValueParser();
- private static final ValueParser YEAR_VALUE_PARSER = new YearValueParser();
+ private static final PartParser SECOND_VALUE_PARSER = PartParser.of(Part.SECOND);
+ private static final PartParser MINUTE_VALUE_PARSER = PartParser.of(Part.MINUTE);
+ private static final PartParser HOUR_VALUE_PARSER = PartParser.of(Part.HOUR);
+ private static final PartParser DAY_OF_MONTH_VALUE_PARSER = PartParser.of(Part.DAY_OF_MONTH);
+ private static final PartParser MONTH_VALUE_PARSER = PartParser.of(Part.MONTH);
+ private static final PartParser DAY_OF_WEEK_VALUE_PARSER = PartParser.of(Part.DAY_OF_WEEK);
+ private static final PartParser YEAR_VALUE_PARSER = PartParser.of(Part.YEAR);
/**
* 解析表达式到匹配表中
@@ -46,7 +47,7 @@ public class CronPatternParser {
* @return {@link MatcherTable}
*/
private static MatcherTable parseGroupPattern(String groupPattern) {
- final List patternList = StrUtil.split(groupPattern, '|');
+ final List patternList = StrUtil.splitTrim(groupPattern, '|');
final MatcherTable matcherTable = new MatcherTable(patternList.size());
for (String pattern : patternList) {
matcherTable.matchers.add(parseSinglePattern(pattern));
@@ -61,17 +62,18 @@ public class CronPatternParser {
* @return {@link DateTimeMatcher}
*/
private static DateTimeMatcher parseSinglePattern(String pattern) {
- final String[] parts = pattern.split("\\s");
+ final String[] parts = pattern.split("\\s+");
+ Assert.checkBetween(parts.length, 5, 7,
+ () -> new CronException("Pattern [{}] is invalid, it must be 5-7 parts!", pattern));
- int offset = 0;// 偏移量用于兼容Quartz表达式,当表达式有6或7项时,第一项为秒
+ // 偏移量用于兼容Quartz表达式,当表达式有6或7项时,第一项为秒
+ int offset = 0;
if (parts.length == 6 || parts.length == 7) {
offset = 1;
- } else if (parts.length != 5) {
- throw new CronException("Pattern [{}] is invalid, it must be 5-7 parts!", pattern);
}
- // 秒,如果不支持秒的表达式,则第一位按照表达式生成时间的秒数赋值,表示整分匹配
- final String secondPart = (1 == offset) ? parts[0] : String.valueOf(DateUtil.date().second());
+ // 秒,如果不支持秒的表达式,则第一位赋值0,表示整分匹配
+ final String secondPart = (1 == offset) ? parts[0] : "0";
// 年
ValueMatcher yearMatcher;
diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/SecondValueParser.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/SecondValueParser.java
deleted file mode 100644
index ae0839c49..000000000
--- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/SecondValueParser.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package cn.hutool.cron.pattern.parser;
-
-/**
- * 秒值处理
- * 限定于0-59
- *
- * @author Looly
- */
-public class SecondValueParser extends MinuteValueParser {
-}
diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/ValueParser.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/ValueParser.java
deleted file mode 100644
index 0cfdef46b..000000000
--- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/ValueParser.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package cn.hutool.cron.pattern.parser;
-
-import cn.hutool.cron.pattern.matcher.ValueMatcher;
-
-/**
- * 值处理接口
- * 值处理用于限定表达式中相应位置的值范围,并转换表达式值为int值
- *
- * @author Looly
- */
-public interface ValueParser {
-
- /**
- * 解析表达式对应部分为{@link ValueMatcher},支持的表达式包括:
- *
- * - 单值或通配符形式,如 a 或 *
- * - 数组形式,如 1,2,3
- * - 间隔形式,如 a/b 或 */b
- * - 范围形式,如 3-8
- *
- *
- * @param pattern 对应时间部分的表达式
- * @return {@link ValueMatcher}
- */
- ValueMatcher parseAsValueMatcher(String pattern);
-
- /**
- * 处理String值并转为int
- * 转换包括:
- *
- * - 数字字符串转为数字
- * - 别名转为对应的数字(如月份和星期)
- *
- *
- * @param value String值
- * @return int
- */
- int parse(String value);
-
- /**
- * 返回最小值
- *
- * @return 最小值
- */
- int getMin();
-
- /**
- * 返回最大值
- *
- * @return 最大值
- */
- int getMax();
-}
diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/YearValueParser.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/YearValueParser.java
deleted file mode 100644
index 169d777ec..000000000
--- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/YearValueParser.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package cn.hutool.cron.pattern.parser;
-
-import cn.hutool.cron.pattern.matcher.ValueMatcher;
-import cn.hutool.cron.pattern.matcher.YearValueMatcher;
-
-import java.util.List;
-
-/**
- * 年值处理
- * 年的限定在1970-2099年
- *
- * @author Looly
- */
-public class YearValueParser extends AbsValueParser {
-
- public YearValueParser() {
- super(1970, 2099);
- }
-
- @Override
- protected ValueMatcher buildValueMatcher(List values) {
- //考虑年数字太大,不适合boolean数组,单独使用列表遍历匹配
- return new YearValueMatcher(values);
- }
-}
diff --git a/hutool-cron/src/test/java/cn/hutool/cron/pattern/CronPatternNextMatchTest.java b/hutool-cron/src/test/java/cn/hutool/cron/pattern/CronPatternNextMatchTest.java
new file mode 100644
index 000000000..78c7f3564
--- /dev/null
+++ b/hutool-cron/src/test/java/cn/hutool/cron/pattern/CronPatternNextMatchTest.java
@@ -0,0 +1,18 @@
+package cn.hutool.cron.pattern;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.Console;
+import org.junit.Test;
+
+import java.util.Calendar;
+
+public class CronPatternNextMatchTest {
+
+ @Test
+ public void nextMatchAfterTest(){
+ CronPattern pattern = new CronPattern("23 12 * 12 * * *");
+ final Calendar calendar = pattern.nextMatchAfter(
+ DateUtil.parse("2022-04-12 09:12:23").toCalendar());
+ Console.log(DateUtil.date(calendar));
+ }
+}
diff --git a/hutool-cron/src/test/java/cn/hutool/cron/pattern/CronPatternTest.java b/hutool-cron/src/test/java/cn/hutool/cron/pattern/CronPatternTest.java
index bd77a8e2b..b2367b74b 100644
--- a/hutool-cron/src/test/java/cn/hutool/cron/pattern/CronPatternTest.java
+++ b/hutool-cron/src/test/java/cn/hutool/cron/pattern/CronPatternTest.java
@@ -10,7 +10,6 @@ import org.junit.Test;
* 定时任务单元测试类
*
* @author Looly
- *
*/
public class CronPatternTest {
@@ -31,7 +30,7 @@ public class CronPatternTest {
CronPattern pattern;
// 任何时间匹配
pattern = new CronPattern("* * * * *");
- for(int i = 0; i < 1; i++) {
+ for (int i = 0; i < 1; i++) {
Assert.assertTrue(pattern.match(DateUtil.current(), false));
}
}
@@ -83,12 +82,23 @@ public class CronPatternTest {
pattern = new CronPattern("39 0 0 7 aug *");
assertMatch(pattern, "2016-08-07 00:00:39");
+ }
+ @Test
+ public void matchDayOfWeekTest() {
// 星期四
- pattern = new CronPattern("39 0 0 * * Thu");
- assertMatch(pattern, "2017-02-09 00:00:39");
+ CronPattern pattern = CronPattern.of("39 0 0 * * Thu");
assertMatch(pattern, "2017-02-09 00:00:39");
+ // 星期日的三种形式
+ pattern = CronPattern.of("39 0 0 * * Sun");
+ assertMatch(pattern, "2022-03-27 00:00:39");
+
+ pattern = CronPattern.of("39 0 0 * * 0");
+ assertMatch(pattern, "2022-03-27 00:00:39");
+
+ pattern = CronPattern.of("39 0 0 * * 7");
+ assertMatch(pattern, "2022-03-27 00:00:39");
}
@SuppressWarnings("ConstantConditions")
@@ -153,11 +163,11 @@ public class CronPatternTest {
* 表达式是否匹配日期
*
* @param pattern 表达式
- * @param date 日期,标准日期时间字符串
+ * @param date 日期,标准日期时间字符串
*/
@SuppressWarnings("ConstantConditions")
private void assertMatch(CronPattern pattern, String date) {
- Assert.assertTrue(pattern.match(DateUtil.parse(date).getTime(), false));
- Assert.assertTrue(pattern.match(DateUtil.parse(date).getTime(), true));
+ Assert.assertTrue(pattern.match(DateUtil.parse(date).toCalendar(), false));
+ Assert.assertTrue(pattern.match(DateUtil.parse(date).toCalendar(), true));
}
}