从列表中获得更接近00:00:00,06:00:00,12:00:00和18:00:00的最佳方式

时间:2014-11-28 10:47:01

标签: c# algorithm linq date

我有一个列表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 个答案:

答案 0 :(得分:2)

您可以减去2个时间跨度。 如果差异超过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)

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

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点(23点)接近午夜而不是早上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

答案 2 :(得分:1)

您可以检索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));

的问候,
丹尼尔。

答案 3 :(得分:0)

我经历了所有答案,我不得不说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);