每天跑一次

时间:2008-11-11 10:44:54

标签: c# scheduling

是否有任何聪明的方法可以让我的executeEveryDayMethod()每天执行一次,而不必涉及Windows TaskScheduler?

此致

/安德斯

10 个答案:

答案 0 :(得分:16)

我通过以下方式实现了这一目标......

  1. 设置一个每20分钟触发一次的计时器(虽然实际时间由你决定 - 我需要在一天中多次运行)。
  2. 在每个Tick事件中,检查系统时间。将时间与您方法的预定运行时间进行比较。
  3. 如果当前时间小于预定时间,请检查某个持久存储中的某个以获取上次运行该方法的日期时间值。
  4. 如果方法上次运行超过24小时,请运行该方法,并将此运行的日期时间存储回数据存储
  5. 如果方法在过去24小时内最后一次运行,请忽略它。
  6. HTH

    *编辑 - C#中的代码示例::注意:未经测试...

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Timers;
    
    namespace ConsoleApplication2
    {
        class Program
        {
            static void Main(string[] args)
            {
                Timer t1 = new Timer();
                t1.Interval = (1000 * 60 * 20); // 20 minutes...
                t1.Elapsed += new ElapsedEventHandler(t1_Elapsed);
                t1.AutoReset = true;
                t1.Start();
    
                Console.ReadLine();
            }
    
            static void t1_Elapsed(object sender, ElapsedEventArgs e)
            {
                DateTime scheduledRun = DateTime.Today.AddHours(3);  // runs today at 3am.
                System.IO.FileInfo lastTime = new System.IO.FileInfo(@"C:\lastRunTime.txt");
                DateTime lastRan = lastTime.LastWriteTime;
                if (DateTime.Now > scheduledRun)
                {
                    TimeSpan sinceLastRun = DateTime.Now - lastRan;
                    if (sinceLastRun.Hours > 23)
                    {
                        doStuff();
                        // Don't forget to update the file modification date here!!!
                    }
                }
            }
    
            static void doStuff()
            {
                Console.WriteLine("Running the method!");
            }
        }
    }
    

答案 1 :(得分:8)

看看quartz.net。它是.net的调度库。

更具体地看一下here

答案 2 :(得分:4)

如果它运行的时间不相关,并且每次程序启动时都可以重置,你可以设置一个计时器,这是最简单的事情。如果这是不可接受的,它开始变得越来越复杂,就像所提出的解决方案here并且仍然无法解决持久性问题,如果您真的希望执行计划任务,那么您需要单独解决这个问题。我真的会再次考虑是否值得通过所有麻烦来复制完美的现有功能。

这是一个related question(从那里取的例子)。

using System;
using System.Timers;

public class Timer1
{
    private static Timer aTimer = new System.Timers.Timer(24*60*60*1000);

    public static void Main()
    {
        aTimer.Elapsed += new ElapsedEventHandler(ExecuteEveryDayMethod);
        aTimer.Enabled = true;

        Console.WriteLine("Press the Enter key to exit the program.");
        Console.ReadLine();
    }

    // Specify what you want to happen when the Elapsed event is 
    // raised.
    private static void ExecuteEveryDayMethod(object source, ElapsedEventArgs e)
    {
        Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
    }
}

答案 3 :(得分:0)

你可以在一段时间内查询时间并运行,即使机器熄火,你也可以调用方法或使用类似Vinko建议的计时器。

但是更好的解决方案(类似于旧的CRON版本,因此它是一个经过验证的模式)是拥有一些持久性数据,我现在可以想到的最便宜的解决方案是空白文件,检查其最后修改的属性,以及是否它在最近24小时内没有被修改,你触摸它并运行你的方法。这样,您可以确保方法在应用程序周末出现的情况下首先运行。例如。

我之前在C#中做过这个,但是它是一年前在另一个Job上做的,所以我没有代码,但它大约有20行(带有注释和所有)左右。

答案 4 :(得分:0)

如果计算机重新启动可能会出现问题,因此您可以将应用程序作为Windows服务运行。

答案 5 :(得分:0)

要在7到8pm之间每天运行一次作业,我设置了一个间隔= 3600000 ms的计时器,然后执行以下代码进行计时器滴答。

