Timers Elapsed 事件仅在选定的工作日

Posted

技术标签:

【中文标题】Timers Elapsed 事件仅在选定的工作日【英文标题】:Timers Elapsed event only on selected weekdays 【发布时间】:2015-08-22 13:44:30 【问题描述】:

我在 Windows 服务中使用计时器,这很简单,并且可以在事件结束时将一些数据写入文件。在这个应用程序中,我尝试实现 3 种类型的案例:

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

    将在某些特定工作日触发的事件表示我只想从给定的 StartTime 开始在星期一、星期二和星期六执行此操作。

    将在某些特定月份和这些月份触发的事件 特定工作日表示我只想在 7 月和 9 月执行此操作,但从给定的 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 属性的恒定时间,但是在这里我没有得到如何为选定的工作日和选定的月份触发 Elapsed 事件。

【问题讨论】:

var arr = new List<string> "Monday", "Wednesday", "Friday" ; if (arr.Contains(DateTime.Today.DayOfWeek.ToString())) _timer.Elapsed += _timer_elaspsed; 这样的? 谢谢阿米特 我猜这个答案会解决的。 让我们知道会发生什么。 是的,我正在努力 【参考方案1】:

我倾向于为此使用 Microsoft 的响应式框架 (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);

此代码设置了一个 observable,它将首先在new TimeSpan(15, 30, 0) 中指定的时间触发,然后在TimeSpan.FromDays(1.0) 中指定的每一天触发。 .Select(n =&gt; DateTimeOffset.Now) 表示序列将返回它触发的实际 DateTimeOffset

现在你只需要应用过滤器来获得你需要的另外两个 observable:

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() 即可。

【讨论】:

我很欣赏你的回答,但如果开始做一些新的事情,这将需要很多时间,因为我需要阅读“Rx-Main”的文档,我可能不会不想那样做。因为我确实有一个符合该条件的逻辑,因为我只需要计算一些东西就可以得到解决方案,但我认为这不是最佳的,因此我正在等待正确的答案。【参考方案2】:

最简单的方法是使用最大的间隔来满足您的需求(您在一天中的特定时间写下您想要它,所以一个小时可能太大,但 15 分钟可能就可以了) ,在Timer_Elapsed 事件处理程序中,只需使用DateTime.Now 检查条件。

如果DateTime.Now 的值适合案例 1,则调用将执行案例 1 的方法。 如果适合案例 2,请调用将执行案例 2 的方法, 如果它适合第 3 种情况,那么,你明白了吧?

【讨论】:

以上是关于Timers Elapsed 事件仅在选定的工作日的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在 Timer 被处理后生成触发 System.Timers.Timer 的 Elapsed 事件的示例?

System.Timers.Timer

如何防止 System.Timers.Timer 在线程池上排队执行?

C#定时器和事件

c# 怎么设置 System.Timers.Timer执行次数 t5.AutoReset = false;

c# Timer异常停止