diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/annotation/AnnotationUtil.java b/hutool-core/src/main/java/cn/hutool/v7/core/annotation/AnnotationUtil.java
index 4fe4ef63c..5d87a91fb 100644
--- a/hutool-core/src/main/java/cn/hutool/v7/core/annotation/AnnotationUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/v7/core/annotation/AnnotationUtil.java
@@ -97,7 +97,12 @@ public class AnnotationUtil {
// region ----- getAnnotation
/**
- * 获取直接声明的注解,若已有缓存则从缓存中获取
+ * 获取直接声明的注解,若已有缓存则从缓存中获取,主要为:
+ *
+ * - 只返回直接声明在该元素上的注解
+ * - 不包括从父类或接口继承来的注解
+ * - 只获取当前类/方法/字段等自身定义的注解
+ *
*
* @param element {@link AnnotatedElement}
* @return 注解
@@ -108,7 +113,12 @@ public class AnnotationUtil {
}
/**
- * 获取指定注解
+ * 获取指定注解,主要为:
+ *
+ * - 返回该元素上的所有注解
+ * - 包括从父类或接口继承来的注解
+ * - 获取当前元素以及继承自父类或接口的所有注解
+ *
*
* @param annotationEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission
* @param isToCombination 是否为转换为组合注解,组合注解可以递归获取注解的注解
diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/annotation/elements/HierarchicalAnnotatedElements.java b/hutool-core/src/main/java/cn/hutool/v7/core/annotation/elements/HierarchicalAnnotatedElements.java
index 29992ae95..ef8755118 100644
--- a/hutool-core/src/main/java/cn/hutool/v7/core/annotation/elements/HierarchicalAnnotatedElements.java
+++ b/hutool-core/src/main/java/cn/hutool/v7/core/annotation/elements/HierarchicalAnnotatedElements.java
@@ -342,8 +342,7 @@ public class HierarchicalAnnotatedElements implements AnnotatedElement, Iterable
scanHierarchy(mappings, (Class>)source, false, source);
}
// 原始元素是方法
- else if (source instanceof Method) {
- final Method methodSource = (Method)source;
+ else if (source instanceof final Method methodSource) {
// 静态、私有与被final关键字修饰方法无法被子类重写,因此不可能具有层级结构
if (Modifier.isPrivate(methodSource.getModifiers())
|| Modifier.isFinal(methodSource.getModifiers())
diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/date/Month.java b/hutool-core/src/main/java/cn/hutool/v7/core/date/Month.java
index 64e2c9251..28f494a3e 100644
--- a/hutool-core/src/main/java/cn/hutool/v7/core/date/Month.java
+++ b/hutool-core/src/main/java/cn/hutool/v7/core/date/Month.java
@@ -276,14 +276,14 @@ public enum Month {
/**
* 获得指定月的最后一天
*
- * @param month 月份,从0开始
+ * @param monthBase0 月份,从0开始
* @param isLeapYear 是否为闰年,闰年只对二月有影响
* @return 最后一天,可能为28,29,30,31
* @since 5.4.7
*/
- public static int getLastDay(final int month, final boolean isLeapYear) {
- final Month of = of(month);
- Assert.notNull(of, "Invalid Month base 0: " + month);
+ public static int getLastDay(final int monthBase0, final boolean isLeapYear) {
+ final Month of = of(monthBase0);
+ Assert.notNull(of, "Invalid Month base 0: " + monthBase0);
return of.getLastDay(isLeapYear);
}
diff --git a/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/CronPattern.java b/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/CronPattern.java
index 4a2b07721..484618813 100644
--- a/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/CronPattern.java
+++ b/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/CronPattern.java
@@ -18,6 +18,7 @@ package cn.hutool.v7.cron.pattern;
import cn.hutool.v7.core.comparator.CompareUtil;
import cn.hutool.v7.core.date.CalendarUtil;
+import cn.hutool.v7.core.lang.Console;
import cn.hutool.v7.cron.pattern.matcher.PatternMatcher;
import cn.hutool.v7.cron.pattern.parser.PatternParser;
diff --git a/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/matcher/DayOfMonthMatcher.java b/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/matcher/DayOfMonthMatcher.java
index 77f826860..6a0b33fab 100644
--- a/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/matcher/DayOfMonthMatcher.java
+++ b/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/matcher/DayOfMonthMatcher.java
@@ -40,7 +40,7 @@ public class DayOfMonthMatcher extends BoolArrayMatcher {
/**
* 给定的日期是否匹配当前匹配器
*
- * @param value 被检查的值,此处为日
+ * @param value 被检查的值,此处为日,从1开始
* @param month 实际的月份,从1开始
* @param isLeapYear 是否闰年
* @return 是否匹配
diff --git a/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/matcher/PatternMatcher.java b/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/matcher/PatternMatcher.java
index 32f4de559..e4e84f977 100644
--- a/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/matcher/PatternMatcher.java
+++ b/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/matcher/PatternMatcher.java
@@ -17,10 +17,10 @@
package cn.hutool.v7.cron.pattern.matcher;
import cn.hutool.v7.core.date.DateUtil;
+import cn.hutool.v7.core.text.StrUtil;
import cn.hutool.v7.cron.pattern.Part;
import java.time.Year;
-import java.util.Arrays;
import java.util.Calendar;
import java.util.TimeZone;
@@ -177,9 +177,15 @@ public class PatternMatcher {
@Override
public String toString() {
- return "PatternMatcher{" +
- "matchers=" + Arrays.toString(matchers) +
- '}';
+ return StrUtil.format("""
+ SECOND : {}
+ MINUTE : {}
+ HOUR : {}
+ DAY_OF_MONTH: {}
+ MONTH : {}
+ DAY_OF_WEEK : {}
+ YEAR : {}
+ """, (Object[]) this.matchers);
}
/**
diff --git a/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/matcher/YearValueMatcher.java b/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/matcher/YearValueMatcher.java
index fdb30b7fe..6ea11c5aa 100644
--- a/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/matcher/YearValueMatcher.java
+++ b/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/matcher/YearValueMatcher.java
@@ -29,6 +29,11 @@ public class YearValueMatcher implements PartMatcher {
private final LinkedHashSet valueList;
+ /**
+ * 构造
+ *
+ * @param intValueList 年数字列表
+ */
public YearValueMatcher(final Collection intValueList) {
this.valueList = new LinkedHashSet<>(intValueList);
}
@@ -49,4 +54,11 @@ public class YearValueMatcher implements PartMatcher {
// 年无效,此表达式整体无效
return -1;
}
+
+ @Override
+ public String toString() {
+ return "YearValueMatcher{" +
+ "valueList=" + valueList +
+ '}';
+ }
}
diff --git a/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/parser/PartParser.java b/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/parser/PartParser.java
index 3f2ab04c3..bd7400058 100644
--- a/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/parser/PartParser.java
+++ b/hutool-cron/src/main/java/cn/hutool/v7/cron/pattern/parser/PartParser.java
@@ -91,14 +91,11 @@ public class PartParser {
throw new CronException("Invalid part value: [{}]", value);
}
- switch (this.part) {
- case DAY_OF_MONTH:
- return new DayOfMonthMatcher(values);
- case YEAR:
- return new YearValueMatcher(values);
- default:
- return new BoolArrayMatcher(values);
- }
+ return switch (this.part) {
+ case DAY_OF_MONTH -> new DayOfMonthMatcher(values);
+ case YEAR -> new YearValueMatcher(values);
+ default -> new BoolArrayMatcher(values);
+ };
}
/**
@@ -163,6 +160,7 @@ public class PartParser {
* 8-3
* 3-3
*
+ * 其中"*"解析时按照min值处理
*
* @param value 范围表达式
* @param step 步进
@@ -287,15 +285,15 @@ public class PartParser {
return part.getMax();
}
- switch (this.part) {
- case MONTH:
+ return switch (this.part) {
+ case MONTH ->
// 月份从1开始
- return Month.of(name).getValueBaseOne();
- case DAY_OF_WEEK:
+ Month.of(name).getValueBaseOne();
+ case DAY_OF_WEEK ->
// 周从0开始,0表示周日
- return Week.of(name).ordinal();
- }
+ Week.of(name).ordinal();
+ default -> throw new CronException("Invalid alias value: [{}]", name);
+ };
- throw new CronException("Invalid alias value: [{}]", name);
}
}
diff --git a/hutool-cron/src/test/java/cn/hutool/v7/cron/pattern/CronPatternUtilTest.java b/hutool-cron/src/test/java/cn/hutool/v7/cron/pattern/CronPatternUtilTest.java
index 0736d1fb3..b5b7594df 100644
--- a/hutool-cron/src/test/java/cn/hutool/v7/cron/pattern/CronPatternUtilTest.java
+++ b/hutool-cron/src/test/java/cn/hutool/v7/cron/pattern/CronPatternUtilTest.java
@@ -16,6 +16,7 @@
package cn.hutool.v7.cron.pattern;
+import cn.hutool.v7.core.date.DateTime;
import cn.hutool.v7.core.date.DateUtil;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -60,4 +61,28 @@ public class CronPatternUtilTest {
Assertions.assertEquals("2018-10-31 03:00:00", matchedDates.get(3).toString());
Assertions.assertEquals("2018-10-31 04:00:00", matchedDates.get(4).toString());
}
+
+ @Test
+ public void issue4056Test() {
+ // "*/5"和"1/5"意义相同,从1号开始,每5天一个匹配,则匹配的天为:
+ // 2025-02-01, 2025-02-06, 2025-02-11, 2025-02-16, 2025-02-21, 2025-02-26
+ // 2025-02-28不应该在匹配之列
+ final String cron = "0 0 0 */5 * ? *";
+ final CronPattern cronPattern = new CronPattern(cron);
+ final boolean match = cronPattern.match(DateUtil.parse("2025-02-28 00:00:00").toCalendar(), true);
+ Assertions.assertFalse( match);
+ }
+
+ @Test
+ public void issue4056Test2() {
+ final String cron = "0 0 0 */5 * ? *";
+ final CronPattern cronPattern = new CronPattern(cron);
+
+ final DateTime judgeTime = DateUtil.parse("2025-02-27 23:59:59");
+ final Date nextDate = CronPatternUtil.nextDateAfter(cronPattern, judgeTime);
+ // "*/5"和"1/5"意义相同,从1号开始,每5天一个匹配,则匹配的天为:
+ // 2025-02-01, 2025-02-06, 2025-02-11, 2025-02-16, 2025-02-21, 2025-02-26
+ // 下一个匹配日期应为2025-03-01
+ Assertions.assertEquals("2025-03-01 00:00:00", nextDate.toString());
+ }
}