Po prostu użyj przeciążenia Timer, które akceptuje wartość DateTimeOffset
. Możesz użyć Defer
i Repeat
, aby utworzyć "interwał bezwzględny".
Observable.Defer(() =>
DateTime.Now.Hour < 9
? Observable.Timer(DateTime.Today.AddHours(9))
: DateTime.Now.Hour < 13
? Observable.Timer(DateTime.Today.AddHours(13))
: Observable.Timer(DateTime.Today.AddDays(1).AddHours(9)))
.Repeat()
.Subscribe(...);
Rx automatically ensures, do starań, że zgłoszenie będzie występować o dokładnej dacie i czasie określonym, nawet w odniesieniu do dryfu czasowego i jeżeli zmiany zegar systemowy przed upływem czasu trwania timera.
Oto metoda przedłużania, która dodatkowo zwiększa problem.
Zastosowanie:
Observable2.Daily(TimeSpan.FromHours(9), TimeSpan.FromHours(13)).Subscribe(...);
Definicja:
public static partial class Observable2
{
public static IObservable<long> Daily(params TimeSpan[] times)
{
Contract.Requires(times != null);
Contract.Requires(Contract.ForAll(times, time => time > TimeSpan.Zero));
Contract.Requires(Contract.ForAll(times, time => time.TotalDays < 1));
return Daily(Scheduler.Default, times);
}
public static IObservable<long> Daily(IScheduler scheduler, params TimeSpan[] times)
{
Contract.Requires(times != null);
Contract.Requires(Contract.ForAll(times, time => time > TimeSpan.Zero));
Contract.Requires(Contract.ForAll(times, time => time.TotalDays < 1));
if (times.Length == 0)
return Observable.Never<long>();
// Do not sort in place.
var sortedTimes = times.ToList();
sortedTimes.Sort();
return Observable.Defer(() =>
{
var now = DateTime.Now;
var next = sortedTimes.FirstOrDefault(time => now.TimeOfDay < time);
var date = next > TimeSpan.Zero
? now.Date.Add(next)
: now.Date.AddDays(1).Add(sortedTimes[0]);
Debug.WriteLine("Next @" + date + " from " + sortedTimes.Aggregate("", (s, t) => s + t + ", "));
return Observable.Timer(date, scheduler);
})
.Repeat()
.Scan(-1L, (n, _) => n + 1);
}
}
Aktualizacja:
Jeśli chcesz być bardziej "funkcjonalny" w swoim podejściu definiując wejście jako nieskończoną sekwencję z iteratora blok, za odpowiedź Jeroena Mosterta, możesz użyć Generate
w następujący sposób.
Observable.Generate(
GetScheduleTimes().GetEnumerator(),
e => e.MoveNext(),
e => e,
e => e.Current,
e => e.Current);
odpowiedź Jeroen Mostert'S (usunięte) pod przykładową realizację GetScheduleTimes
, ale w zasadzie tylko blok iteracyjnej, która dała nieskończoną sekwencję DateTimeOffset
wartości w pętli, przy czym każda pętla jest zwiększany o wartości dzień o 1.
Można obliczyć czas do następnego wyzwalacza i użyć timera z tym czasem oczekiwania (sprawdź parametr 'dueTime' w [Threading.Timer] (http://msdn.microsoft.com/en- us/library/3yb9at7c (v = vs.110) .aspx)) – Jcl
Wpisz swój kod w taki sposób, aby móc korzystać z Harmonogramu zadań systemu Windows, ponieważ jest to jego nazwa d dla. – JRLambert