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;
- //}
}
}