Таймеры прошедшего события только в выбранные будни
Я использую таймеры в службе Windows, которая проста и может записывать некоторые данные в файл всякий раз, когда происходит событие. В этом приложении я пытаюсь реализовать 3 типа случаев:
Событие будет происходить в одно и то же время (с учетом StartTime) каждый день.
Событие, которое будет проводиться в определенные недели WeekDays, говорит, что я хочу сделать это только в понедельник, вторник и субботу, начиная с данного 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 для выбранных дней недели и выбранных месяцев.
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, хорошо, вы получите картину, верно?