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 } // ----------------------------------------------------------------------- + /** * 相等需同时满足如下条件: *
    *
  1. 非空
  2. - *
  3. 类型为 {@link MutableLong}
  4. + *
  5. 类型为 MutableLong
  6. *
  7. 值相等
  8. *
* * @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
    - * 转换包括: - *
      - *
    1. 数字字符串转为数字
    2. - *
    3. 别名转为对应的数字(如月份和星期)
    4. - *
    - * - * @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)); } }