You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中如何编写预约时间与排班时段的冲突判断条件?

解决C#预约时间与HR午餐时段冲突的判断问题

原代码的核心问题

  1. 重复解析DateTime:多次调用DateTime.Parse既降低性能,又增加出错风险,且代码可读性极差。
  2. 逻辑覆盖不全:原判断仅检查预约开始时间是否落在午餐时段内,未覆盖预约时间段与午餐时段部分重叠的场景(比如你的示例中11:30-14:30与13:00-14:00重叠,但原代码无法检测到)。
  3. 变量未定义:代码中使用了currentDate变量,但你提供的变量示例中无此值,会直接导致运行错误。
  4. 时间解析隐患:currentStartTime是"1pm",直接用InvariantCulture.Parse可能因区域性设置问题解析失败,更可靠的方式是解析为TimeSpan。

正确的判断逻辑实现

步骤1:解析所有时间变量(仅一次)

先将所有字符串格式的时间/日期解析为DateTime或TimeSpan对象,避免重复操作:

using System;
using System.Globalization;

// 解析预约的完整时间段
if (!DateTime.TryParse(currentAptStartTime, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime aptStart))
{
    throw new ArgumentException("预约开始时间格式无效");
}
if (!DateTime.TryParse(currentAptEndTime, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime aptEnd))
{
    throw new ArgumentException("预约结束时间格式无效");
}

// 解析HR午餐的日期范围
if (!DateTime.TryParse(currentStartDate, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime lunchDateStart))
{
    throw new ArgumentException("午餐起始日期格式无效");
}
if (!DateTime.TryParse(currentEndDate, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime lunchDateEnd))
{
    throw new ArgumentException("午餐结束日期格式无效");
}

// 解析每日午餐的时间区间(转换为TimeSpan)
if (!TimeSpan.TryParse(currentStartTime, CultureInfo.InvariantCulture, out TimeSpan lunchDailyStart))
{
    throw new ArgumentException("午餐开始时间格式无效");
}
if (!TimeSpan.TryParse(currentEndTime, CultureInfo.InvariantCulture, out TimeSpan lunchDailyEnd))
{
    throw new ArgumentException("午餐结束时间格式无效");
}

步骤2:判断时间段是否重叠

核心逻辑:只要预约时间段与任何一天的午餐时间段存在重叠,就禁止创建预约。

先封装一个判断两个时间段是否重叠的工具方法(采用左闭右开规则,即[start1, end1)和[start2, end2)):

private static bool IsTimeOverlap(DateTime start1, DateTime end1, DateTime start2, DateTime end2)
{
    // 左闭右开的重叠判断:start1 < end2 且 start2 < end1
    return start1 < end2 && start2 < end1;
}

然后遍历所有需要检查的日期(即预约日期与午餐日期范围的交集):

// 确定需要检查的日期范围:预约和午餐日期的重叠区间
DateTime checkStartDate = DateTime.MaxValue(aptStart.Date, lunchDateStart.Date);
DateTime checkEndDate = DateTime.MinValue(aptEnd.Date, lunchDateEnd.Date);

// 如果没有日期重叠,直接允许预约
if (checkStartDate > checkEndDate)
{
    return true;
}

// 遍历每一天,检查当天的午餐时段是否与预约重叠
for (DateTime date = checkStartDate; date <= checkEndDate; date = date.AddDays(1))
{
    DateTime dailyLunchStart = date.Date.Add(lunchDailyStart);
    DateTime dailyLunchEnd = date.Date.Add(lunchDailyEnd);

    // 检查当前午餐时段是否与预约时间段重叠
    if (IsTimeOverlap(aptStart, aptEnd, dailyLunchStart, dailyLunchEnd))
    {
        // 存在重叠,禁止创建预约
        return false;
    }
}

// 无重叠,允许创建预约
return true;

完整示例代码

将上述逻辑整合为一个可调用的方法:

using System;
using System.Globalization;

public class AppointmentValidator
{
    public bool CanCreateAppointment(string currentAptStartTime, string currentAptEndTime,
                                    string currentStartDate, string currentEndDate,
                                    string currentStartTime, string currentEndTime)
    {
        // 解析预约时间
        if (!DateTime.TryParse(currentAptStartTime, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime aptStart) ||
            !DateTime.TryParse(currentAptEndTime, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime aptEnd))
        {
            throw new ArgumentException("预约时间格式无效");
        }

        // 解析午餐日期范围
        if (!DateTime.TryParse(currentStartDate, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime lunchDateStart) ||
            !DateTime.TryParse(currentEndDate, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime lunchDateEnd))
        {
            throw new ArgumentException("午餐日期范围格式无效");
        }

        // 解析每日午餐时间
        if (!TimeSpan.TryParse(currentStartTime, CultureInfo.InvariantCulture, out TimeSpan lunchDailyStart) ||
            !TimeSpan.TryParse(currentEndTime, CultureInfo.InvariantCulture, out TimeSpan lunchDailyEnd))
        {
            throw new ArgumentException("午餐时段格式无效");
        }

        // 确定需要检查的日期区间
        DateTime checkStart = DateTime.MaxValue(aptStart.Date, lunchDateStart.Date);
        DateTime checkEnd = DateTime.MinValue(aptEnd.Date, lunchDateEnd.Date);

        if (checkStart > checkEnd)
        {
            return true;
        }

        // 遍历每一天检查重叠
        for (DateTime date = checkStart; date <= checkEnd; date = date.AddDays(1))
        {
            DateTime dailyLunchStart = date.Date.Add(lunchDailyStart);
            DateTime dailyLunchEnd = date.Date.Add(lunchDailyEnd);

            if (IsTimeOverlap(aptStart, aptEnd, dailyLunchStart, dailyLunchEnd))
            {
                return false;
            }
        }

        return true;
    }

    private static bool IsTimeOverlap(DateTime start1, DateTime end1, DateTime start2, DateTime end2)
    {
        // 左闭右开规则:两个时间段有重叠的条件
        return start1 < end2 && start2 < end1;
    }
}

最佳实践

  • 优先使用TryParse系列方法:避免Parse在格式错误时抛出未处理的异常,提升代码健壮性。
  • 避免重复解析DateTime:解析一次后存储为变量,既提升性能,也让代码更易读。
  • 明确时间段边界规则:提前约定是左闭右开还是闭区间,避免因边界判断歧义导致逻辑错误(比如14:00是否属于午餐时段)。
  • 封装重复逻辑:将时间段重叠判断封装为独立方法,便于复用和维护。
  • 使用清晰的变量命名:比如将currentAptStartTime改为appointmentFullStart,明确变量包含日期和时间,避免混淆。
  • 考虑时区问题:如果系统涉及跨时区,使用DateTimeOffset代替DateTime,确保时间判断的准确性。
  • 添加错误处理:对解析失败的情况返回明确的错误信息,方便调试和用户理解。

内容的提问来源于stack exchange,提问作者Fatt Sky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 18:45:20