mirror of
https://gitee.com/dotnetchina/TimeCrontab.git
synced 2025-12-06 10:18:58 +08:00
😊 新增 CRON 的 秒分时 字段域支持 R 字符
This commit is contained in:
30
README.md
30
README.md
@@ -198,6 +198,14 @@ var crontab = Crontab.YearlyAt("MAR", "MAY", "JUN");
|
||||
var crontab = Crontab.YearlyAt(3, "MAY", 6);
|
||||
```
|
||||
|
||||
**支持 `R` 随机时刻**
|
||||
|
||||
`R` 是一个特殊的 `CRON` 表达式字符,允许您指定随机生成的时刻。例如,`R 0 0 * * ? *` 表示在每天 `00:00` 的随机秒数 (`0-59`) 时刻引发触发器。
|
||||
|
||||
```cs
|
||||
var crontab = Crontab.Parse("R 0 0 * * ? *", CronStringFormat.WithSecondsAndYears);
|
||||
```
|
||||
|
||||
[更多文档](https://furion.baiqian.ltd/docs/cron)
|
||||
|
||||
## 文档
|
||||
@@ -209,6 +217,12 @@ var crontab = Crontab.YearlyAt(3, "MAY", 6);
|
||||
```cs
|
||||
public class TimeCrontabUnitTests
|
||||
{
|
||||
private readonly ITestOutputHelper _testOutput;
|
||||
public TimeCrontabUnitTests(ITestOutputHelper testOutput)
|
||||
{
|
||||
_testOutput = testOutput;
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("* * * * *", "* * * * *", CronStringFormat.Default)]
|
||||
[InlineData("0 0 31W * *", "0 0 31W * *", CronStringFormat.Default)]
|
||||
@@ -224,6 +238,7 @@ public class TimeCrontabUnitTests
|
||||
[InlineData("0 */5 * * * *", "0 */5 * * * *", CronStringFormat.WithSeconds)]
|
||||
[InlineData("0 0/1 * * * ?", "0 */1 * * * ?", CronStringFormat.WithSeconds)]
|
||||
[InlineData("5-10 30-35 10-12 * * *", "5-10 30-35 10-12 * * *", CronStringFormat.WithSeconds)]
|
||||
[InlineData("20/10 * * * * ?", "20/10 * * * * ?", CronStringFormat.WithSeconds)]
|
||||
public void TestParse(string expression, string outputString, CronStringFormat format)
|
||||
{
|
||||
var output = Crontab.Parse(expression, format).ToString();
|
||||
@@ -245,6 +260,8 @@ public class TimeCrontabUnitTests
|
||||
[InlineData("0 */5 * * * *", "2022-01-01 00:05:00", CronStringFormat.WithSeconds)]
|
||||
[InlineData("0 0/1 * * * ?", "2022-01-01 00:01:00", CronStringFormat.WithSeconds)]
|
||||
[InlineData("5-10 30-35 10-12 * * *", "2022-01-01 10:30:05", CronStringFormat.WithSeconds)]
|
||||
[InlineData("20/10 * * * * ?", "2022-01-01 00:00:20", CronStringFormat.WithSeconds)]
|
||||
[InlineData("20/30 * * * * ?", "2022-01-01 00:00:20", CronStringFormat.WithSeconds)]
|
||||
public void TestGetNextOccurence(string expression, string nextOccurenceString, CronStringFormat format)
|
||||
{
|
||||
var beginTime = new DateTime(2022, 1, 1, 0, 0, 0);
|
||||
@@ -252,6 +269,19 @@ public class TimeCrontabUnitTests
|
||||
var nextOccurence = crontab.GetNextOccurrence(beginTime);
|
||||
Assert.Equal(nextOccurenceString, nextOccurence.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestRandownInSecondOrMinuteOrHour()
|
||||
{
|
||||
var beginTime = new DateTime(2022, 1, 1, 0, 0, 0);
|
||||
var crontab = Crontab.Parse("R 0 0 * * ? *", CronStringFormat.WithSecondsAndYears);
|
||||
Assert.Equal("R 0 0 * * ? *", crontab.ToString());
|
||||
var nextOccurence = crontab.GetNextOccurrence(beginTime);
|
||||
Assert.True(nextOccurence.Second >= 0 && nextOccurence.Second <= 59);
|
||||
_testOutput.WriteLine(nextOccurence.Second.ToString());
|
||||
|
||||
Assert.Throws<TimeCrontabException>(() => Crontab.Parse("* 0 0 R * ? *", CronStringFormat.WithSecondsAndYears));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -1 +1,241 @@
|
||||
<mxfile host="app.diagrams.net" modified="2021-11-02T03:52:12.660Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36 Edg/95.0.1020.40" etag="Mx09_VDbTYaenX91ye-a" version="15.6.5" type="device"><diagram id="WkeWRNO0_8-4DGBAKRoH" name="第 1 页">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</diagram></mxfile>
|
||||
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0" version="25.0.3">
|
||||
<diagram id="WkeWRNO0_8-4DGBAKRoH" name="第 1 页">
|
||||
<mxGraphModel dx="2946" dy="2322" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-5" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;dashed=1;strokeColor=#9AC7BF;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="bQTGmraBkOQblV_vZFuV-9" target="bQTGmraBkOQblV_vZFuV-39" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="520" y="-230" as="sourcePoint" />
|
||||
<mxPoint x="605" y="-280" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="8vwS0P_EyHgajMrRZs6i-3" value="" style="whiteSpace=wrap;html=1;rounded=1;shadow=0;glass=0;labelBackgroundColor=none;labelBorderColor=none;sketch=0;fontSize=14;fontColor=#66CC00;strokeColor=default;fillColor=default;" parent="1" vertex="1">
|
||||
<mxGeometry x="100" y="-570" width="1020" height="550" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-37" value="" style="shape=step;perimeter=stepPerimeter;whiteSpace=wrap;html=1;fixedSize=1;rounded=1;shadow=0;dashed=1;fillColor=#f9f7ed;strokeColor=#36393d;fontColor=default;" parent="1" vertex="1">
|
||||
<mxGeometry x="549.5" y="-530" width="150" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-19" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeColor=#9AC7BF;" parent="1" target="bQTGmraBkOQblV_vZFuV-48" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="610" y="-140" as="sourcePoint" />
|
||||
<mxPoint x="640" y="-280" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-18" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;exitX=0.568;exitY=-0.056;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeColor=#9AC7BF;" parent="1" source="oyyRcJvMBh7io7JTii5K-3" target="bQTGmraBkOQblV_vZFuV-42" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="590" y="-230" as="sourcePoint" />
|
||||
<mxPoint x="640" y="-280" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-17" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeColor=#9AC7BF;" parent="1" target="bQTGmraBkOQblV_vZFuV-36" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="600" y="-140" as="sourcePoint" />
|
||||
<mxPoint x="640" y="-280" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-16" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeColor=#9AC7BF;" parent="1" source="bQTGmraBkOQblV_vZFuV-9" target="bQTGmraBkOQblV_vZFuV-30" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="510" y="-230" as="sourcePoint" />
|
||||
<mxPoint x="560" y="-280" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-15" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeColor=#9AC7BF;" parent="1" target="bQTGmraBkOQblV_vZFuV-45" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="610" y="-140" as="sourcePoint" />
|
||||
<mxPoint x="630" y="-280" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-14" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;exitX=0.526;exitY=-0.233;exitDx=0;exitDy=0;exitPerimeter=0;strokeColor=#9AC7BF;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" target="bQTGmraBkOQblV_vZFuV-27" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="603.386" y="-136.99" as="sourcePoint" />
|
||||
<mxPoint x="360" y="-250" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-9" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffff88;strokeColor=#36393d;" parent="1" vertex="1">
|
||||
<mxGeometry x="420.5" y="-140" width="369.5" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-1" value="秒" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#eeeeee;strokeColor=#36393d;fontStyle=1" parent="1" vertex="1">
|
||||
<mxGeometry x="441" y="-100" width="39" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-2" value="分" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;shadow=1;fontStyle=1" parent="1" vertex="1">
|
||||
<mxGeometry x="490" y="-100" width="39" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-3" value="时" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;shadow=1;fontStyle=1" parent="1" vertex="1">
|
||||
<mxGeometry x="540" y="-100" width="39" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-4" value="天" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;shadow=1;fontStyle=1" parent="1" vertex="1">
|
||||
<mxGeometry x="590" y="-100" width="39" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-6" value="月" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;shadow=1;fontStyle=1" parent="1" vertex="1">
|
||||
<mxGeometry x="640" y="-100" width="39" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-7" value="星期" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;shadow=1;fontStyle=1" parent="1" vertex="1">
|
||||
<mxGeometry x="690" y="-100" width="39" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-8" value="年" style="rounded=0;whiteSpace=wrap;html=1;dashed=1;fillColor=#eeeeee;strokeColor=#36393d;fontStyle=1" parent="1" vertex="1">
|
||||
<mxGeometry x="740" y="-100" width="39" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-27" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
|
||||
<mxGeometry x="148" y="-330" width="210" height="65" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-28" value=""?" 字符解析器" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontColor=#0000CC;" parent="1" vertex="1">
|
||||
<mxGeometry x="207" y="-330" width="91" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-29" value="BlankDayOfMonthOrWeekParser" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fad7ac;strokeColor=#b46504;" parent="1" vertex="1">
|
||||
<mxGeometry x="158.5" y="-303" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-30" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
|
||||
<mxGeometry x="148.5" y="-413" width="210" height="65" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-31" value=""*" 字符解析器" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontColor=#0000CC;" parent="1" vertex="1">
|
||||
<mxGeometry x="207.5" y="-413" width="91" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-32" value="AnyParser" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fad7ac;strokeColor=#b46504;" parent="1" vertex="1">
|
||||
<mxGeometry x="159" y="-386" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-36" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
|
||||
<mxGeometry x="384" y="-413" width="210" height="65" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-37" value=""L" 字符解析器" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontColor=#0000CC;" parent="1" vertex="1">
|
||||
<mxGeometry x="443" y="-413" width="91" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-38" value="LastDayOfMonthParser" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fad7ac;strokeColor=#b46504;" parent="1" vertex="1">
|
||||
<mxGeometry x="394.5" y="-386" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-39" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
|
||||
<mxGeometry x="387.5" y="-330" width="210" height="65" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-40" value=""{0}L" 字符解析器" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontColor=#0000CC;" parent="1" vertex="1">
|
||||
<mxGeometry x="436.5" y="-330" width="111" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-41" value="LastDayOfWeekInMonthParser" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fad7ac;strokeColor=#b46504;" parent="1" vertex="1">
|
||||
<mxGeometry x="398" y="-303" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-42" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
|
||||
<mxGeometry x="626.5" y="-413" width="210" height="65" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-44" value="LastWeekdayOfMonthParser" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fad7ac;strokeColor=#b46504;" parent="1" vertex="1">
|
||||
<mxGeometry x="637" y="-386" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-45" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
|
||||
<mxGeometry x="627" y="-330" width="210" height="65" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-46" value=""{0}W" 字符解析器" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontColor=#0000CC;" parent="1" vertex="1">
|
||||
<mxGeometry x="676" y="-330" width="111" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-47" value="NearestWeekdayParser" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fad7ac;strokeColor=#b46504;" parent="1" vertex="1">
|
||||
<mxGeometry x="637.5" y="-303" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-48" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
|
||||
<mxGeometry x="867.5" y="-413" width="210" height="65" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-49" value=""{0}-{1}[/{2}]" 字符解析器" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontColor=#0000CC;" parent="1" vertex="1">
|
||||
<mxGeometry x="905.25" y="-413" width="143.5" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-50" value="RangeParser" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fad7ac;strokeColor=#b46504;" parent="1" vertex="1">
|
||||
<mxGeometry x="878" y="-386" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-51" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontColor=default;" parent="1" vertex="1">
|
||||
<mxGeometry x="144" y="-247" width="210" height="65" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-53" value="SpecificDayOfWeekInMonthParser" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fad7ac;strokeColor=#b46504;fontColor=default;" parent="1" vertex="1">
|
||||
<mxGeometry x="154.5" y="-220" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-54" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
|
||||
<mxGeometry x="384" y="-247" width="210" height="65" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-60" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
|
||||
<mxGeometry x="626.5" y="-247" width="210" height="65" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-61" value=""{0}/{1}" 字符解析器" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontColor=#0000CC;" parent="1" vertex="1">
|
||||
<mxGeometry x="675.5" y="-247" width="121" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-62" value="StepParser" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fad7ac;strokeColor=#b46504;" parent="1" vertex="1">
|
||||
<mxGeometry x="637" y="-220" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-3" value="Cron 表达式" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontColor=#0000CC;" parent="1" vertex="1">
|
||||
<mxGeometry x="545" y="-135" width="111" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-6" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;strokeColor=#9AC7BF;" parent="1" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="601" y="-140" as="sourcePoint" />
|
||||
<mxPoint x="480" y="-180" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-7" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;dashed=1;strokeColor=#9AC7BF;" parent="1" source="bQTGmraBkOQblV_vZFuV-9" target="bQTGmraBkOQblV_vZFuV-60" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="520" y="-230" as="sourcePoint" />
|
||||
<mxPoint x="570" y="-280" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-8" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;strokeColor=#9AC7BF;" parent="1" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="610" y="-140" as="sourcePoint" />
|
||||
<mxPoint x="970" y="-180" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-9" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;strokeColor=#9AC7BF;labelBackgroundColor=default;fontColor=default;entryX=0.467;entryY=1.006;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" target="bQTGmraBkOQblV_vZFuV-51" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="600" y="-140" as="sourcePoint" />
|
||||
<mxPoint x="230" y="-150" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-20" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;dashed=1;strokeColor=#36393d;fillColor=#cdeb8b;labelBackgroundColor=default;fontColor=default;" parent="1" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="449" y="-490.49" as="sourcePoint" />
|
||||
<mxPoint x="509" y="-490.49" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-31" value="" style="shape=image;html=1;verticalAlign=top;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;imageAspect=0;aspect=fixed;image=https://cdn4.iconfinder.com/data/icons/macaron-1/48/calc-128.png;rounded=1;shadow=0;dashed=1;fontColor=default;" parent="1" vertex="1">
|
||||
<mxGeometry x="524.25" y="-517.12" width="54.25" height="54.25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-34" value="" style="shape=image;html=1;verticalAlign=top;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;imageAspect=0;aspect=fixed;image=https://cdn0.iconfinder.com/data/icons/interior-and-decor-vol-1-1/512/14-128.png;rounded=1;shadow=0;dashed=1;fontColor=default;" parent="1" vertex="1">
|
||||
<mxGeometry x="598.25" y="-525.75" width="71.5" height="71.5" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="oyyRcJvMBh7io7JTii5K-36" value=""LW" 字符解析器" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontColor=#0000CC;" parent="1" vertex="1">
|
||||
<mxGeometry x="685.5" y="-413" width="111" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8vwS0P_EyHgajMrRZs6i-1" value=""{0}#{1}" 字符解析器" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontColor=#0000CC;" parent="1" vertex="1">
|
||||
<mxGeometry x="179" y="-248" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8vwS0P_EyHgajMrRZs6i-2" value="*&nbsp; &nbsp; &nbsp; ,&nbsp; &nbsp; &nbsp; -&nbsp; &nbsp; &nbsp; /&nbsp; &nbsp; &nbsp; ?&nbsp; &nbsp; &nbsp; <font color="#66cc00">L&nbsp; &nbsp; &nbsp; W&nbsp; &nbsp; &nbsp; #</font>&nbsp; &nbsp; &nbsp; &nbsp;R&nbsp; &nbsp; &nbsp; \d" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontColor=#666600;spacingLeft=3;fontSize=14;fontStyle=1;shadow=0;glass=0;sketch=0;labelBackgroundColor=none;labelBorderColor=none;" parent="1" vertex="1">
|
||||
<mxGeometry x="450.5" y="-60" width="309.5" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8vwS0P_EyHgajMrRZs6i-4" value="TimeCrontab" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;shadow=0;glass=0;labelBackgroundColor=none;labelBorderColor=none;sketch=0;fontSize=20;fontColor=#000000;fontStyle=1" parent="1" vertex="1">
|
||||
<mxGeometry x="155" y="-530" width="105.5" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="a0XmUJtOgRV8PZM-BElt-1" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
|
||||
<mxGeometry x="867.5" y="-330" width="210" height="65" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="a0XmUJtOgRV8PZM-BElt-2" value=""R" 字符解析器" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontColor=#0000CC;" vertex="1" parent="1">
|
||||
<mxGeometry x="916.5" y="-330" width="111" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="a0XmUJtOgRV8PZM-BElt-3" value="RandomParser" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fad7ac;strokeColor=#b46504;" vertex="1" parent="1">
|
||||
<mxGeometry x="878" y="-303" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="a0XmUJtOgRV8PZM-BElt-4" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeColor=#9AC7BF;" edge="1" parent="1" target="a0XmUJtOgRV8PZM-BElt-1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="620" y="-130" as="sourcePoint" />
|
||||
<mxPoint x="983" y="-172" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-56" value="SpecificParser" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fad7ac;strokeColor=#b46504;" parent="1" vertex="1">
|
||||
<mxGeometry x="394.5" y="-220" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-55" value=""\d" 字符解析器" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontColor=#0000CC;" parent="1" vertex="1">
|
||||
<mxGeometry x="433" y="-247" width="121" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-57" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
|
||||
<mxGeometry x="868.5" y="-247" width="210" height="65" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-59" value="SpecificYearParser" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fad7ac;strokeColor=#b46504;" parent="1" vertex="1">
|
||||
<mxGeometry x="879" y="-220" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="bQTGmraBkOQblV_vZFuV-58" value=""\d-Y" 字符解析器" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontColor=#0000CC;" parent="1" vertex="1">
|
||||
<mxGeometry x="916.5" y="-247" width="121" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 115 KiB |
@@ -158,6 +158,12 @@ public sealed partial class Crontab
|
||||
}
|
||||
}
|
||||
|
||||
// 判断值是否等于 R
|
||||
if (newParser == "R")
|
||||
{
|
||||
return new RandomParser(kind);
|
||||
}
|
||||
|
||||
// 判断值是否等于 ?
|
||||
if (newParser == "?")
|
||||
{
|
||||
|
||||
99
src/TimeCrontab/Parsers/RandomParser.cs
Normal file
99
src/TimeCrontab/Parsers/RandomParser.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
// 版权归百小僧及百签科技(广东)有限公司所有。
|
||||
//
|
||||
// 此源代码遵循位于源代码树根目录中的 LICENSE 文件的许可证。
|
||||
|
||||
using System;
|
||||
|
||||
namespace TimeCrontab;
|
||||
|
||||
/// <summary>
|
||||
/// Cron 字段值含 R 字符解析器
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>R 表示随机生成的时刻,仅在 <see cref="CrontabFieldKind.Second"/>、<see cref="CrontabFieldKind.Minute"/> 或 <see cref="CrontabFieldKind.Hour"/> 字段域中使用。</para>
|
||||
/// <para>参考文献:https://help.eset.com/protect_admin/10.0/zh-CN/cron_expression.html。</para>
|
||||
/// </remarks>
|
||||
internal sealed class RandomParser : ICronParser, ITimeParser
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="kind">Cron 字段种类</param>
|
||||
/// <exception cref="TimeCrontabException"></exception>
|
||||
public RandomParser(CrontabFieldKind kind)
|
||||
{
|
||||
// 验证 R 字符是否在 Second、Minute 或 Hour 字段域中使用
|
||||
if (kind != CrontabFieldKind.Second &&
|
||||
kind != CrontabFieldKind.Minute &&
|
||||
kind != CrontabFieldKind.Hour)
|
||||
{
|
||||
throw new TimeCrontabException("The <R> parser can only be used with the Second, Minute, or Hour fields.");
|
||||
}
|
||||
|
||||
Kind = kind;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cron 字段种类
|
||||
/// </summary>
|
||||
public CrontabFieldKind Kind { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 判断当前时间是否符合 Cron 字段种类解析规则
|
||||
/// </summary>
|
||||
/// <param name="datetime">当前时间</param>
|
||||
/// <returns><see cref="bool"/></returns>
|
||||
public bool IsMatch(DateTime datetime)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 Cron 字段种类当前值的下一个发生值
|
||||
/// </summary>
|
||||
/// <param name="currentValue">时间值</param>
|
||||
/// <returns><see cref="int"/></returns>
|
||||
/// <exception cref="TimeCrontabException"></exception>
|
||||
public int? Next(int currentValue)
|
||||
{
|
||||
return GenerateRandomValue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 Cron 字段种类字段起始值
|
||||
/// </summary>
|
||||
/// <returns><see cref="int"/></returns>
|
||||
/// <exception cref="TimeCrontabException"></exception>
|
||||
public int First()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将解析器转换成字符串输出
|
||||
/// </summary>
|
||||
/// <returns><see cref="string"/></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return "R";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 随机对象
|
||||
/// </summary>
|
||||
private static readonly Random random = new();
|
||||
|
||||
/// <summary>
|
||||
/// 生成指定范围的随机值
|
||||
/// </summary>
|
||||
/// <returns><see cref="int"/></returns>
|
||||
private int GenerateRandomValue()
|
||||
{
|
||||
// 获取 Cron 字段种类最小值和最大值
|
||||
var minimum = Constants.MinimumDateTimeValues[Kind];
|
||||
var maximum = Constants.MaximumDateTimeValues[Kind];
|
||||
|
||||
// 生成最小值和最大值之间的随机数
|
||||
return random.Next(minimum, maximum + 1);
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,9 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageReference Include="xunit" Version="2.7.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
using System;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace TimeCrontab.UnitTests;
|
||||
|
||||
public class TimeCrontabUnitTests
|
||||
{
|
||||
private readonly ITestOutputHelper _testOutput;
|
||||
public TimeCrontabUnitTests(ITestOutputHelper testOutput)
|
||||
{
|
||||
_testOutput = testOutput;
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("* * * * *", "* * * * *", CronStringFormat.Default)]
|
||||
[InlineData("0 0 31W * *", "0 0 31W * *", CronStringFormat.Default)]
|
||||
@@ -51,4 +59,17 @@ public class TimeCrontabUnitTests
|
||||
var nextOccurence = crontab.GetNextOccurrence(beginTime);
|
||||
Assert.Equal(nextOccurenceString, nextOccurence.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestRandownInSecondOrMinuteOrHour()
|
||||
{
|
||||
var beginTime = new DateTime(2022, 1, 1, 0, 0, 0);
|
||||
var crontab = Crontab.Parse("R 0 0 * * ? *", CronStringFormat.WithSecondsAndYears);
|
||||
Assert.Equal("R 0 0 * * ? *", crontab.ToString());
|
||||
var nextOccurence = crontab.GetNextOccurrence(beginTime);
|
||||
Assert.True(nextOccurence.Second >= 0 && nextOccurence.Second <= 59);
|
||||
_testOutput.WriteLine(nextOccurence.Second.ToString());
|
||||
|
||||
Assert.Throws<TimeCrontabException>(() => Crontab.Parse("* 0 0 R * ? *", CronStringFormat.WithSecondsAndYears));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user