计时器仅在选定的工作日发生经过的事件
本文关键字:经过 事件 工作日 计时器 | 更新日期: 2023-09-27 17:54:01
我在windows服务中使用计时器,这很简单,并且可以在事件经过时将一些数据写入文件。在这个应用程序中,我试图实现3种类型的情况:
-
事件将每天在同一时间(给定的StartTime)被触发。
-
事件将在某些特定的工作日触发,说我想只在星期一,星期二和星期六从给定的StartTime开始。
-
事件,它将在一些特定的月份和在这些月份的特定工作日说,我想做它只在七月和九月,但在限制天星期一,星期二和星期六从给定的StartTime开始。
到目前为止,我实现的是案例1,我不确定如何为案例2和案例3做同样的事情。(我在想的逻辑很奇怪)。如果我在解决案例2中得到了一些帮助也会对案例3的实施有所帮助。欢迎提出任何其他建议。
下面是我的代码:
private static Timer aTimer;
public static void Main()
{
aTimer = new System.Timers.Timer(2000);
aTimer.Elapsed += OnTimedEvent;
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program... ");
Console.ReadLine();
Console.WriteLine("Terminating the application...");
}
private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
String path = @"E:'sample1.txt";
StreamWriter osw = new StreamWriter(path, true);
Console.WriteLine("Enter the case (1 or 2 or 3)");
var ch = int.Parse(Console.ReadLine());
//throw new NotImplementedException();
switch (ch)
{
default: break;
case 1:aTimer = new System.Timers.Timer();
aTimer.Elapsed += OnTimedEventCase1;
aTimer.Enabled = false;
break;
case 2: aTimer = new System.Timers.Timer();
aTimer.Elapsed += OnTimedEventCase2;
aTimer.Enabled = false;
break;
case 3: aTimer = new System.Timers.Timer();
aTimer.Elapsed += OnTimedEventCase3;
aTimer.Enabled = false;
break;
}
osw.Close();
osw = null;
}
// Elapsed Event for Case 1
private void OnTimedEventCase1(object source, ElapsedEventArgs e)
{
//throw new NotImplementedException();
Console.WriteLine("Daily Job");
Console.WriteLine("DateTime: " + DateTime.Now);
Timer theTimer = (System.Timers.Timer)source;
theTimer.Interval = 1000 * 24 * 60 * 60; // will do it daily i.e, 24 hours
theTimer.Enabled = true;
}
// Elapsed Event for Case 2
private void OnTimedEventCase2(object source, ElapsedEventArgs e)
{
// throw new NotImplementedException();
string[] days = new string[]{"Monday", "Tuesday" ,"Saturday"};
Console.WriteLine("WeekDays Job");
Console.WriteLine("DateTime: " + DateTime.Now);
Timer theTimer = (System.Timers.Timer)source;
//theTimer.Interval = I don't know how to fire event here according weekdays
//theTimer.Enabled = true;
}
// Elapsed Event for Case 3
private void OnTimedEventCase3(object source, ElapsedEventArgs e)
{
// throw new NotImplementedException();
string[] days = new string[]{"Monday", "Tuesday" ,"Saturday"};
string[] months= new string[]{"July", "September"};
Console.WriteLine("Monthly job");
Console.WriteLine("DateTime: " + DateTime.Now);
Timer theTimer = (System.Timers.Timer)source;
//theTimer.Interval = I don't know how to fire event here according months and then weekdays
//theTimer.Enabled = true;
}
虽然我可以很容易地实现经过的事件数小时,甚至1天,这是恒定的时间量,我需要通过timeInterval属性,但这里我不知道如何为选定的工作日和选定的月份触发经过的事件。
我倾向于使用微软的响应式框架(NuGet "Rx-Main")。那就简单多了。
这是最难的部分:
IObservable<DateTimeOffset> daily =
Observable
.Create<long>(o =>
{
var startTime = DateTimeOffset.Now.Date.Add(new TimeSpan(15, 30, 0));
if (startTime < DateTimeOffset.Now)
{
startTime = startTime.AddDays(1.0);
}
return Observable.Timer(startTime, TimeSpan.FromDays(1.0)).Subscribe(o);
})
.Select(n => DateTimeOffset.Now);
这段代码设置了一个可观察对象,它将首先在new TimeSpan(15, 30, 0)
中指定的时间触发,然后在TimeSpan.FromDays(1.0)
中指定的每天触发。.Select(n => DateTimeOffset.Now)
意味着序列将返回它触发的实际DateTimeOffset
。
现在你只需要应用过滤器来获得你需要的另外两个可观察对象:
IObservable<DateTimeOffset> weekday =
from n in daily
where new []
{
DayOfWeek.Monday,
DayOfWeek.Tuesday,
DayOfWeek.Saturday,
}.Contains(n.DayOfWeek)
select n;
IObservable<DateTimeOffset> monthWeekday =
from n in weekday
where new [] { 7, 9, }.Contains(n.Month)
select n;
它们基本上是LINQ查询,从daily
中过滤出您不想触发的事件。
然后您只需要添加实际使用事件的代码:
IDisposable dailySubscription =
daily
.Subscribe(n =>
{
/* daily work goes here */
});
IDisposable weekdaySubscription =
weekday
.Subscribe(n =>
{
/* weekday work goes here */
});
IDisposable monthWeekdaySubscription =
monthWeekday
.Subscribe(n =>
{
/* month/weekday work goes here */
});
要关闭每个订阅,您需要做的就是对它们调用.Dispose()
。
最简单的方法是使用最大的间隔,这将为您的需求提供最佳的准确性(您写了您希望在一天中的特定时间,所以一个小时可能太大,但15分钟可能是可以的),并在Timer_Elapsed
事件处理程序中使用DateTime.Now
检查条件。
如果DateTime.Now
的值符合情形1,调用执行情形1的方法。
如果它符合情形2,调用一个执行情形2的方法,
如果它符合情形3,你就能明白了,对吧?