标准中没有可用的内容.NET库,具有此功能.而且我不认为它很快会被加入.我的建议是使用第三方Cronos库,它可以很好地处理时间间隔的计算.您可以找到斯蒂芬·克利里的用法示例here.这个库只计算时间间隔,不做任何调度.
如果您想获得更多乐趣,可以将Cronos库的功能包含在定制的PeriodicTimer
类组件中,如下所示:
using Cronos;
public sealed class CronosPeriodicTimer : IDisposable
{
private readonly CronExpression _cronExpression;
private readonly CancellationTokenSource _cts;
private static readonly TimeSpan _minDelay = TimeSpan.FromMilliseconds(500);
public CronosPeriodicTimer(string expression, CronFormat format)
{
_cronExpression = CronExpression.Parse(expression, format);
_cts = new();
}
public async ValueTask<bool> WaitForNextTickAsync(
CancellationToken cancellationToken = default)
{
if (_cts.IsCancellationRequested) return false;
CancellationTokenSource linkedCts = null;
CancellationToken token = _cts.Token;
if (cancellationToken.CanBeCanceled)
{
cancellationToken.ThrowIfCancellationRequested();
linkedCts = CancellationTokenSource
.CreateLinkedTokenSource(_cts.Token, cancellationToken);
token = linkedCts.Token;
}
try
{
DateTime utcNow = DateTime.UtcNow;
DateTime? utcNext = _cronExpression.GetNextOccurrence(utcNow + _minDelay);
if (utcNext is null)
throw new InvalidOperationException("Unreachable date.");
TimeSpan delay = utcNext.Value - utcNow;
Debug.Assert(delay > _minDelay);
try
{
await Task.Delay(delay, token).ConfigureAwait(false);
return true;
}
catch (OperationCanceledException)
{
cancellationToken.ThrowIfCancellationRequested();
return false;
}
}
finally { linkedCts?.Dispose(); }
}
public void Dispose() => _cts.Cancel();
}
除了构造函数之外,CronosPeriodicTimer
类与PeriodicTimer
类具有相同的API.您可以这样使用它:
var timer = new CronosPeriodicTimer("0 * * * * *", CronFormat.IncludeSeconds);
//...
await timer.WaitForNextTickAsync();
表达式0 * * * * *
表示"on the 0 (zero) second of every minute, of every hour, of every day of the month, of every month, and of every day of the week."
您可以找到关于Cron表达式here格式的详细文档.
Note:为了处理Task.Delay
比目标DateTime
完成earlier的场景,WaitForNextTickAsync
的延迟至少为500毫秒.我无法通过实验实现这种情况.Task.Delay
总是在几毫秒after内完成我机器中的目标DateTime
.尽管如此,为了防止计时器两次错误滴答作响的可能性微乎其微,还是应该包括这一安全措施.此功能在实践中不应有任何明显的效果.