计时器仅在选定的工作日发生经过的事件

本文关键字:经过 事件 工作日 计时器 | 更新日期: 2023-09-27 17:54:01

我在windows服务中使用计时器,这很简单,并且可以在事件经过时将一些数据写入文件。在这个应用程序中,我试图实现3种类型的情况:

  1. 事件将每天在同一时间(给定的StartTime)被触发。

  2. 事件将在某些特定的工作日触发,说我想只在星期一,星期二和星期六从给定的StartTime开始。

  3. 事件,它将在一些特定的月份和在这些月份的特定工作日说,我想做它只在七月和九月,但在限制天星期一,星期二和星期六从给定的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,你就能明白了,对吧?