【问题标题】:How do I calculate timer intervals for monthly scheduling?如何计算每月计划的计时器间隔?
【发布时间】:2016-05-25 16:04:44
【问题描述】:

我正在构建一个 Windows 服务,我希望它以可配置的时间间隔处理一堆不同的后台任务。

我很难弄清楚如何计算计时器在开始某些任务之前需要等待的时间长度。

我针对任务存储了一个StartDate,以及一个间隔类型:每天、每周、每月等。我已经确定了每天,但不知道如何每月执行...

规则是:

  • 如果StartDate在未来,则等待NowStartDate之间的时间长度。

  • 如果 StartDate 是过去的,则在与 StartDate 相同的日期/时间开始任务,但在当前/下个月。因此,如果StartDate 是 3 月 15 日 09:00,而今天是 5 月 25 日,那么下一次任务应该运行的时间是 6 月 15 日 09:00。

到目前为止,我已经做到了这一点。这是一个测试应用程序,它需要一些测试用例并尝试计算当前时间(根据测试用例)和任务的固定开始时间之间的小时数:

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main() {

        // Test cases
        var times = new Dictionary<DateTime,TimeSpan> {
            { new DateTime(2016, 3, 1, 9, 0, 0), TimeSpan.FromHours(2016)},
            { new DateTime(2016, 3, 5, 3, 0, 0), TimeSpan.FromHours(1926)},
            { new DateTime(2016, 3, 5, 9, 0, 0), TimeSpan.FromHours(1920)},
            { new DateTime(2016, 3, 5, 15, 0, 0), TimeSpan.FromHours(1914)},
            { new DateTime(2016, 3, 24, 3, 0, 0), TimeSpan.FromHours(1470)},
            { new DateTime(2016, 3, 24, 9, 0, 0), TimeSpan.FromHours(1464)},
            { new DateTime(2016, 3, 24, 15, 0, 0), TimeSpan.FromHours(1458)},
            { new DateTime(2016, 4, 19, 9, 0, 0), TimeSpan.FromHours(840)},
            { new DateTime(2016, 4, 24, 3, 0, 0), TimeSpan.FromHours(726)},
            { new DateTime(2016, 4, 24, 9, 0, 0), TimeSpan.FromHours(720)},
            { new DateTime(2016, 4, 24, 15, 0, 0), TimeSpan.FromHours(714)},
            { new DateTime(2016, 4, 24, 21, 0, 0), TimeSpan.FromHours(708)},
            { new DateTime(2016, 5, 6, 3, 0, 0), TimeSpan.FromHours(438)},
            { new DateTime(2016, 5, 24, 3, 0, 0), TimeSpan.FromHours(6)},
            { new DateTime(2016, 5, 24, 9, 0, 0), TimeSpan.FromHours(0)},
            { new DateTime(2016, 5, 24, 15, 0, 0), TimeSpan.FromHours(738)},
            { new DateTime(2016, 5, 26, 3, 0, 0), TimeSpan.FromHours(702)},
            { new DateTime(2016, 5, 26, 9, 0, 0), TimeSpan.FromHours(696)},
            { new DateTime(2016, 5, 26, 15, 0, 0), TimeSpan.FromHours(690)},
            { new DateTime(2016, 6, 24, 3, 0, 0), TimeSpan.FromHours(6)},
            { new DateTime(2016, 6, 24, 9, 0, 0), TimeSpan.FromHours(0)},
            { new DateTime(2016, 6, 24, 15, 0, 0), TimeSpan.FromHours(714)},
            { new DateTime(2016, 7, 6, 3, 0, 0), TimeSpan.FromHours(438)},
            { new DateTime(2016, 7, 6, 9, 0, 0), TimeSpan.FromHours(432)},
            { new DateTime(2016, 7, 6, 15, 0, 0), TimeSpan.FromHours(426)},
            { new DateTime(2016, 7, 24, 3, 0, 0), TimeSpan.FromHours(6)},
            { new DateTime(2016, 7, 24, 9, 0, 0), TimeSpan.FromHours(0)},
            { new DateTime(2016, 7, 24, 15, 0, 0), TimeSpan.FromHours(738)},

        }; 


        var startTime = new DateTime(2016, 05, 24, 09, 00, 00);
        var last = times.First().Key;


        foreach (var time in times) {

            var now = time.Key;
            var expected = time.Value;

            var timer = startTime.TimeOfDay - now.TimeOfDay;

            if (now <= startTime)                   
                timer += TimeSpan.FromDays((startTime.Date - now.Date).TotalDays);
            else 
                timer += TimeSpan.FromDays((now.Date.AddMonths(1) - now.Date).TotalDays);                   

            if (last.Date != now.Date) Console.WriteLine();
            Console.WriteLine($"{now:yyyy-MM-dd HH:mm} -> {startTime:yyyy-MM-dd HH:mm} = {timer:dd\\.hh}   {(timer != expected ? "EXPECTED " + expected.ToString("dd\\.hh") : "CORRECT       ")}");

            last = now;

        }           
    }       
}

