From f3096745e35e69786c12ed452d1bd04154738929 Mon Sep 17 00:00:00 2001 From: Falcon <12919280+falconfly@user.noreply.gitee.com> Date: Mon, 24 Feb 2025 16:22:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86=E6=97=A5=E5=88=A4=E6=96=AD=E5=92=8C?= =?UTF-8?q?=E6=98=9F=E6=9C=9F=E5=88=A4=E6=96=AD=E5=88=86=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TimedBackgroundTask/CronExpression.cs | 76 ++++++++++++++----- .../TimedBackgroundTask/CronOptions.cs | 13 ++++ .../TimedBackgroundTask/CronResult.cs | 24 ++---- 3 files changed, 76 insertions(+), 37 deletions(-) create mode 100644 Falcon.SugarApi/TimedBackgroundTask/CronOptions.cs diff --git a/Falcon.SugarApi/TimedBackgroundTask/CronExpression.cs b/Falcon.SugarApi/TimedBackgroundTask/CronExpression.cs index 4fb90ff..5da7ddd 100644 --- a/Falcon.SugarApi/TimedBackgroundTask/CronExpression.cs +++ b/Falcon.SugarApi/TimedBackgroundTask/CronExpression.cs @@ -13,31 +13,36 @@ namespace Falcon.SugarApi.TimedBackgroundTask /// /// 可选的秒范围枚举 /// - private List Seconds { get; } + public List Seconds { get; } /// /// 可选的分范围枚举 /// - private List Minutes { get; } + public List Minutes { get; } /// /// 可选的时范围枚举 /// - private List Hours { get; } + public List Hours { get; } /// /// 可选的天范围枚举 /// - private List DaysOfMonth { get; } + public List DaysOfMonth { get; } /// /// 可选的月范围枚举 /// - private List Months { get; } + public List Months { get; } /// /// 可选的星期范围枚举 /// - private List DaysOfWeek { get; } + public List DaysOfWeek { get; } /// /// 可选的年范围枚举 /// - private List Years { get; set; } + public List Years { get; set; } + + /// + /// 解析配置 + /// + public CronOptions Options { get; set; } = new CronOptions(); /// /// 通过提供cron表达式构造对象 @@ -59,13 +64,35 @@ namespace Falcon.SugarApi.TimedBackgroundTask var fields = cronExpression.Split(new[] { ' ' },StringSplitOptions.RemoveEmptyEntries); Seconds = fields.Length > 0 ? GetRange(fields[0],0,59) : Enumerable.Range(0,60).ToList(); + if(Seconds.Count == 0) { + throw new ArgumentOutOfRangeException(nameof(CronExpression),"表达式没有任何可以匹配的秒,无法触发!"); + } Minutes = fields.Length > 1 ? GetRange(fields[1],0,59) : Enumerable.Range(0,60).ToList(); + if(Minutes.Count == 0) { + throw new ArgumentOutOfRangeException(nameof(CronExpression),"表达式没有任何可以匹配的分,无法触发!"); + } Hours = fields.Length > 2 ? GetRange(fields[2],0,23) : Enumerable.Range(0,24).ToList(); + if(Hours.Count == 0) { + throw new ArgumentOutOfRangeException(nameof(CronExpression),"表达式没有任何可以匹配的时,无法触发!"); + } DaysOfMonth = fields.Length > 3 ? GetRange(fields[3],1,31) : Enumerable.Range(1,31).ToList(); + if(DaysOfMonth.Count == 0) { + throw new ArgumentOutOfRangeException(nameof(CronExpression),"表达式没有任何可以匹配的日,无法触发!"); + } Months = fields.Length > 4 ? GetRange(fields[4],1,12) : Enumerable.Range(1,12).ToList(); + if(Months.Count == 0) { + throw new ArgumentOutOfRangeException(nameof(CronExpression),"表达式没有任何可以匹配的月份,无法触发!"); + } DaysOfWeek = fields.Length > 5 ? GetRange(fields[5],0,6) : Enumerable.Range(0,7).ToList(); + if(DaysOfWeek.Count == 0) { + throw new ArgumentOutOfRangeException(nameof(CronExpression),"表达式没有任何可以匹配的星期几,无法触发!"); + } var nowYear = DateTime.Now.Year; - Years = fields.Length > 6 ? GetRange(fields[6],nowYear,nowYear + 2) : Enumerable.Range(nowYear,2).ToList(); + var endYear = Options.MaxYear; + Years = fields.Length > 6 ? GetRange(fields[6],nowYear,endYear) : Enumerable.Range(nowYear,2).ToList(); + if(Years.Count == 0) { + throw new ArgumentOutOfRangeException(nameof(CronExpression),"表达式没有任何可以匹配的年份,无法触发!"); + } } /// @@ -91,15 +118,21 @@ namespace Falcon.SugarApi.TimedBackgroundTask continue; } } + if(!ct.IsDayOfWeekAdjust) { + AdjustDayOfWeek(ct); + if(!ct.IsYearAdjust || !ct.IsMonthAdjust || !ct.IsDayAdjust || !ct.IsDayOfWeekAdjust) { + continue; + } + } if(!ct.IsHourAdjust) { AdjustHour(ct); - if(!ct.IsYearAdjust || !ct.IsMonthAdjust || !ct.IsDayAdjust) { + if(!ct.IsYearAdjust || !ct.IsMonthAdjust || !ct.IsDayAdjust || !ct.IsDayOfWeekAdjust) { continue; } } if(!ct.IsMinuteAdjust) { AdjustMinute(ct); - if(!ct.IsYearAdjust || !ct.IsMonthAdjust || !ct.IsDayAdjust || !ct.IsHourAdjust) { + if(!ct.IsYearAdjust || !ct.IsMonthAdjust || !ct.IsDayAdjust || !ct.IsDayOfWeekAdjust || !ct.IsHourAdjust) { continue; } } @@ -145,19 +178,29 @@ namespace Falcon.SugarApi.TimedBackgroundTask int month = dt.Month; int day = dt.Day; int maxDayInMonth = DateTime.DaysInMonth(year,month); - var next = DaysOfMonth.Where(a => a >= day && a <= maxDayInMonth && DaysOfWeek.Contains((int)dt.DayOfWeek)); + + var next = DaysOfMonth.Where(a => a >= day && a <= maxDayInMonth); if(next.Any()) { date.SetAdjustTime(dt.AddDays(next.First() - day),TimePartEnum.YearDay); date.IsDayAdjust = true; return; } - if(!DaysOfWeek.Contains((int)dt.DayOfWeek)) { - date.SetAdjustTime(dt.AddDays(1),TimePartEnum.YearDay); - return; - } date.SetAdjustTime(dt.AddMonths(1),TimePartEnum.YearMonth); } + private void AdjustDayOfWeek(CronResult date) { + var dw = (int)date.AdjustTime.DayOfWeek; + var next = DaysOfWeek.Where(a => a >= dw); + if(next.Any()) { + date.SetAdjustTime(date.AdjustTime.AddDays(next.First() - dw),TimePartEnum.YearDay); + date.IsDayOfWeekAdjust = true; + } + else { + date.SetAdjustTime(date.AdjustTime.AddDays(7 - dw + DaysOfWeek.First()),TimePartEnum.YearDay); + date.IsDayOfWeekAdjust = true; + } + } + private void AdjustHour(CronResult date) { var next = Hours.Where(m => m >= date.AdjustTime.Hour); if(next.Any()) { @@ -195,9 +238,6 @@ namespace Falcon.SugarApi.TimedBackgroundTask 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(); if(exp == "*") { return Enumerable.Range(min,max - min + 1).ToList(); diff --git a/Falcon.SugarApi/TimedBackgroundTask/CronOptions.cs b/Falcon.SugarApi/TimedBackgroundTask/CronOptions.cs new file mode 100644 index 0000000..0eb45a4 --- /dev/null +++ b/Falcon.SugarApi/TimedBackgroundTask/CronOptions.cs @@ -0,0 +1,13 @@ +namespace Falcon.SugarApi.TimedBackgroundTask +{ + /// + /// Cron表达式解析选项 + /// + public class CronOptions + { + /// + /// 最大支持的年份 + /// + public int MaxYear { get; set; } = 2099; + } +} diff --git a/Falcon.SugarApi/TimedBackgroundTask/CronResult.cs b/Falcon.SugarApi/TimedBackgroundTask/CronResult.cs index ba71209..d389ba8 100644 --- a/Falcon.SugarApi/TimedBackgroundTask/CronResult.cs +++ b/Falcon.SugarApi/TimedBackgroundTask/CronResult.cs @@ -8,12 +8,13 @@ namespace Falcon.SugarApi.TimedBackgroundTask public bool IsYearAdjust { get; set; } = false; public bool IsMonthAdjust { get; set; } = false; public bool IsDayAdjust { get; set; } = false; + public bool IsDayOfWeekAdjust { get; set; } = false; public bool IsHourAdjust { get; set; } = false; public bool IsMinuteAdjust { get; set; } = false; public bool IsSecondAdjust { get; set; } = false; public bool IsAllAdjust - => (IsYearAdjust && IsMonthAdjust && IsDayAdjust + => (IsYearAdjust && IsMonthAdjust && IsDayAdjust && IsDayOfWeekAdjust && IsHourAdjust && IsMinuteAdjust && IsSecondAdjust) || IsNullVal; /// @@ -32,14 +33,12 @@ namespace Falcon.SugarApi.TimedBackgroundTask IsYearAdjust = false; IsMonthAdjust = false; IsDayAdjust = false; + IsDayOfWeekAdjust = false; IsHourAdjust = false; IsMinuteAdjust = false; IsSecondAdjust = false; return; } - //else { - // IsYearAdjust = true; - //} if(!part.HasFlag(TimePartEnum.Month)) { return; } @@ -47,28 +46,24 @@ namespace Falcon.SugarApi.TimedBackgroundTask this.AdjustTime = new DateTime(dt.Year,dt.Month,1,0,0,0); IsMonthAdjust = false; IsDayAdjust = false; + IsDayOfWeekAdjust = false; IsHourAdjust = false; IsMinuteAdjust = false; IsSecondAdjust = false; return; } - //else { - // IsMonthAdjust = true; - //} if(!part.HasFlag(TimePartEnum.Day)) { return; } if(dt.Day != this.AdjustTime.Day) { this.AdjustTime = new DateTime(dt.Year,dt.Month,dt.Day,0,0,0); IsDayAdjust = false; + IsDayOfWeekAdjust = false; IsHourAdjust = false; IsMinuteAdjust = false; IsSecondAdjust = false; return; } - //else { - // IsDayAdjust = true; - //} if(!part.HasFlag(TimePartEnum.Hour)) { return; } @@ -79,9 +74,6 @@ namespace Falcon.SugarApi.TimedBackgroundTask IsSecondAdjust = false; return; } - //else { - // IsHourAdjust = true; - //} if(!part.HasFlag(TimePartEnum.Minute)) { return; } @@ -91,9 +83,6 @@ namespace Falcon.SugarApi.TimedBackgroundTask IsSecondAdjust = false; return; } - //else { - // IsMinuteAdjust = true; - //} if(!part.HasFlag(TimePartEnum.Second)) { return; } @@ -102,9 +91,6 @@ namespace Falcon.SugarApi.TimedBackgroundTask IsSecondAdjust = false; return; } - //else { - // IsSecondAdjust = true; - //} } }