C#'反转'日期时间列表

时间:2015-03-16 09:48:47

标签: c# datetime gaps-and-islands

我有一个DateTimes列表,我需要'反转'(缺少一个更好的词)这个列表。

public class Available
{
    public Available(DateTime startDate, DateTime endDate)
    {
        if (!startDate.Day.Equals(endDate.Day))
            throw new Exception("The start and end days are not equal.");

        this.StartDate = startDate;
        this.EndDate = endDate;
    }

    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
}

List<Available> availableTimes = new List<Available>()
{
    new Available(new DateTime(2015, 3, 16, 08, 00, 00), new DateTime(2015, 3, 16, 10, 00, 00)),
    new Available(new DateTime(2015, 3, 16, 12, 00, 00), new DateTime(2015, 3, 16, 14, 00, 00)),
    new Available(new DateTime(2015, 3, 16, 15, 00, 00), new DateTime(2015, 3, 16, 16, 00, 00)),
};

我需要将此可用时间列表转换为该特定日期的阻止时间列表,但我有点卡住了。在这种情况下,我需要:

2015-3-16 00:00 - 2015-3-16 08:00, 
2015-3-16 10:00 - 2015-3-16 12:00, 
2015-3-16 14:00 - 2015-3-16 15:00, 
2015-3-16 16:00 - 2015-3-16 23:59

有什么好主意吗?

6 个答案:

答案 0 :(得分:5)

尝试这个,将你的类重命名为DateTimeRange,因为它具有双重含义,现在包括阻止,还必须假设23:59是午夜-1滴答。

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

public class DateTimeRange
{
    public DateTimeRange(DateTime startDate, DateTime endDate)
    {
        if (!startDate.Day.Equals(endDate.Day))
            throw new Exception("The start and end days are not equal.");

        this.StartDate = startDate;
        this.EndDate = endDate;
    }

    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
}    



public class Program
{
    static List<DateTimeRange> availableTimes = new List<DateTimeRange>()
    {
        new DateTimeRange(new DateTime(2015, 3, 16, 08, 00, 00), new DateTime(2015, 3, 16, 10, 00, 00)),
        new DateTimeRange(new DateTime(2015, 3, 16, 12, 00, 00), new DateTime(2015, 3, 16, 14, 00, 00)),
        new DateTimeRange(new DateTime(2015, 3, 16, 15, 00, 00), new DateTime(2015, 3, 16, 16, 00, 00)),
    };

    private static IEnumerable<DateTimeRange> GetBlockedTimes(IEnumerable<DateTimeRange> ranges)
    {
        var min = ranges.Select(r => r.StartDate).Min().Date;
        var max = ranges.Select(r => r.EndDate).Max().AddDays(1).Date.AddTicks(-1);

        foreach(var range in ranges.OrderBy(r => r.StartDate))
        {
            yield return new DateTimeRange(min, range.StartDate);
            min = range.EndDate;
        }

        yield return new DateTimeRange(min, max);
    }

    public static void Main()
    {
        foreach(var item in GetBlockedTimes(availableTimes))
        {
            Console.WriteLine(item.StartDate + " - " + item.EndDate);
        }
    }
}

答案 1 :(得分:2)

如果您的列表始终排序&#34;已排序&#34;并且没有重叠时间,算法不应该太难。 &#34;全球开始/结束时间&#34;是指您示例中的值2015-3-16 00:002015-3-16 23:59

start = global start time
for each item in list:
    yield new (start, item.start)
    start = item.end
yield new (start, global end time)

将其翻译成C#方法留作练习。

答案 2 :(得分:1)

您应该注意边缘情况的第一个和结束时间范围。

List<DateTimeRange> availableTimes = new List<DateTimeRange>()
{
    new DateTimeRange(new DateTime(2015, 3, 16, 00, 00, 00), new DateTime(2015, 3, 16, 1, 00, 00)),
    new DateTimeRange(new DateTime(2015, 3, 16, 08, 00, 00), new DateTime(2015, 3, 16, 10, 00, 00)),
    new DateTimeRange(new DateTime(2015, 3, 16, 12, 00, 00), new DateTime(2015, 3, 16, 14, 00, 00)),
    new DateTimeRange(new DateTime(2015, 3, 16, 15, 00, 00), new DateTime(2015, 3, 16, 16, 00, 00)),
    new DateTimeRange(new DateTime(2015, 3, 16, 19, 00, 00), new DateTime(2015, 3, 16, 23, 59, 59)),
};
var gap = GetGapsForDay(availableTimes);




public IEnumerable<DateTimeRange> GetGapsForDay(List<DateTimeRange> ranges)
{
    var start = ranges.First().StartDate.Date;
    var end = ranges.First().StartDate.Date.AddDays(1).AddMinutes(-1);

    foreach(var item in ranges.OrderBy(i => i.StartDate))
    {
        if(start < item.StartDate)
            yield return new DateTimeRange(start, item.StartDate);

        start = item.EndDate;
    }
    if (ranges.Max(i => i.EndDate) < end)
        yield return new DateTimeRange(start, end);
}

答案 3 :(得分:0)

海因兹的算法变成了C#。假设可用间隔不重叠并进行排序。

        DateTime firstDay = availableTimes[0].StartDate;
        DateTime previousTime = new DateTime(firstDay.Year, firstDay.Month, firstDay.Day, 0, 0, 0);
        List<Available> unavailableTimes = new List<Available>();

        foreach (Available available in availableTimes)
        {
            unavailableTimes.Add(new Available(previousTime, available.StartDate));
            previousTime = available.EndDate;
        }

        var dateTime = previousTime.Date;
        DateTime endDay = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 23, 59, 59);
        unavailableTimes.Add(new Available(previousTime, endDay));

答案 4 :(得分:0)

您必须将DateTime连接到单维数组:

        var minBorder = new DateTime(2015, 3, 16, 00, 00, 00);
        var maxBorder = new DateTime(2015, 3, 16, 23, 59, 00);

        var times = new List<DateTime>();
        times.Add(minBorder);
        foreach (var at in availableTimes) {
            times.Add(at.StartDate);
            times.Add(at.EndDate);
        }
        times.Add(maxBorder);

结果:

enter image description here

然后按照你需要的间隔:

    public static IList<Available> Invert(IList<DateTime> input) {
        var result = new List<Available>();
        for (var i = 0; i < input.Count; i += 2) {
            result.Add(
                new Available(input[i], input[i + 1])
            );
        }
        return result;
    }

enter image description here

答案 5 :(得分:-2)

如果您只想按日期订购列表项,请使用链接,这非常简单:

availableTimes = availableTimes.OrderByDescending(x => x.startDate).ToList();