From 6e68a8ad8c6d1229bfc3180c2f7d4bb52ea909cd Mon Sep 17 00:00:00 2001
From: Falcon <12919280+falconfly@user.noreply.gitee.com>
Date: Thu, 20 Feb 2025 16:33:11 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3cron=E8=A7=A3=E6=9E=90?=
 =?UTF-8?q?=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../TimedBackgroundTask/CronExpression.cs       | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/Falcon.SugarApi/TimedBackgroundTask/CronExpression.cs b/Falcon.SugarApi/TimedBackgroundTask/CronExpression.cs
index b60680b..85033a9 100644
--- a/Falcon.SugarApi/TimedBackgroundTask/CronExpression.cs
+++ b/Falcon.SugarApi/TimedBackgroundTask/CronExpression.cs
@@ -48,7 +48,9 @@ public class CronExpression
     /// <para>取值可以用,分割,表示取值枚举,比如0 10,20,30 5 表示匹配每天早上5点10分、5点20分和5点30分。</para>
     /// <para>表达式右侧的*可以省略。比如0 15 4表示每天上午4点15分,和0 15 4 * * * *相同</para>
     /// <para>星期取值范围0-6,0表示星期天,1表示星期一,以此类推。</para>
-    /// <para>日取值范围1-31,不用考虑大月小月和二月的特殊情况,方法会自动过滤这些特殊日期</para>
+    /// <para>日取值范围1-31,不用考虑大月小月和二月的特殊情况,方法会自动处理这些特殊日期</para>
+    /// <para>关于日期和星期匹配问题。一般的cron标准中日期和星期只要满足一个即可匹配,但本方法不同,我认为既然其他所有部分(比如分和秒)都是必须同时满足,那么日期和星期也是必须同时满足。</para>
+    /// <para>目前方法不支持*-/,分隔符的混合使用,等待后续改进</para>
     /// </summary>
     /// <param name="cronExpression">cron表达式</param>
     /// <exception cref="ArgumentException"></exception>
@@ -57,7 +59,7 @@ public class CronExpression
 
         Seconds = fields.Length > 0 ? GetRange(fields[0],0,59) : Enumerable.Range(0,60).ToList();
         Minutes = fields.Length > 1 ? GetRange(fields[1],0,59) : Enumerable.Range(0,60).ToList();
-        Hours = fields.Length > 2 ? GetRange(fields[2],0,23) : Enumerable.Range(0,23).ToList();
+        Hours = fields.Length > 2 ? GetRange(fields[2],0,23) : Enumerable.Range(0,24).ToList();
         DaysOfMonth = fields.Length > 3 ? GetRange(fields[3],1,31) : Enumerable.Range(1,31).ToList();
         Months = fields.Length > 4 ? GetRange(fields[4],1,12) : Enumerable.Range(1,12).ToList();
         DaysOfWeek = fields.Length > 5 ? GetRange(fields[5],0,6) : Enumerable.Range(0,7).ToList();
@@ -187,9 +189,14 @@ public class CronExpression
 
     private static List<int> GetRange(string exp,int min,int max) {
         var charList = "0123456789*-/,".ToArray();
-        if(exp.ToCharArray().Any(a => a.NotIn(charList))) {
-            throw new ArgumentOutOfRangeException(nameof(exp));
+        var expChars = exp.ToCharArray().Distinct();
+        var outRangeChars = expChars.Where(a => a.NotIn(charList)).ToArray();
+        if(outRangeChars.Any()) {
+            throw new ArgumentOutOfRangeException(nameof(exp),$"非法字符{new string(outRangeChars)} 在表达式 {exp} 中");
         }
+        //if(exp.ToCharArray().Any(a => a.NotIn(charList))) {
+        //    throw new ArgumentOutOfRangeException(nameof(exp));
+        //}
         var list = new List<int>();
         if(exp == "*") {
             return Enumerable.Range(min,max - min + 1).ToList();
@@ -213,7 +220,7 @@ public class CronExpression
             var g = exp.Split('/',StringSplitOptions.RemoveEmptyEntries);
             var f = Math.Max(min,int.Parse(g[0]));
             var s = int.Parse(g[1]);
-            while(f < max) {
+            while(f <= max) {
                 list.Add(f);
                 f += s;
             }