渲染具有时隙和重叠约会的日历

时间:2018-10-10 16:25:11

标签: c# .net list time

我正在努力使自己转过头来。

我有一个List<Appointment>,其中包含DateTime StartDateTime End以及其他一些位。

我想画一个日程安排者,其中列出所有约会,并在适当的地方按占位符/空白排列。

我已经解决了这个问题,但是现在我需要处理约会重叠的情况。看来可能是这样;

  • 约会a在约会b之前开始,并在约会b之后结束
  • 约会a在约会b之前开始,并在约会b期间结束
  • 约会a在约会b中开始,并在约会b之后结束
  • 在约会b中指定开始时间,并在约会中结束

这感觉像是一个必须先解决的问题。有指针吗?

这是我目前正在处理的一些可怕代码的示例;

        List<TechActivityModel> techActivity = new TechService().GetTechActivity(7, new DateTime(2018, 4, 11), new DateTime(2018, 4, 11).AddDays(1))
            .OrderBy(t => t.Start).ToList();

        for (int i = techActivity.Count - 1; i >= 0; i--)
        {
            //something starts before and ends after
            TechActivityModel clash = techActivity.Where(t => t.Id != techActivity[i].Id && t.Start < techActivity[i].Start && t.End > techActivity[i].End).FirstOrDefault();
            while (clash != null)
            {
                //split the clashing activity into a task before and another task after the existing on
                //first create the 2nd part of the task (after the existing one)
                TechActivityModel activityContinued = new TechActivityModel()
                {
                    Start = techActivity[i].End,
                    End = clash.End,
                    Subject = "++" + clash.Subject
                };
                activityContinued.Length = (int)(activityContinued.End - activityContinued.Start).TotalMinutes;
                techActivity.Add(activityContinued);

                //update the clashing task to finish when the existing task starts
                clash.Subject = "+" + clash.Subject;
                clash.End = techActivity[i].Start;
                clash.Length = (int)(clash.End - clash.Start).TotalMinutes;

                clash = techActivity.Where(t => t.Id != techActivity[i].Id && t.Start < techActivity[i].Start && t.End > techActivity[i].End).FirstOrDefault();
            }
        }

        for (int i = techActivity.Count - 1; i >= 0; i--)
        {
            //something starts before and ends during
            TechActivityModel clash = techActivity.Where(t => t.Id != techActivity[i].Id && t.Start <= techActivity[i].Start && t.End > techActivity[i].Start).FirstOrDefault();
            while (clash != null)
            {
                //update the clashing task to finish when the existing task starts
                clash.Subject = "/" + clash.Subject;
                clash.End = techActivity[i].Start;
                clash.Length = (int)(clash.End - clash.Start).TotalMinutes;

                clash = techActivity.Where(t => t.Id != techActivity[i].Id && t.Start < techActivity[i].Start && t.End > techActivity[i].Start).FirstOrDefault();
            }
        }

        techActivity = techActivity.OrderBy(t => t.Start).ToList();

        //now we're going to pad all the gaps
        List<TechActivityModel> newList = new List<TechActivityModel>();

        DateTime LastEnd = techActivity[0].End;

        //start with the gap from midnight till the first task
        newList.Add(new TechActivityModel()
        {
            Start = new DateTime(2018, 4, 10),
            End = techActivity[0].Start,
            TicketNumber = 0,
            Note = "",
            TicketSubject = "",
            TimeLogged = 0,
            Id = 0
        }
        );

        //pad all the gaps
        for (int i = 1; i < techActivity.Count; i++)
        {
            if (LastEnd < techActivity[i].Start.AddMinutes(-2))
            {
                TechActivityModel gap = new TechActivityModel()
                {
                    Start = LastEnd.AddMinutes(1),
                    End = techActivity[i].Start,
                    Subject = "",
                    Id = 0
                };
                gap.Length = (int)(gap.End - gap.Start).TotalMinutes;
                newList.Add(gap);
            }
            LastEnd = techActivity[i].End;
        }

        //and finally fill the gap from the last task till midnight
        newList.Add(new TechActivityModel()
        {
            Start = LastEnd,
            End = new DateTime(2018, 4, 11),
            Subject = "",
            Length = 0
        }
        );

        newList.AddRange(techActivity);

        string content = "";
        foreach (TechActivityModel techActivityModel in newList.OrderBy(t => t.Start))
        {
            content += 
                techActivityModel.Start.ToShortTimeString() 
                + " - " + techActivityModel.End.ToShortTimeString() 
                + " (" + techActivityModel.Length + "mins)"
                + " : " + techActivityModel.Subject 
                + Environment.NewLine;
        }

1 个答案:

答案 0 :(得分:1)

如果我对您的理解正确,那么这就是我如何解决您的问题。我将从在一个列表中一起找到所有不同的StartEnd值开始。我们希望它们与众不同且井井有条。然后,我们将列表与自身压缩在一起以生成对:

var l = new List<Appointment>();
var ex = l.SelectMany(a => new[] { a.Start, a.End }).Distinct().OrderBy(dt => dt);
var pairs = ex.Zip(ex.Skip(1), (First, Second) => new { First, Second });

现在,使用我在评论中提到的规则:

  

如果时段a在时段b之前开始并且时段b在时段a之前开始,则两个时间段重叠。

我们遍历每对日期时间,然后在约会列表中重新查询与该对描述的时间段重叠的所有所有约会。如果没有结果,则该时间段当前是免费的。如果得到一个结果,则您(在此期间)的约会没有其他任何重叠。如果得到多个结果,则说明冲突,并且可以计算出显示方式。但是请注意,您不必在这个时间段内再次访问 并延长/缩短它,更新其文本等。