private void timer1_Tick(object sender, EventArgs e)
{
    //ensure that it is running between 7-8pm daily.
    if (DateTime.Now.Hour == 19)
    { 
        RunJob(); 
    }
 }

小时窗口对我来说很好。时间上的额外粒度将需要较小的计时器间隔(60000一分钟),并包括if的分钟。

例如

{
    //ensure that it is running at 7:30pm daily.
    if (DateTime.Now.Hour == 19 && DateTime.Now.Minute == 30)
    { 
        RunJob(); 
    }
 }

答案 6 :(得分:0)

如果您只想每天运行一次,而不关心何时运行,那么它将起作用(将在午夜之后运行)。

声明一个DateTime变量:

DateTime _DateLastRun;

在启动时,设置初始日期值:

_DateLastRun = DateTime.Now.Date;

在要检查是否执行操作的逻辑区域中:

if (_DateLastRun < DateTime.Now.Date) 
{
    // Perform your action
    _DateLastRun= DateTime.Now.Date;
}

答案 7 :(得分:0)

公共局部类Main:形式 {
public Main()// Windows窗体称为Main { InitializeComponent(); }

    private void Main_Load( object sender, EventArgs e )
    {
        /*
         This example uses a System.Windows.Forms Timer

         This code allows you to schedule an event at any given time in one day.
         In this example the timer will tick at 3AM.

         */
        Int32 alarm = GetAlarmInMilliseconds( 3, 0, 0 ); // Milliseconds until 3:00 am.
        timer_MessageCount.Interval = alarm; // Timer will tick at 3:00am.

        timer_MessageCount.Start( );                    
    }

    private Int32 GetAlarmInMilliseconds(Int32 eventHour, Int32 eventMinute, Int32 eventSecond )
    {
        DateTime now = DateTime.Now;
        DateTime eventTime = new DateTime( now.Year, now.Month, now.Day, eventHour, eventMinute, eventSecond );

        TimeSpan ts;

        if ( eventTime > now )
        {
            ts = eventTime - now;
        }
        else
        {
            eventTime = eventTime.AddDays( 1 );
            ts = eventTime - now;
        }

        Console.WriteLine("Next alarm in: {0}", ts );

        return ( Int32 ) ts.TotalMilliseconds;
    }        

    static void DoSomething( )
    {
        Console.WriteLine( "Run your code here." );
    }      

    private void timer_MessageCount_Tick( object sender, EventArgs e )
    {
        DoSomething( );

        Int32 alarm = GetAlarmInMilliseconds( 3, 0, 0 ); // Next alarm time = 3AM
        timer_MessageCount.Interval = alarm;            
    }
}

答案 8 :(得分:0)

您可以尝试此解决方案。

    public Main()
    {
        StartService();
    }

    public async Task StartService(CancellationToken token = default(CancellationToken))
    {
        while (!token.IsCancellationRequested)
        {
            ExecuteFunction();
            try
            {
                await Task.Delay(TimeSpan.FromDays(1), token);
            }
            catch (TaskCanceledException)
            {
                break;
            }
        }
    }

    public async Task ExecuteFunction()
    {
        ...
    }

答案 9 :(得分:0)

如果您正在运行Windows Forms应用程序,则可以按以下方法进行操作。但是,您需要配置一个设置,以便可以存储触发事件的最后日期。如果您从不打算关闭应用程序,则可以将日期存储为静态值。

我正在使用计时器来触发事件,如下所示:

        private void tmrAutoBAK_Tick(object sender, EventArgs e)
        {
            if (BakDB.Properties.Settings.Default.lastFireDate != DateTime.Now.ToString("yyyy-MM-dd"))
            {
                 tmrAutoBAK.Stop(); //STOPS THE TIMER IN CASE OF EVENTUAL MESSAGEBOXES.
                 createBakup(); //EVENT
                 BakDB.Properties.Settings.Default.lastFireDate = DateTime.Now.ToString("yyyy-MM-dd"); //STORING CURRENT DATE TO SETTINGS FILE.
                 BakDB.Properties.Settings.Default.Save(); //SAVING THE SETTING FILE.
                 tmrAutoBAK.Start(); //RESTARTING TIMER
            }
        }