时间过滤和合并

本文探讨了在服务预定系统中如何通过时间过滤和时间段合并算法来管理服务人员班次、请假及服务预定,确保用户能够选择到空闲的服务人员。详细介绍了两种关键算法:一种用于合并集合中的各时间段,另一种用于从原始数据中去除请假、预定时间,只保留有效服务时段。通过示例数据展示了算法的实际应用,并提供了辅助测试代码。
摘要由CSDN通过智能技术生成

近期在做一项目的过程中,需要涉及到服务人员班次、请假及服务预定等一系列时间管理问题,最后要提供出人员空闲的时间段以供用户选择,归结到底,涉及到两大时间算法,一是时间过滤,即在原定上班班次安排的基础上扣除休假、请假以及已预定的时间段,另一个是时间段合并,需要将一个服务涉及的多位服务人员的有效时间合并,以便用户先选择时间,而后选择该时间段有空的服务人员。下面将分享一下涉及时间的两个算法。


1、合并集合中的各时间段

原始数据:
startTime=2015-05-26 12:06:00    endTime=2015-05-26 15:06:00
startTime=2015-05-27 16:08:00    endTime=2015-05-27 19:08:00
startTime=2015-05-27 13:10:00    endTime=2015-05-27 16:10:00
startTime=2015-05-27 14:57:00    endTime=2015-05-27 17:57:00
startTime=2015-05-27 10:16:00    endTime=2015-05-27 13:16:00
startTime=2015-05-26 11:50:00    endTime=2015-05-26 13:50:00
startTime=2015-05-26 13:46:00    endTime=2015-05-26 16:46:00
startTime=2015-05-27 9:09:00    endTime=2015-05-27 12:09:00
startTime=2015-05-27 16:36:00    endTime=2015-05-27 18:36:00
startTime=2015-05-26 14:39:00    endTime=2015-05-26 16:39:00

结果:
startTime=2015-05-26 11:50:00    endTime=2015-05-26 16:46:00
startTime=2015-05-27 9:09:00    endTime=2015-05-27 19:08:00


核心代码

public static List<EmptyDuration> MergeDateTime(List<EmptyDuration> emptyDurations)
{
    List<EmptyDuration> results = new List<EmptyDuration>();

    if (emptyDurations.Count == 0)
    {
        return results;
    }

    // 对原始数据进行排序
    List<EmptyDuration> em = emptyDurations.OrderBy(p => p.StartTime).ToList<EmptyDuration>();

    DateTime startTime = em[0].StartTime;
    DateTime endTime = em[0].EndTime;

    for (int i = 0; i < em.Count - 1; i++)
    {
        int j = i + 1;

        // 处理前后两个没有交叉重叠的情况
        if (em[i].EndTime < em[j].StartTime)
        {
            results.Add(new EmptyDuration
            {
                StartTime = startTime,
                EndTime = endTime
            });

            startTime = em[j].StartTime;
            endTime = em[j].EndTime;
        }
        else
        {
            endTime = em[i].EndTime > em[j].EndTime ? em[i].EndTime : em[j].EndTime;
        }
    }

    // 补上最后剩下的时间段
    results.Add(new EmptyDuration
    {
        StartTime = startTime,
        EndTime = endTime
    });

    return results;
}
其它辅助测试代码

public static void MergeTest(int num, int days)
{
    List<EmptyDuration> timeList = GeneralDuration(num, days);
    List<EmptyDuration> list = MergeDateTime(timeList);
}

public static List<EmptyDuration> GeneralDuration(int count, int maxDateDiff)
{
    Random random = new Random(DateTime.Now.Millisecond);
    List<EmptyDuration> list = new List<EmptyDuration>();
    for (int i = 0; i < count; i++)
    {
        int hour = random.Next(9, 20);
        int hourDiff = random.Next(2, 4);
        int min = random.Next(60);
        int dateDiff = random.Next(0, maxDateDiff);
        DateTime startTime = DateTime.Now.Date.AddDays(dateDiff).AddHours(hour).AddMinutes(min);
        DateTime endTime = DateTime.Now.Date.AddDays(dateDiff).AddHours(hour).AddHours(hourDiff).AddMinutes(min);
        list.Add(new EmptyDuration
        {
            ArtificerId = 10002,
            ShopId = 20001,
            StartTime = startTime,
            EndTime = endTime
        });
    }

    return list;
}

2、时间段过滤

在此代码中,左侧是服务人员原定上班时间集合,右侧是员工请假、预定所占时间集合。

原始数据(左):
startTime=2015-05-26 9:00:00    endTime=2015-05-26 22:00:00
startTime=2015-05-27 9:00:00    endTime=2015-05-27 22:00:00
startTime=2015-05-28 9:00:00    endTime=2015-05-28 22:00:00

