首页 > 解决方案 > 检查块时间存在

问题描述

我需要一些帮助来正确检查工人是否离开街区超过 15 分钟。我在工人的工作时间内对他进行不同的检查,并检查他在时间段内的存在。这是我对代码的尝试,该代码目前不适用于:块类(我在其中获取块的开始和结束)

 public class Block
    {
        public DateTime Start { get; set; }
        public DateTime End { get; set; }
    }

带有阻止列表的示例,两个阻止(早上和下午)这是列表中的时间的样子

 List<Block> blocks = new List<Block>();

![在此处输入图像描述

[0] = End{12/30/1899 11:45:00 AM}
[0] = Start{12/30/1899 8:30:00 AM}
[1] = End{12/30/1899 5:00:00 PM}
[1] = Start{12/30/1899 1:15:00 PM}

现在,我在数据库中以这种形式获得了工人的到达和离开:

 List<Presence> presence = new List<Presence>();

time received in the presence list:

arrival                     departure 
1899-12-30 08:03:00.000;    1899-12-30 09:21:00.000
1899-12-30 09:36:00.000;    1899-12-30 10:34:00.000
1899-12-30 10:45:00.000;    1899-12-30 12:05:00.000
1899-12-30 13:03:00.000;    1899-12-30 14:24:00.000
1899-12-30 14:34:00.000;    1899-12-30 16:14:00.000
1899-12-30 16:27:00.000;    1899-12-30 18:02:00.000

在此处输入图像描述

因此,对于每个街区,我需要检查工人是否缺席> 15 分钟。我该如何检查?

这是我当前的代码。

public class Block
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
}

public class Presence
{
    public DateTime Arrival { get; set; }
    public DateTime Departure { get; set; }

    public TimeSpan FlightTime => Arrival - Departure;
}

public static class PresenceExtensions
{
    public static TimeSpan GetTotalFlightTime(this IEnumerable<Presence> presences)
    {
        return new TimeSpan(presences.Sum(r => r.FlightTime.Ticks));
    }
}

public static class BlockExtensions
{
    public static Dictionary<Block, IEnumerable<Presence>> FilterPresences(this IEnumerable<Block> blocks, IEnumerable<Presence> presences)
    {
        Dictionary<Block, IEnumerable<Presence>> result = new Dictionary<Block, IEnumerable<Presence>>();
        foreach (Block block in blocks)
        {
            result.Add(block, presences.Where(p => p.Arrival <= block.End && p.Departure >= block.Start));
        }

        return result;
    }
}

用法:

List<Block> blocks = new List<Block>();
List<Presence> presences = new List<Presence>();

Dictionary<Block, IEnumerable<Presence>> filteredList = blocks.FilterPresences(presences);

foreach (KeyValuePair<Block, IEnumerable<Presence>> pair in filteredList)
{
      if (pair.Value.GetTotalFlightTime() > 15){
      Console.WriteLine("The worker is out of the block for more than 15 min")}

}

我的一位同事向我建议了 检测重叠时段的算法,但我无法计算这段时间之间的数量,我真的需要解决这个问题,我这几天一直有这个问题。请理解。

我用他的例子尝试了这段代码,但没有找到正确的解决方案。

 if(presences.Any(x=>blocks.Any(b=> x.Arrival < b.End && b.Start < x.Departure)))
                {
                    errors.Add("The worker is out of the block for more than 15 min");
                        hasErrors = true;
                }

当应该报告消息以取消阻止> 15 分钟时,我还设置了不同的选项。封锁时间:

  第一节:08:30-11:45 第二节:13:15-17:00

工人的工作地点:

 1. (first Day) 07:00-12:00 | 13:00-16:55 // all right
    2. (second Day) 08:40-11:39 | 13:00-16:55 // missed in the first block> 15 min
    3. (third Day) 08:30-09:00, 09:10-10:00, 10:15-12: 01 | 13:00-16: 55 // missed in the first block> 15 min
   4. (fourt Day) 08:00-14:00 // Missed in the second block> 15 min
   5. (fifth Day)  12:00-17:00 // Missed in first block> 15 min


public class Presence
{
    public Presence(DateTime Arrival, DateTime Departure) { this.Arrival = Arrival; this.Departure = Departure; }
    public DateTime Arrival { get; set; }
    public DateTime Departure { get; set; }
    public DateTime Date { get; set; } //added
    public TimeSpan FlightTime;
    public int UserID {get; set;} //added
}

Date                               Arrival                 Departure
2020-12-23 00:00:00.000 1899-12-30 08:30:00.000 1899-12-30 10:15:00.000
2020-12-23 00:00:00.000 1899-12-30 10:20:00.000 1899-12-30 12:20:00.000
2020-12-23 00:00:00.000 1899-12-30 13:25:00.000 1899-12-30 15:00:00.000
2020-12-23 00:00:00.000 1899-12-30 15:05:00.000 1899-12-30 17:00:00.000
2020-12-23 00:00:00.000 1899-12-30 17:05:00.000 1899-12-30 18:30:00.000

从数据库 prtsc

在此处输入图像描述

例如@Rufus 它看起来不错,几乎在所有地方都向我展示了当消息丢失超过 15 分钟时它应该如何查找消息,只有一个地方没有显示:工人工作:来自

new Presence { 
Arrival = DateTime.Parse("1899-12-30 12:53:00.000"), 
Departure = DateTime.Parse("1899-12-30 15:07:00.000") }, 

那天只有一个街区,它来自

new Block { Start = DateTime.Parse("12/30/1899 08:00:00 AM"), 
End = DateTime.Parse("12/30/1899 16:30:00 PM"), },

标签: c#

