确定两个日期是否在允许的时间范围内

Determine if two dates are within an allowed time span

我有一个 StartDateTimeEndDateTime,我必须 验证
为了使它们有效,它们必须 在允许的时间内 这是完全可定制的。

// allowed hours
allowedStart = new TimeSpan(08, 00, 0);
allowedEnd   = new TimeSpan(20, 00, 0);

现在要输入两个日期(StartDateTimeEndDateTime)(一些示例测试用例)

    // Valid date
    obj1.StartDateTime = new DateTime(2020, 1, 30, 19, 10, 0);
    obj1.EndDateTime = new DateTime(2020, 1, 30, 19, 20, 0);

    // End date exceeding
    obj2.StartDateTime = new DateTime(2020, 1, 30, 19, 50, 0);
    obj2.EndDateTime = new DateTime(2020, 1, 30, 20, 15, 0);

    // Start and end date exceeding
    obj3.StartDateTime = new DateTime(2020, 1, 30, 20, 10, 0);
    obj3.EndDateTime = new DateTime(2020, 1, 30, 20, 35, 0);

    // Invalid (overnight) both exceeding
    obj4.StartDateTime = new DateTime(2020, 1, 30, 23, 50, 0);
    obj4.EndDateTime = new DateTime(2020, 1, 31, 0, 35, 0);

    // Start to early
    obj5.StartDateTime = new DateTime(2020, 1, 31, 7, 50, 0);
    obj5.EndDateTime = new DateTime(2020, 1, 31, 8, 15, 0);

我想知道是否有一些已经实现的功能我还没有找到,因为我的大脑现在快要死了。我一直在尝试像这样自己实现它,但是 obj4 测试用例 仍然会杀死它:

    if ((obj.StartDateTime.Date.Add(allowedStart) <= obj.StartDateTime) &&
        (allowedEnd < allowedStart 
           ? obj.EndDateTime <= obj.EndDateTime.Date.AddDays(1).Add(allowedEnd) 
           : obj.EndDateTime <= obj.EndDateTime.Date.Add(allowedEnd)))) 
    {
        // valid
    } 
    else 
    {
        // invalid
    }

以下是我在我的程序中为这个不准确的目标使用的确切代码:

public bool IsInsideTimeframe(DateTime firstStart, DateTime firstEnd, DateTime secondStart, DateTime secondEnd)
{
    bool isInside;

    if (firstStart.Ticks >= secondStart.Ticks && firstEnd.Ticks <= secondEnd.Ticks)
        isInside = true;
    else
        isInside = false;

    return isInside;
}

假设您有两个时间范围,一个在 11:00-14:00 之间,第二个在 10:00-15:00 之间。为了检查第一个时间跨度是否在第二个时间跨度内,您可以按以下方式使用该函数: IsInsideTimeframe(11:00, 14:00, 10:00, 15:00)

您可以简单地在您希望验证的两个日期上 运行 此函数,将 "allowed time span" 作为给定的 "second" 日期。

从单身开始吧value

private static bool WithinSpan(DateTime value, TimeSpan from, TimeSpan to) =>
  value >= value.Date.Add(from) && value <= value.Date.Add(to);

现在我们可以用两个 values 实现相同的功能:

private static bool WithinSpan(DateTime startDate, DateTime endDate,
                               TimeSpan from, TimeSpan to) =>
// startDate <= endDate &&  // you may want to add this condition as well 
   startDate >= startDate.Date.Add(from) && startDate <= startDate.Date.Add(to) &&
     endDate >= startDate.Date.Add(from) &&   endDate <= startDate.Date.Add(to);

演示:

  TimeSpan allowedStart = new TimeSpan(08, 00, 0);
  TimeSpan allowedEnd = new TimeSpan(20, 00, 0);

  (DateTime, DateTime)[] tests = new (DateTime, DateTime)[] {
    (new DateTime(2020, 1, 30, 19, 10, 0), new DateTime(2020, 1, 30, 19, 20, 0)),
    (new DateTime(2020, 1, 30, 19, 50, 0), new DateTime(2020, 1, 30, 20, 15, 0)),
    (new DateTime(2020, 1, 30, 20, 10, 0), new DateTime(2020, 1, 30, 20, 35, 0)),
    (new DateTime(2020, 1, 30, 23, 50, 0), new DateTime(2020, 1, 31,  0, 35, 0)),
    (new DateTime(2020, 1, 31,  7, 50, 0), new DateTime(2020, 1, 31,  8, 15, 0)),
  };

  Func<DateTime, DateTime, string> within = 
    (t1, t2) => $"{(WithinSpan(t1, t2, allowedStart, allowedEnd) ? "Yes" : "No")}";

  string report = string.Join(Environment.NewLine, tests
    .Select(test => $"{test.Item1:yyyy-MM-dd HH:mm:ss} .. {test.Item2:yyyy-MM-dd HH:mm:ss} : {within(test.Item1, test.Item2)}"));

  Console.Write(report);