原始数据(右):
startTime=2015-05-27 19:39:00    endTime=2015-05-27 21:39:00
startTime=2015-05-28 12:56:00    endTime=2015-05-28 15:56:00
startTime=2015-05-26 17:17:00    endTime=2015-05-26 20:17:00
startTime=2015-05-27 9:45:00    endTime=2015-05-27 12:45:00
startTime=2015-05-27 18:08:00    endTime=2015-05-27 20:08:00
startTime=2015-05-28 19:46:00    endTime=2015-05-28 22:46:00
startTime=2015-05-28 12:09:00    endTime=2015-05-28 15:09:00
startTime=2015-05-27 11:55:00    endTime=2015-05-27 13:55:00
startTime=2015-05-28 17:18:00    endTime=2015-05-28 20:18:00
startTime=2015-05-26 18:09:00    endTime=2015-05-26 20:09:00

结果:
startTime=2015-05-26 9:00:00    endTime=2015-05-26 17:17:00
startTime=2015-05-26 20:17:00    endTime=2015-05-26 22:00:00
startTime=2015-05-27 9:00:00    endTime=2015-05-27 9:45:00
startTime=2015-05-27 13:55:00    endTime=2015-05-27 18:08:00
startTime=2015-05-27 21:39:00    endTime=2015-05-27 22:00:00
startTime=2015-05-28 9:00:00    endTime=2015-05-28 12:09:00
startTime=2015-05-28 15:56:00    endTime=2015-05-28 17:18:00

核心代码

public static List<EmptyDuration> SubtractDateTime(List<EmptyDuration> minuend, List<EmptyDuration> subtrahend)
{
    List<EmptyDuration> results = new List<EmptyDuration>();

    if (minuend.Count == 0 )
    {
        return results;
    }

    if (subtrahend.Count == 0)
    {
        return minuend;
    }

    // 对原始数据进行排序
    List<EmptyDuration> lefts = minuend.OrderBy(p => p.StartTime).ToList<EmptyDuration>();
    List<EmptyDuration> rights = subtrahend.OrderBy(p => p.StartTime).ToList<EmptyDuration>();

    // 左右两个集合的指针
    int lIndex = 0;
    int rIndex = 0;

    // 左右两个集合的元素数量
    int lMax = lefts.Count;
    int rMax = rights.Count;

    DateTime startTime = DateTime.MinValue;
    DateTime endTime = DateTime.MinValue;

    // 左右指针是否要下移一位并获取元素数据
    bool lIncrease = true;

    while (lIndex < lMax && rIndex < rMax)
    {
        if (lIncrease)
        {
            startTime = lefts[lIndex].StartTime;
            endTime = lefts[lIndex].EndTime;
        }

        lIncrease = false;

        // 处理两个集合当前元素存在交叉重叠的情况
        if (endTime > rights[rIndex].StartTime && startTime < rights[rIndex].EndTime)
        {
            // 上班开始时间在请假预定时间之前
            if (startTime < rights[rIndex].StartTime)
            {
                results.Add(new EmptyDuration
                {
                    StartTime = startTime,
                    EndTime = rights[rIndex].StartTime
                });

                // 上班结束时间在请假预定结束时间之前
                if (endTime <= rights[rIndex].EndTime)
                {
                    lIncrease = true;
                }
                else
                {
                    startTime = rights[rIndex].EndTime;
                    rIndex++;
                }
            }
            else // 上班开始时间在请假预定时间之后
            {
                        
                // 上班结束在请假预定时间之后
                if (endTime > rights[rIndex].EndTime)
                {
                    startTime = rights[rIndex].EndTime;
                    rIndex++;
                }
                else
                {
                    lIncrease = true;
                }
            }
        }
        else
        {
            // 上班时间段在请假预定时间段之前
            if (startTime < rights[rIndex].StartTime)
            {
                results.Add(new EmptyDuration
                {
                    StartTime = startTime,
                    EndTime = endTime
                });

                lIncrease = true;
            }
            else
            {
                rIndex++;
            }
        }

        if (lIncrease)
        {
            lIndex++;
        }
    }

    // 处理剩余上班时间段
    if (lIndex < lMax)
    {
        results.Add(new EmptyDuration
        {
            StartTime = startTime,
            EndTime = endTime
        });

        for (int i = lIndex + 1; i < lMax; i++)
        {
            results.Add(new EmptyDuration
            {
                StartTime = lefts[i].StartTime,
                EndTime = lefts[i].EndTime
            });
        }
    }

    return results;
}
其它辅助测试代码:

public static void SubtractTest(int num, int days)
{
    List<EmptyDuration> leftList = GeneralDuration(days);
    List<EmptyDuration> rightList = GeneralDuration(num, days);

    List<EmptyDuration> list = SubtractDateTime(leftList, rightList);
}

public static List<EmptyDuration> GeneralDuration(int days)
{
    List<EmptyDuration> list = new List<EmptyDuration>();
    for (int i = 0; i < days; i++)
    {
        list.Add(new EmptyDuration
        {
            StartTime = DateTime.Now.Date.AddDays(i).AddHours(9),
            EndTime = DateTime.Now.Date.AddDays(i).AddHours(22)
        });
    }

    return list;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值