解决方案


代码存在一些问题。

首先,FlightTime计算将始终返回一个负数,因为它是从日期中减去Departure日期ArrivalDeparture如果日期来自 onePresence并且Arrival日期来自 next ,这可能是有意义的Presence,但它不适用于单个Presence.

接下来,与上述相关,GetTotalFlightTime只是返回FlightTimefor each的总和Presence,而不是检查a 中连续存在之间Block的时间。

为了解决这个问题,我在Block类中添加了一个方法,该方法接受 aList<Presence>并返回缺席分钟数。此方法过滤掉任何Presence不与块重叠的项目(就像您的扩展方法所做的那样),然后通过查看连续存在之间的时间跨度来计算“缺席时间”。它还检查第一个是否在块开始Presence到达,如果是,则添加该时间:

public class Block
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }

    public double MinutesAbsent(IEnumerable<Presence> presences)
    {
        // Given a list of presences, select only those that overlap this block 
        var relevantPresences = Presence.CombineOverlapping(
            presences?.Where(p => p?.OverlapsWith(this) == true))?
            .OrderBy(p => p.Arrival)
            .ToList();

        // If there aren't any relevant presences, return the total minutes for this block
        if (relevantPresences == null || relevantPresences.Count == 0)
            return (End - Start).TotalMinutes;

        // Get any absent minutes at the start of the block by determining
        // if the first presence arrived after the block's start. If it did,
        // begin with the difference between the block's Start and the 
        // first presence's Arrival. 
        var minutesAbsent = relevantPresences.First().Arrival > Start
            ? (relevantPresences.First().Arrival - Start).TotalMinutes
            : 0;

        // Then add the number of minutes between each presence's 
        // Departure and the next presence's Arrival
        for (var i = 0; i < relevantPresences.Count - 1; i++)
        {
            minutesAbsent += (relevantPresences[i + 1].Arrival -
                              relevantPresences[i].Departure).TotalMinutes;
        }

        // Finally, add any minutes after the last presence 
        // if it departed before the end of the block
        if (relevantPresences.Last().Departure < End)
            minutesAbsent += (End - relevantPresences.Last().Departure).TotalMinutes;

        return minutesAbsent;
    }
}

public class Presence
{
    public DateTime Arrival { get; set; }
    public DateTime Departure { get; set; }

    public TimeSpan FlightTime => Arrival - Departure;

    public Presence(){ }

    public Presence(DateTime arrival, DateTime departure)
    {
        Arrival = arrival;
        Departure = departure;
    }

    public bool OverlapsWith(Block block)
    {
        return Arrival < block?.End && Departure > block.Start;
    }

    public static IEnumerable<Presence> CombineOverlapping(IEnumerable<Presence> presences)
    {
        var items = presences?.ToList()
            .Where(p => p != null)
            .OrderBy(presence => presence.Arrival)
            .ToList();

        if (items?.Any() != true) return items;

        var combined = new List<Presence>();
        var current = items.First();

        for (var i = 1; i < items.Count; i++)
        {
            if (items[i].Arrival <= current.Departure)
            {
                if (items[i].Departure > current.Departure)
                {
                    current.Departure = items[i].Departure;
                }
            }
            else
            {
                combined.Add(current);
                current = items[i];
            }
        }

        combined.Add(current);

        return combined;
    }

    public override string ToString()
    {
        return $"{Arrival} - {Departure}";
    }
}

在使用中,它看起来像:

static void Main()
{
    var blocks = GetSampleBlockData();
    var presences = GetSamplePresenceData();

    for(var i = 0; i < blocks.Count; i++)
    {
        var minutesAbsent = blocks[i].MinutesAbsent(presences);

        if (minutesAbsent > 15)
        {
            Console.WriteLine("Error: User was absent for "+
                $"{minutesAbsent} minutes in block # {i + 1}");
        }
    }

    GetKeyFromUser("\nPress any key to exit...");
}

输出

在此处输入图像描述


为了完整起见,以下是生成示例数据的方法:

private static List<Block> GetSampleBlockData()
{
    return new List<Block>
    {
        new Block
        {
            Start = DateTime.Parse("12/30/1899 8:30:00 AM"),
            End = DateTime.Parse("12/30/1899 11:45:00 AM"),
        },
        new Block
        {
            Start = DateTime.Parse("12/30/1899 1:15:00 PM"),
            End = DateTime.Parse("12/30/1899 5:00:00 PM"),
        },
    };
}

private static List<Presence> GetSamplePresenceData()
{
    return new List<Presence>
    {
        new Presence
        {
            Arrival = DateTime.Parse("1899-12-30 08:03:00.000"),
            Departure = DateTime.Parse("1899-12-30 09:21:00.000")
        },
        new Presence
        {
            Arrival = DateTime.Parse("1899-12-30 09:36:00.000"),
            Departure = DateTime.Parse("1899-12-30 10:34:00.000")
        },
        new Presence
        {
            Arrival = DateTime.Parse("1899-12-30 10:45:00.000"),
            Departure = DateTime.Parse("1899-12-30 12:05:00.000")
        },
        new Presence
        {
            Arrival = DateTime.Parse("1899-12-30 13:03:00.000"),
            Departure = DateTime.Parse("1899-12-30 14:24:00.000")
        },
        new Presence
        {
            Arrival = DateTime.Parse("1899-12-30 14:34:00.000"),
            Departure = DateTime.Parse("1899-12-30 16:14:00.000")
        },
        new Presence
        {
            Arrival = DateTime.Parse("1899-12-30 16:27:00.000"),
            Departure = DateTime.Parse("1899-12-30 18:02:00.000")
        },
    };
}

推荐阅读