产生以下输出:

2016-03-01 09:00 -> 2016-05-24 09:00 = 84.00   CORRECT       

2016-03-05 03:00 -> 2016-05-24 09:00 = 80.06   CORRECT       
2016-03-05 09:00 -> 2016-05-24 09:00 = 80.00   CORRECT       
2016-03-05 15:00 -> 2016-05-24 09:00 = 79.18   CORRECT       

2016-03-24 03:00 -> 2016-05-24 09:00 = 61.06   CORRECT       
2016-03-24 09:00 -> 2016-05-24 09:00 = 61.00   CORRECT       
2016-03-24 15:00 -> 2016-05-24 09:00 = 60.18   CORRECT       

2016-04-19 09:00 -> 2016-05-24 09:00 = 35.00   CORRECT       

2016-04-24 03:00 -> 2016-05-24 09:00 = 30.06   CORRECT       
2016-04-24 09:00 -> 2016-05-24 09:00 = 30.00   CORRECT       
2016-04-24 15:00 -> 2016-05-24 09:00 = 29.18   CORRECT       
2016-04-24 21:00 -> 2016-05-24 09:00 = 29.12   CORRECT       

2016-05-06 03:00 -> 2016-05-24 09:00 = 18.06   CORRECT       

2016-05-24 03:00 -> 2016-05-24 09:00 = 00.06   CORRECT       
2016-05-24 09:00 -> 2016-05-24 09:00 = 00.00   CORRECT       
2016-05-24 15:00 -> 2016-05-24 09:00 = 30.18   CORRECT       

2016-05-26 03:00 -> 2016-05-24 09:00 = 31.06   EXPECTED 29.06
2016-05-26 09:00 -> 2016-05-24 09:00 = 31.00   EXPECTED 29.00
2016-05-26 15:00 -> 2016-05-24 09:00 = 30.18   EXPECTED 28.18

2016-06-24 03:00 -> 2016-05-24 09:00 = 30.06   EXPECTED 00.06
2016-06-24 09:00 -> 2016-05-24 09:00 = 30.00   EXPECTED 00.00
2016-06-24 15:00 -> 2016-05-24 09:00 = 29.18   CORRECT       

2016-07-06 03:00 -> 2016-05-24 09:00 = 31.06   EXPECTED 18.06
2016-07-06 09:00 -> 2016-05-24 09:00 = 31.00   EXPECTED 18.00
2016-07-06 15:00 -> 2016-05-24 09:00 = 30.18   EXPECTED 17.18

2016-07-24 03:00 -> 2016-05-24 09:00 = 31.06   EXPECTED 00.06
2016-07-24 09:00 -> 2016-05-24 09:00 = 31.00   EXPECTED 00.00
2016-07-24 15:00 -> 2016-05-24 09:00 = 30.18   CORRECT

正如你所看到的,它在最后有点不对劲。我需要哪些计算才能正确计算出小时数?

【问题讨论】:

  • TimeSpan.FromDays((a - b).TotalDays)不等于(a-b)吗?
  • @IanMercer:可能......我已经尝试了很多东西,只是我在玩计算而没有最终优化它:)

标签: c# datetime intervals


【解决方案1】:

试试这个代码:

foreach (var time in times)
{
    var now = time.Key;
    var expected = time.Value;                
    TimeSpan timer;
    if (now <= startTime) {
         // no need to do anything here - just substract
         timer = startTime - now;
    } 
    else {
         // normalize start time to current month
         var normalized = new DateTime(now.Year, now.Month, startTime.Day, startTime.Hour, startTime.Minute, startTime.Second);
         if (normalized >= now) {
               // normalized date is later in the same month - substract
               timer = normalized - now;
         }
         else {
               // normalized date is before current - move to next month
               timer = normalized.AddMonths(1) - now;
         }
    }                

if (last.Date != now.Date) Console.WriteLine();
    Console.WriteLine($"{now:yyyy-MM-dd HH:mm} -> {startTime:yyyy-MM-dd HH:mm} = {timer:dd\\.hh}   {(timer != expected ? "EXPECTED " + expected.ToString("dd\\.hh") : "CORRECT       ")}");
    last = now;
}

【讨论】:

  • 这是完美的,谢谢。经过测试并完全按照需要工作:)
猜你喜欢
  • 2012-04-26
  • 2021-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多