从List <t> </t> </datetime>中的List <datetime>获取正在进行的和即将到来的(订单)DateTimes

时间:2014-07-04 22:36:56

标签: c# linq list datetime

假设我有一个这样的列表:

List<Timer> bosses = new List<Timer>();
bosses.Add(new Timer { Boss = "Tequatl", Priority = BossPriority.HardCore, SpawnTimes =  {  
    DateTime.ParseExact("07:00 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),  
    DateTime.ParseExact("11:30 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("16:00 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("19:00 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("00:00 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("03:00 +0000", "HH:mm zzz", CultureInfo.InvariantCulture) 
}, Runtime = new TimeSpan(0, 30, 0) });
bosses.Add(new Timer { Boss = "The Shatterer", Priority = BossPriority.Standard, SpawnTimes = {
    DateTime.ParseExact("07:00 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("10:00 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("13:00 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("16:00 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("19:00 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("22:00 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("01:00 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("04:00 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
}, Runtime = new TimeSpan(0, 30, 0) });
bosses.Add(new Timer { Boss = "Jungle Wurm", Priority = BossPriority.LowLevel, SpawnTimes = {
    DateTime.ParseExact("07:15 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("09:15 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("11:15 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("13:15 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("15:15 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("17:15 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("19:15 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("21:15 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("23:15 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("01:15 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("03:15 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
    DateTime.ParseExact("05:15 +0000", "HH:mm zzz", CultureInfo.InvariantCulture),
}, Runtime = new TimeSpan(0,30, 0) });

每个单独的日期时间都是一天中的时间,因此应该每天计算以上日期。

由此我需要找到当前正在运行的DateTimes(与关联的Boss类),每个Timer对象都有一个运行时,它指定运行的时间。例如,我的第一个DateTime从UTC时间7:00开始,到UTC时间7:30结束。

我该怎么做?我希望用LINQ做这个,但我不知道如何订购这些项目,以便日期时间按时间顺序排列。

我想的可能是“扁平化”整个列表,并创建一个新列表,如下所示:

List<BossDatetime> orderedList = new List<BossDatetime>();
foreach (Timer boss in bosses)
{
    foreach (DateTime item in boss.SpawnTimes)
    {
        orderedList.Add(new BossDatetime { Timer = boss, SpawnTime = item });
    }
}
orderedList = orderedList.OrderBy(x => x.SpawnTime).ToList();

这似乎是一种不好的做法,也引发了一些新问题,例如列表告诉我关闭Datetime是最后一个: enter image description here

总结一下我的要求:

  1. 我如何通过DateTime命令我的bosses列表关闭我,并引用计时器,所以我知道它是什么老板,最好是通过LINQ
  2. 如何从上面的列表中检索正在进行的项目。

3 个答案:

答案 0 :(得分:1)

激战2,对吧? ; P

由于每个老板最多只有一个时间可以在任何时刻激活,所以只需过滤掉当前正在运行的那些老板就足够了。因此,您实际上不需要展平列表以检查时间。

因此,您需要选择当前有效的所有老板(使用now = DateTime.Now):

bosses.Where(b => b.SpawnTimes.Where(t => t.TimeOfDay < now.TimeOfDay && now.TimeOfDay < t.TimeOfDay + b.Runtime).Count() > 0)

但是,我个人更喜欢采用不同的方法。由于除了硬核之外的所有老板都出现在一个重复周期中,因此只需记下该周期,然后计算任何给定时间,即周期内的位置。

为此,我将三个boss类型分开,这使得周期变得更加简单(例如,低级别的老板在一个周期中只有4个不同的项目;标准老板在一个周期中有6个不同的项目)。您可以在官方维基上查看我的exemplary implementation,但是用wiki解析器代码编写。这个想法很简单;例如对于标准老板来说,这就是获得当前老板的必要条件:

string[] standardBosses = new string[] { "Taidha Covington", "Megadestroyer", "The Shatterer", "Modniir Ulgoth", "Golem Mark II", "Claw of Jormag" };
Console.WriteLine(standardBosses[((int)DateTime.UtcNow.TimeOfDay.TotalMinutes / 30) % 6]);

答案 1 :(得分:0)

这应该让你当前正在运行老板。由于它返回了老板,因此您获得了所需的所有数据。我不确定我是否理解第1点。

 bosses.Where(x => x.SpawnTimes != null && 
                   x.SpawnTimes.Count > 0 && 
                   x.SpawnTimes.Any(y => y.TimeOfDay <= DateTime.UtcNow.TimeOfDay && 
                                         y.TimeOfDay >= DateTime.UtcNow.TimeOfDay.Subtract(x.Runtime))).ToList();

请注意,您当前的代码会将这些日期时间移动2小时+。

答案 2 :(得分:0)

我不确定它是否与您相关,但这些实现似乎都没有正确处理周期性 - 即前一天晚上开始的事件可能仍然在早上很早就开始运行。

这应该可以解决问题:

    /// <summary>
    /// Check if a time falls inside a repeating daily event of a given duration.
    /// </summary>
    /// <param name="spawnTime">Start time of an event</param>
    /// <param name="runTime">Duration of the event</param>
    /// <param name="now">Time to test</param>
    /// <returns>true if the test time is inside the duration of the specified event.</returns>
    public static bool IsDailyEventActive(DateTime spawnTime, TimeSpan runTime, DateTime now)
    {
        // Are we inside an event that started today?
        DateTime spawnTimeToday = now.Date + spawnTime.TimeOfDay;
        if (now >= spawnTimeToday && now <= spawnTimeToday + runTime)
            return true;
        // Are we still inside an event that started yesterday?
        DateTime spawnTimeYesterday = now.Date.AddDays(-1) + spawnTime.TimeOfDay;
        if (now >= spawnTimeYesterday && now <= spawnTimeYesterday + runTime)
            return true;
        return false;
    }