Подтвердить что ты не робот

Как использовать класс .NET Timer для запуска события в определенное время?

Я хотел бы, чтобы в моем приложении запускалось событие, которое непрерывно работает в течение дня в определенное время, например, в 16:00. Я думал о запуске таймера каждую секунду, и когда время равняется 4:00 вечера, запустите это событие. Это работает. Но мне интересно, есть ли способ получить обратный вызов один раз в 16:00 и не продолжать проверять.

4b9b3361

Ответ 1

Как насчет чего-то подобного, используя класс System.Threading.Timer?

var t = new Timer(TimerCallback);

// Figure how much time until 4:00
DateTime now = DateTime.Now;
DateTime fourOClock = DateTime.Today.AddHours(16.0);

// If it already past 4:00, wait until 4:00 tomorrow    
if (now > fourOClock)
{
    fourOClock = fourOClock.AddDays(1.0);
}

int msUntilFour = (int)((fourOClock - now).TotalMilliseconds);

// Set the timer to elapse only once, at 4:00.
t.Change(msUntilFour, Timeout.Infinite);

Обратите внимание, что если вы используете System.Threading.Timer, обратный вызов, указанный TimerCallback, будет выполнен в потоке пула потоков (non-UI), поэтому, если вы планируете что-то сделать с вашим пользовательским интерфейсом в 4:00, вам нужно будет соответствующим образом упорядочить код (например, используя Control.Invoke в приложении Windows Forms или Dispatcher.Invoke в приложении WPF).

Ответ 2

Начиная с .NET 4.5 существует действительно чистое решение:

public async void ScheduleAction(Action action, DateTime ExecutionTime)
{
    await Task.Delay((int)ExecutionTime.Subtract(DateTime.Now).TotalMilliseconds);
    action();
}

Здесь решение без async/wait:

public void Execute(Action action, DateTime ExecutionTime)
{
    Task WaitTask = Task.Delay((int)ExecutionTime.Subtract(DateTime.Now).TotalMilliseconds);
    WaitTask.ContinueWith(_ => action);
    WaitTask.Start();
}

Следует отметить, что это работает только около 24 дней из-за значения int32 max, чего много для вашего случая, но стоит отметить.

Ответ 3

Вы можете использовать Task Sceduler в окнах См. ежедневный пример триггера для деталей.

или используйте следующий код, если вы хотите написать его самостоятельно:

public void InitTimer()
{
    DateTime time = DateTime.Now;
    int second = time.Second;
    int minute = time.Minute;
    if (second != 0)
    {
        minute = minute > 0 ? minute-- : 59;
    }

    if (minute == 0 && second == 0)
    {
        // DoAction: in this function also set your timer interval to 24 hours
    }
    else
    {
        TimeSpan span = //new daily timespan, previous code was hourly: new TimeSpan(0, 60 - minute, 60 - second);
        timer.Interval = (int) span.TotalMilliseconds - 100; 
        timer.Tick += new EventHandler(timer_Tick);
        timer.Start();
    }
}

void timer_Tick(object sender, EventArgs e)
{
    timer.Interval = ...; // 24 hours
    // DoAction
}

Ответ 4

Взяв VoteCoffees, вот компактное решение, основанное на событиях:

public class DailyTrigger 
{
    readonly TimeSpan triggerHour;  

    public DailyTrigger(int hour, int minute = 0, int second = 0)
    {
        triggerHour = new TimeSpan(hour, minute, second);
        InitiateAsync();        
    }

    async void InitiateAsync()
    {
        while (true)
        {
            var triggerTime = DateTime.Today + triggerHour - DateTime.Now;
            if (triggerTime < TimeSpan.Zero)
                triggerTime = triggerTime.Add(new TimeSpan(24,0,0));
            await Task.Delay(triggerTime);
            OnTimeTriggered?.Invoke();
        }
    }

    public event Action OnTimeTriggered;
}

Потребитель: `

void Main()
{
    var trigger = new DailyTrigger(16); // every day at 4:00pm

    trigger.OnTimeTriggered += () => 
    {
        // Whatever
    };  

    Console.ReadKey();
}

Ответ 5

Планировщик задач является лучшим вариантом, и его можно легко использовать в С#, http://taskscheduler.codeplex.com/

Ответ 6

Я сделал так, чтобы каждое утро уволить 7 утра.

bool _ran = false; //initial setting at start up
    private void timer_Tick(object sender, EventArgs e)
    {

        if (DateTime.Now.Hour == 7 && _ran==false)
        {
            _ran = true;
            Do_Something();               

        }

        if(DateTime.Now.Hour != 7 && _ran == true)
        {
            _ran = false;
        }

    }

Ответ 7

Решение Echo to Dan, использование Timercallback - быстрое и аккуратное решение. Внутри метода, который вы хотите запланировать выполнение задачи или подпрограммы, используйте следующее:

    t = New Timer(Sub()
                        'method call or code here'
                  End Sub, Nothing, 400, Timeout.Infinite)

использование "Timeout.Infinite" гарантирует, что обратный вызов будет выполнен только один раз через 400 мс. Я использую VB.Net.

Ответ 8

Как насчет этого решения?

Sub Main()
  Dim t As New Thread(AddressOf myTask)
  t.Start()
  Console.ReadLine()
End Sub

Private Sub myTask()
  Dim a = "14:35"
  Dim format = "dd/MM/yyyy HH:mm:ss"
  Dim targetTime = DateTime.Parse(a)
  Dim currentTime = DateTime.Parse(Now.ToString(format))
  Console.WriteLine(currentTime)
  Console.WriteLine("target time " & targetTime)
  Dim bb As TimeSpan = targetTime - currentTime
  If bb.TotalMilliseconds < 0 Then
    targetTime = targetTime.AddDays(1)
    bb = targetTime - currentTime
  End If
  Console.WriteLine("Going to sleep at " & Now.ToString & " for " & bb.TotalMilliseconds)
  Thread.Sleep(bb.TotalMilliseconds)
  Console.WriteLine("Woke up at " & Now.ToString(format))
End Sub

Ответ 9

.NET имеет много классов таймеров, но все они занимают промежутки времени относительно текущего времени. С относительным временем, есть много вещей, которые необходимо учитывать, прежде чем запускать таймер и следить за его работой.

  • Что делать, если компьютер переходит в режим ожидания?
  • Что делать, если время компьютера меняется?
  • Что делать, если срок годности истек после перехода на летнее время?
  • Что если пользователь изменяет часовой пояс компьютера после того, как вы запустили таймер, так что перед истечением срока действия произошел переход на новый часовой пояс, которого раньше не было?

Операционная система прекрасно подходит для решения этой проблемы. Код приложения, работающего в .NET, отсутствует.

Для Windows пакет NuGet AbsoluteTimer оборачивает таймер операционной системы, который истекает в абсолютное время.