【问题标题】:Best way to get closer time to 00:00:00, 06:00:00, 12:00:00 and 18:00:00 from list从列表中获得更接近 00:00:00、06:00:00、12:00:00 和 18:00:00 的时间的最佳方式
【发布时间】:2014-11-28 10:47:01
【问题描述】:

我有一个列表 DateTime 类型,我需要更接近 00:00:00、06:00:00、12:00:00 和 18:00:00 的时间。

我正在使用 for 循环通过一些 if 条件遍历列表,以获取介于两者之间的值。

但是,我不确定如何获得更接近的值,我也想知道是否有办法使用 LINQ 获得正确的结果。

TimeSpan ts1 = new TimeSpan(list[i].Item1.Hour,
                            list[i].Item1.Minute, 
                            list[i].Item1.Second);

TimeSpan ts2 = new TimeSpan(list[i + 1].Item1.Hour, 
                            list[i + 1].Item1.Minute, 
                            list[i + 1].Item1.Second);

if (ts1.TotalHours < 00 && ts2.TotalHours > 00)
    Console.WriteLine("00:00:00 {0} {1} Take: {2}", ts1, ts2, ts1);
else if (ts1.TotalHours < 06 && ts2.TotalHours > 06)
    Console.WriteLine("06:00:00 {0} {1} Take: {2}", ts1, ts2, ts1);
else if (ts1.TotalHours < 12 && ts2.TotalHours > 12 )
    Console.WriteLine("12:00:00 {0} {1} Take: {2}", ts1, ts2, ts1);
else if (ts1.TotalHours < 18 && ts2.TotalHours > 18)
    Console.WriteLine("18:00:00 {0} {1} Take: {2}", ts1, ts2, ts1);

输出:

00:00:00 11:59:59 12:59:58 Take: 11:59:59
00:00:00 17:59:57 19:00:00 Take: 17:59:57
00:00:00 11:59:59 13:00:00 Take: 11:59:59
00:00:00 16:59:59 18:00:01 Take: 16:59:59
00:00:00 05:59:58 07:00:00 Take: 05:59:58
00:00:00 11:59:58 12:59:59 Take: 11:59:58
00:00:00 17:59:57 18:59:59 Take: 17:59:57
00:00:00 11:00:02 12:00:01 Take: 11:00:02
00:00:00 11:00:02 12:00:02 Take: 11:00:02
00:00:00 16:59:59 18:00:01 Take: 16:59:59
00:00:00 10:59:58 12:00:01 Take: 10:59:58
00:00:00 17:00:02 18:00:01 Take: 17:00:02
00:00:00 05:59:58 06:59:58 Take: 05:59:58
00:00:00 11:59:59 12:59:59 Take: 11:59:59
00:00:00 17:00:00 18:00:01 Take: 17:00:00
00:00:00 11:59:59 12:59:57 Take: 11:59:59
00:00:00 05:59:57 07:00:01 Take: 05:59:57
00:00:00 10:59:58 12:00:01 Take: 10:59:58
00:00:00 17:00:01 18:00:01 Take: 17:00:01
00:00:00 05:59:59 07:00:02 Take: 05:59:59

【问题讨论】:

  • 你想比较什么日期时间,只有当前和下一个?不清楚你想要什么结果。
  • 您想要列表中与这 4 个选项中的任何一个在时间上最接近的项目?
  • @TimSchmelter 好吧,就我而言,我比较了前后。如果您有其他选择,请与我分享。
  • @DavidG 是正确的。

标签: c# algorithm linq date


【解决方案1】:

您可以减去 2 个 TimeSpan。 如果差值超过 12 小时,则从 24 小时中减去。

TimeSpan oneDay = new TimeSpan(24,0,0);
TimeSpan zero = new TimeSpan(0,0,0); //the timespan you want to compare against
TimeSpan diff1 = (ts1 - zero).Duration();
if (diff1.TotalHours >= 12) diff1 = oneDay - diff1;
TimeSpan diff2 = (ts2 - zero).Duration();
if (diff2.TotalHours >= 12) diff2 = oneDay - diff2;
TimeSpan closest = diff1 < diff2 ? ts1 : ts2