结果:

2020-01-30 19:10:00 .. 2020-01-30 19:20:00 : Yes
2020-01-30 19:50:00 .. 2020-01-30 20:15:00 : No
2020-01-30 20:10:00 .. 2020-01-30 20:35:00 : No
2020-01-30 23:50:00 .. 2020-01-31 00:35:00 : No
2020-01-31 07:50:00 .. 2020-01-31 08:15:00 : No

编辑:

详细版为

private static bool WithinSpan(DateTime startDate, DateTime endDate,
                               TimeSpan from, TimeSpan to) {
  // Empty Period
  if (startDate > endDate)
    return false;

  // [from..to] within single day
  if (to >= from)
    return startDate >= startDate.Date.Add(from) && startDate <= startDate.Date.Add(to) &&
           endDate >= startDate.Date.Add(from) && endDate <= startDate.Date.Add(to);

  // [from..midnight..to]
  if (startDate.Day == endDate.Day)
    return startDate >= startDate.Date.Add(from) || endDate <= endDate.Date.Add(to);
  else {
    to = to.Add(TimeSpan.FromDays(1));

    return startDate >= startDate.Date.Add(from) && startDate <= startDate.Date.Add(to) &&
           endDate >= startDate.Date.Add(from) && endDate <= startDate.Date.Add(to);
  }
}

删除空句号,并将 from > to TimeSpan 视为包含午夜。

演示:

  // from 22:00 to midnight and then up to 06:00
  TimeSpan allowedStart = new TimeSpan(22, 00, 00);
  TimeSpan allowedEnd   = new TimeSpan(06, 00, 00);

  (DateTime, DateTime)[] tests = new (DateTime, DateTime)[] {
    (new DateTime(2020, 1, 30, 19, 10, 0), new DateTime(2020, 1, 30, 19, 20, 0)),
    (new DateTime(2020, 1, 30, 19, 50, 0), new DateTime(2020, 1, 30, 20, 15, 0)),
    (new DateTime(2020, 1, 30, 20, 10, 0), new DateTime(2020, 1, 30, 20, 35, 0)),
    (new DateTime(2020, 1, 30, 23, 50, 0), new DateTime(2020, 1, 31,  0, 35, 0)),
    (new DateTime(2020, 1, 30, 23, 00, 0), new DateTime(2020, 1, 30, 23, 35, 0)),
    (new DateTime(2020, 1, 30,  3, 00, 0), new DateTime(2020, 1, 30,  4, 00, 0)),
    (new DateTime(2020, 1, 31,  4, 50, 0), new DateTime(2020, 1, 31,  8, 15, 0)),
  };

  Func<DateTime, DateTime, string> within =
    (t1, t2) => $"{(WithinSpan(t1, t2, allowedStart, allowedEnd) ? "Yes" : "No")}";

  string report = string.Join(Environment.NewLine, tests
    .Select(test => $"{test.Item1:yyyy-MM-dd HH:mm:ss} .. {test.Item2:yyyy-MM-dd HH:mm:ss} : {within(test.Item1, test.Item2)}"));

  Console.Write(report);

结果:

2020-01-30 19:10:00 .. 2020-01-30 19:20:00 : No
2020-01-30 19:50:00 .. 2020-01-30 20:15:00 : No
2020-01-30 20:10:00 .. 2020-01-30 20:35:00 : No
2020-01-30 23:50:00 .. 2020-01-31 00:35:00 : Yes
2020-01-30 23:00:00 .. 2020-01-30 23:35:00 : Yes
2020-01-30 03:00:00 .. 2020-01-30 04:00:00 : Yes
2020-01-31 04:50:00 .. 2020-01-31 08:15:00 : No

下一次编辑:
神奇的缩短版本:

if (startDate > endDate) {
  return false;
}
if (startDate.Day == endDate.Day && to < from) {
  return startDate >= startDate.Date.Add(from) || endDate <= endDate.Date.Add(to);
}
if (to < from) {
  to = to.Add(TimeSpan.FromDays(1));
}
return startDate >= startDate.Date.Add(from) && endDate <= startDate.Date.Add(to);