Таймеры прошедшего события только в выбранные будни

Я использую таймеры в службе Windows, которая проста и может записывать некоторые данные в файл всякий раз, когда происходит событие. В этом приложении я пытаюсь реализовать 3 типа случаев:

  1. Событие будет происходить в одно и то же время (с учетом StartTime) каждый день.

  2. Событие, которое будет проводиться в определенные недели WeekDays, говорит, что я хочу сделать это только в понедельник, вторник и субботу, начиная с данного StartTime.

  3. Событие, которое будет проводиться в определенные месяцы и в эти месяцы. Определенные выходные дни говорят, что я хочу сделать это только в июле и сентябре, но в ограниченные дни: понедельник, вторник и суббота, начиная с заданного времени начала.

До сих пор то, что я реализовал, относится к случаю 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 для выбранных дней недели и выбранных месяцев.

2 ответа

Я был бы склонен использовать Microsoft Reactive Framework (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, хорошо, вы получите картину, верно?

Другие вопросы по тегам