【讨论】:

  • 如果时间跨度是 1 小时(晚上 1 点),日期时间是晚上 11 点。距离将是2小时。因此,如果有另一个 DateTimeTimeOfDay=4 小时(晚上 4 点),那么第一个 DateTime 应该会赢。 (如果我正确理解 OP)
  • @TimSchmelter 我第一次没有想到这一点。我希望我现在修好了。
【解决方案2】:

我不确定这是否是您要尝试做的,但以下方法返回最接近给定 TimeSpan 的所有 DateTimes(可以是多个具有相同距离的):

public static IEnumerable<DateTime> GetNearestToTime(TimeSpan targetTime, params DateTime[] dates)
{
    TimeSpan negativeTarget = TimeSpan.FromHours(24) - targetTime;
    var dateInfos = dates
        .Select(dt => new
        {
            DateTime = dt,
            MinDistance = new[] { (dt.TimeOfDay - targetTime).Duration(), (dt.TimeOfDay - negativeTarget).Duration() }.Min()
        });
    var distanceLookup = dateInfos.ToLookup(x => x.MinDistance);
    TimeSpan min = distanceLookup.Min(x => x.Key);
    return distanceLookup[min].Select(x => x.DateTime);
}

这个例子说明了难度:

Target: midnight
Date1 = 2014-11-28 02:00:00
Date2 = 2014-11-27 23:00:00

第二个DateTime 应该获胜,因为晚上 11 点(23H)比凌晨 2 点更接近午夜。

这是一个包含一些日期和时间以及这种极端情况的示例:

TimeSpan[] spans = {TimeSpan.FromHours(0), TimeSpan.FromHours(6),TimeSpan.FromHours(12),TimeSpan.FromHours(18)};
var now = DateTime.Today;  // midnight
var list = new List<DateTime> { now.AddMinutes(-99), now.AddMinutes(+100), now.AddMinutes(199), now.AddMinutes(-200) };
for (int i = 0; i < list.Count; i+=2)
{
    DateTime dt1 = list[i];
    DateTime dt2 = list[i + 1];
    IEnumerable<DateTime> nearestToMidNight = GetNearestToTime(spans[0], dt1, dt2);
    Console.WriteLine("{0} nearest: {1}", spans[0], string.Join(",", nearestToMidNight));
    // and so on with the other timespans...
}

输出:

00:00:00 nearest: 27.11.2014 22:21:00
00:00:00 nearest: 27.11.2014 20:41:00

【讨论】:

  • @doro:当然,看看“输出”。你只需要GetNearestToTime这个方法。
【解决方案3】:

您可以检索 Ticks 属性的值并对其应用偏移量和模运算符。 这允许直接测试底层值并避免调用对其进行冗余计算的属性或方法。

const long TicksPerSecond = 10000000L;
const long TicksPer1Hour = TicksPerSecond * 3600;
const long TicksPer3Hours = TicksPer1Hour * 3;
const long TicksPer6Hours = TicksPer1Hour * 6;
const long TicksPerDay = TicksPer1Hour * 24;

private static long GetDiffFrom6Hours(DateTime time)
{
    return Math.Abs(TicksPer3Hours - (((time.Ticks % TicksPerDay) + TicksPer3Hours) % TicksPer6Hours));
}

取模运算符会将 24 小时分为 4 个块,以匹配您要比较的一天中的时间。 偏移量只允许进行 1 次比较而不是 4 次。

要通过 Linq 对列表进行排序,您只需执行以下操作:

var list2 = list.OrderBy(item => GetDiffFrom6Hours(item.Item1));

问候,
丹尼尔。

【讨论】:

    【解决方案4】:

    我浏览了所有答案,我不得不说 Dennis_E 的答案是最好和最简单的。但是,我进一步简化了它,对于 00:00:00 的情况,我使用了以下代码。相同的逻辑可用于 06:00:00、12:00:00 和 18:00:00。此外,如果可以使用 LINQ 找到解决方案,那就太好了。

    TimeSpan ts00 = new TimeSpan(00, 00, 00);
    TimeSpan diff1 = (ts1 - ts00).Duration();
    TimeSpan diff2 = (ts2 - ts00).Duration();
    TimeSpan closest = diff1 < diff2 ? ts1 : ts2;
    Console.WriteLine("00:00:00 Take: {0}\n\n", closest);
    

    【讨论】:

      猜你喜欢
      • 2011-06-27
      • 1970-01-01
      • 2019-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-12
      相关资源
      最近更新 更多