3

当您有不同组的人每天 24 小时在不同的班次上工作(比如一组工作三个 8 小时轮班,另一组工作两个 12 小时轮班,最后一组工作两个 10 小时轮班,4 小时无人值守)给予一分及时返回最近开始的班次的最直接方式是什么?

例如,我有一个 8 小时Shift的列表(BeginTime 分别是早上 6 点、下午 2 点、晚上 10 点)

 public class Shift
    {
        public string Name { get; set; }
        public TimeSpan BeginTime { get; set; }
        public int LengthHours { get; set; }
    }

我当前的代码有效(出于我的目的),但并不理想,因为它需要 startTime 并且轮班在集合中是有序的。

public Shift FindCurrentShift(DateTime startTime, DateTime endTime, List<Shift> shifts)
{
    Shift mostRecentShift = null;
    foreach (Shift aShift in shifts) {
        DateTime shiftBeginTime = DateTime.Parse(endTime.Date.Add(aShift.BeginTime).ToString());
        if (startTime.Date != endTime.Date) {
            if (shiftBeginTime.TimeOfDay > startTime.TimeOfDay) {
                shiftBeginTime = shiftBeginTime.AddDays(-1);
            }
        }
        //does this shift fall in between start and stop time
        if ((startTime < shiftBeginTime && endTime > shiftBeginTime)) {
            mostRecentShift = aShift;
        }
    }
    return mostRecentShift;
}

鉴于当前时间,我在哪个班次?有什么更简单的方法可以做到这一点?

4

5 回答 5

2

使用 LINQ 试试这个:

public Shift FindCurrentShift(DateTime currentDateTime, List<Shift> shifts)
{
    DateTime startOfDay = currentDateTime.Date;

    // Get most recent shift that started today and has not ended yet
    Shift shift = 
        shifts.Where(s => startOfDay.Add(s.BeginTime) <= currentDateTime
                     && startOfDay.Add(s.BeginTime).AddHours(s.LengthHours) <= currentDateTime)
              .OrderByDescending(s => s.BeginTime)
              .FirstOrDefault();

    // If none were found that had a start date today, get the latest shift
    // (would be one that started yesterday) as long as its end time today has not passed yet
    if (shift == null) {
        shift =
            shifts.Where(s => startOfDay.AddDays(-1).Add(s.BeginTime).AddHours(s.LengthHours) <= currentDateTime
                  .OrderByDescending(s => s.BeginTime)
                  .FirstOrDefault();
    }

    return shift;
}
于 2013-10-16T21:44:28.530 回答
1

使用递归和 LINQ 的解决方案可能如下所示:

/// iterate backwards until a shift is found
/// the recursion stops automatically when the last shift is found
/// AddHour(-1) calculates correctly the date if last shift 
/// was "yesterday"
private Shift lastShift(List<Shift> shifts, DateTime startTime)
{
    if (shifts.Count > 0)
    {
        var now = startTime;
        var time = new TimeSpan(now.Hour, now.Minute, now.Second);
        var shiftRunning = (from s in shifts
                            let frame = (time - s.BeginTime).Hours
                            where frame > 0 && frame < s.LengthHours
                            select s).FirstOrDefault();
        if (shiftRunning == null)
        {
            shiftRunning = lastShift(shifts, startTime.AddHours(-1));
        }
        return shiftRunning;
    }
    return null;
}

private Shift findShift(List<Shift> shifts)
{
    return lastShift(shifts, DateTime.Now);
}

它可以这样使用:

var shifts = new List<Shift>
{
    new Shift { Name = "C", BeginTime = new TimeSpan(22, 00, 00), LengthHours = 8 },
    new Shift { Name = "A", BeginTime = new TimeSpan(06, 00, 00), LengthHours = 8 },
    new Shift { Name = "B", BeginTime = new TimeSpan(14, 00, 00), LengthHours = 6 },
    new Shift { Name = "D", BeginTime = new TimeSpan(11, 00, 00), LengthHours = 8 }
};

var shiftRunning = findShift(shifts);

班次的顺序不再重要,总是会选择最近的班次(因为使用 AddHour(-1) 进行了正确计算)。由于递归,不需要双重检查和复杂的 if 条件。由于递归,重叠的移位和间隙也被覆盖。

于 2013-10-16T21:55:15.353 回答
0

我不是 C# 大师,我不太了解 TimeSpan 的类型。如果您只是认为 BeginTime 是 0~23 的整数值范围,则以下伪代码可能会起作用:

Shift mostRecentShift = null;
foreach (Shift aShift in shifts) 
{
    Shift goodShift = null;
    if(aShift.BeginTime <= currentTime)
        if(aShift.BeginTime + aShift.LengthHours > currentTime)
            goodShift = aShift;
    else if(24 - aShift.BeginTime < aShift.LengthHours - currentTime)
        goodShift = aShift;

    if(goodShift != null)
    {
        if(mostRecentShift == null)
            mostRecentShift = goodShift;
        else if(mostRecentShift.BeginTime < goodShift.BeginTime)
            mostRecentShift = goodShift;
    }
}

给定一个 8 小时班次列表(BeginTime 分别是早上 6 点、下午 2 点、晚上 10 点),这段代码关心的是 0:00 ~ 5:59am

于 2013-10-16T22:21:03.127 回答
0

如果我刚刚更新了 mayabelle 的答案,我不确定 SO 的礼仪,但是这个已经改进以删除 LINQ 查询重复并修复一些错误。

public Shift FindCurrentShift(DateTime currentDateTime)
{
    Shift shift = LastShift(currentDateTime, currentDateTime.Date);
// not in shift that started today? then check yesterday
    if (shift == null) {
        shift = LastShift(currentDateTime, currentDateTime.Date.AddDays(-1));
    }
    return shift;
}

private Shift LastShift(DateTime currentDateTime, DateTime startOfDay)
{
return shifts.Where(s => startOfDay.Add(s.BeginTime) <= currentDateTime
               && startOfDay.Add(s.BeginTime).AddHours(s.LengthHours) >= currentDateTime)
        .OrderByDescending(s => s.BeginTime)
        .FirstOrDefault();
}
//initalize this with shifts
public List<Shift> shifts;
于 2013-10-21T18:55:09.407 回答
0

这是一个经典的求最大值问题。您应该只更新mostRecentShiftnull或者如果正在检查的班次最近开始。目前你正在更新它,不管。

于 2013-10-16T21:42:53.467 回答