Projektdateien hinzufügen.
This commit is contained in:
131
FileinterfaceCronScheduler/Scheduler/CronExpression.cs
Normal file
131
FileinterfaceCronScheduler/Scheduler/CronExpression.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
namespace FileInterface.Scheduler
|
||||
{
|
||||
/// <summary>
|
||||
/// Standard 5-field cron expression: minute hour day-of-month month day-of-week.
|
||||
/// Supported: *, */n, a,b,c, a-b, a-b/n. Day-of-week: 0 or 7 = Sunday.
|
||||
/// </summary>
|
||||
public sealed class CronExpression
|
||||
{
|
||||
private readonly HashSet<int> _minutes;
|
||||
private readonly HashSet<int> _hours;
|
||||
private readonly HashSet<int> _days;
|
||||
private readonly HashSet<int> _months;
|
||||
private readonly HashSet<int> _daysOfWeek;
|
||||
|
||||
public string Expression { get; private set; }
|
||||
|
||||
private CronExpression(string expression,
|
||||
HashSet<int> minutes,
|
||||
HashSet<int> hours,
|
||||
HashSet<int> days,
|
||||
HashSet<int> months,
|
||||
HashSet<int> daysOfWeek)
|
||||
{
|
||||
Expression = expression;
|
||||
_minutes = minutes;
|
||||
_hours = hours;
|
||||
_days = days;
|
||||
_months = months;
|
||||
_daysOfWeek = daysOfWeek;
|
||||
}
|
||||
|
||||
public static CronExpression Parse(string expression)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(expression))
|
||||
throw new FormatException("Cron expression is empty.");
|
||||
|
||||
string[] parts = expression.Trim().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length != 5)
|
||||
throw new FormatException("Cron must contain exactly 5 fields: minute hour day month day-of-week.");
|
||||
|
||||
return new CronExpression(
|
||||
expression.Trim(),
|
||||
ParseField(parts[0], 0, 59, false),
|
||||
ParseField(parts[1], 0, 23, false),
|
||||
ParseField(parts[2], 1, 31, false),
|
||||
ParseField(parts[3], 1, 12, false),
|
||||
ParseField(parts[4], 0, 7, true));
|
||||
}
|
||||
|
||||
public bool IsMatch(DateTime localTime)
|
||||
{
|
||||
int dow = (int)localTime.DayOfWeek;
|
||||
return _minutes.Contains(localTime.Minute)
|
||||
&& _hours.Contains(localTime.Hour)
|
||||
&& _days.Contains(localTime.Day)
|
||||
&& _months.Contains(localTime.Month)
|
||||
&& _daysOfWeek.Contains(dow);
|
||||
}
|
||||
|
||||
private static HashSet<int> ParseField(string text, int min, int max, bool normalizeSunday)
|
||||
{
|
||||
var result = new HashSet<int>();
|
||||
string[] segments = text.Split(',');
|
||||
foreach (string rawSegment in segments)
|
||||
{
|
||||
string segment = rawSegment.Trim();
|
||||
if (segment.Length == 0)
|
||||
throw new FormatException("Empty cron field segment.");
|
||||
|
||||
int step = 1;
|
||||
string rangePart = segment;
|
||||
int slash = segment.IndexOf('/');
|
||||
if (slash >= 0)
|
||||
{
|
||||
rangePart = segment.Substring(0, slash);
|
||||
string stepText = segment.Substring(slash + 1);
|
||||
if (!Int32.TryParse(stepText, NumberStyles.Integer, CultureInfo.InvariantCulture, out step) || step <= 0)
|
||||
throw new FormatException("Invalid cron step: " + segment);
|
||||
}
|
||||
|
||||
int start;
|
||||
int end;
|
||||
if (rangePart == "*")
|
||||
{
|
||||
start = min;
|
||||
end = max;
|
||||
}
|
||||
else
|
||||
{
|
||||
int dash = rangePart.IndexOf('-');
|
||||
if (dash >= 0)
|
||||
{
|
||||
start = ParseNumber(rangePart.Substring(0, dash), min, max);
|
||||
end = ParseNumber(rangePart.Substring(dash + 1), min, max);
|
||||
if (start > end)
|
||||
throw new FormatException("Cron range start is greater than end: " + segment);
|
||||
}
|
||||
else
|
||||
{
|
||||
start = ParseNumber(rangePart, min, max);
|
||||
end = start;
|
||||
}
|
||||
}
|
||||
|
||||
for (int value = start; value <= end; value += step)
|
||||
{
|
||||
int normalized = normalizeSunday && value == 7 ? 0 : value;
|
||||
result.Add(normalized);
|
||||
}
|
||||
}
|
||||
|
||||
if (result.Count == 0)
|
||||
throw new FormatException("Cron field produced no values: " + text);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int ParseNumber(string text, int min, int max)
|
||||
{
|
||||
int value;
|
||||
if (!Int32.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
|
||||
throw new FormatException("Invalid cron number: " + text);
|
||||
if (value < min || value > max)
|
||||
throw new FormatException("Cron value out of range: " + value + " (allowed " + min + "-" + max + ")");
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user