c#检查时间跨度范围是否在时间范围和小时之间

假设我有3个时间范围:

07:00 - 18:00 18:00 - 23:00 23:00 - 07:00 

和代码:

 public class TimeShift { public TimeSpan Start { get; set; } public TimeSpan End { get; set; } } List shifts = new List(); 

如何检查列表中的每个项目是否在上述3个范围和多少小时之间?

例如一个TimeShift ,其中:

 Start: 07:00 End: 23:30 

那意味着16.5小时。

对于上面的例子:

 Range 1: 11 hours Range 2: 5 hours Range 3: 0.5 hours 

这是一个包含测试的解决方案:

计算器

 public class TimeSpacCalculator { public static TimeSpan GetTimeSpanIntersect(TimeShift input, TimeSpan start, TimeSpan end) { // Loopsback input from 23:59 - 00:00 if (input.Start > input.End) return GetTimeSpanIntersect(new TimeShift(input.Start, TimeSpan.FromHours(24)), start, end) + GetTimeSpanIntersect(new TimeShift(TimeSpan.FromHours(0), input.End), start, end); // Loopsback Shift from 23:59 - 00:00 if (start > end) return GetTimeSpanIntersect(input, new TimeSpan(), end) + GetTimeSpanIntersect(input, start, TimeSpan.FromHours(24)); if (input.End < start) return new TimeSpan(); if (input.Start > end) return new TimeSpan(); var actualStart = input.Start < start ? start : input.Start; var actualEnd = input.End > end ? end : input.End; return actualEnd - actualStart; } } 

 public class TimeRange : TimeShift { public TimeRange(string name, TimeSpan start, TimeSpan end) : base(start, end) { Name = name; } public string Name { get; set; } } public class TimeShift { public TimeShift(TimeSpan start, TimeSpan end) { Start = start; End = end; } public TimeSpan Start { get; set; } public TimeSpan End { get; set; } } 

测试

 [TestFixture] internal class TimShiftTests { [Test] [TestCase(7, 23.5, 11, 5, 0.5)] [TestCase(22, 7.5, 0.5, 1, 8)] public void Test(double inputStartHours, double inputEndHours, double expectedRange1Hours, double expectedRange2Hours, double expectedRange3Hours ) { var input = new TimeShift(TimeSpan.FromHours(inputStartHours), TimeSpan.FromHours(inputEndHours)); var ranges = new List { new TimeRange("Range1", TimeSpan.FromHours(7), TimeSpan.FromHours(18)), new TimeRange("Range2", TimeSpan.FromHours(18), TimeSpan.FromHours(23)), new TimeRange("Range3", TimeSpan.FromHours(23), TimeSpan.FromHours(7)) }; var result = new Dictionary(); foreach (var range in ranges) { var time = TimeSpacCalculator.GetTimeSpanIntersect(input, range.Start, range.End); result.Add(range.Name, time); Console.WriteLine($"{range.Name}: " + time.TotalHours); } result["Range1"].Should().Be(TimeSpan.FromHours(expectedRange1Hours)); result["Range2"].Should().Be(TimeSpan.FromHours(expectedRange2Hours)); result["Range3"].Should().Be(TimeSpan.FromHours(expectedRange3Hours)); } 

你使用的是错误的类型。 StartEnd应该是DateTime ,而不是TimeSpanEnd.Subtract(Start)将提供TimeSpan作为结果。 TimeSpan类型具有将提供总小时数,分钟数等的属性。

TimeSpan属性

我建议在类中添加一个方法,表示开始和结束之间的实际差异。 例如,称之为Timepan TimeDiff。 您需要包含if语句以确认TimeLater小于TimeEnd且TimeEarlier大于TimeStart。 然后’TimeDiff = TimeLater – TimeEarlier’。

TimeLater是提供范围的结束。 TimeEarlier是提供范围的开始。

如果要计算经过TimeEnd到TimeStart的时间跨度,您只需要执行检查TimeEarlier是否大于TimeLater并且具有计算差异的逻辑。 它将沿着TimeDiff =(TimeEnd – TimeEarlier)+(TimeLater – TimeEnd)

要完成时间跨度减法,请在所有时间跨度中使用.Subtract()

对最近的项目有类似的要求。 以下是我解决同一问题的经验。

根据要求,推导出以下类别。

 public interface IRange : IEquatable where T : IComparable { T Maximum { get; } T Minimum { get; } } public sealed class Range : IRange where T : IComparable { public Range(T minimum, T maximum) { Minimum = minimum; Maximum = maximum; } public T Maximum { get; private set; } public T Minimum { get; private set; } public override string ToString() { return string.Format("{{{0} - {1}}}", Minimum, Maximum); } public override int GetHashCode() { return ToString().GetHashCode(); } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) { return false; } return obj is Range && Equals((Range)obj); } public bool Equals(T other) { return object.Equals(this.ToString(), other.ToString()); } } 

由以下扩展方法支持

 public static class Range { ///  /// Create an  using the provided minimum and maximum value ///  public static IRange Of(T min, T max) where T : IComparable { return new Range(min, max); } ///  /// ///  public static bool Contains(this IRange range, T value) where T : IComparable { return range.Minimum.CompareTo(value) <= 0 && value.CompareTo(range.Maximum) <= 0; } ///  /// ///  public static bool IsOverlapped(this IRange range, IRange other, bool inclusive = false) where T : IComparable { return inclusive ? range.Minimum.CompareTo(other.Maximum) <= 0 && other.Minimum.CompareTo(range.Maximum) <= 0 : range.Minimum.CompareTo(other.Maximum) < 0 && other.Minimum.CompareTo(range.Maximum) < 0; } ///  /// ///  public static IRange GetIntersection(this IRange range, IRange other, bool inclusive = false) where T : IComparable { var start = new[] { range.Minimum, other.Minimum }.Max(); var end = new[] { range.Maximum, other.Maximum }.Min(); var valid = inclusive ? start.CompareTo(end) < 0 : start.CompareTo(end) <= 0; return valid ? new Range(start, end) : null; } } 

这是一个适合您特定要求的测试

 [TestClass] public class TimeShiftTests : MiscUnitTests { [TestMethod] public void TimeShiftDurationTest() { var shifts = new List(){ "07:00 - 18:00", "18:00 - 23:00", "23:00 - 07:00" }.Select(s => ParseShift(s)); var timeShift = "07:00 - 23:30"; var totalExpectedHours = 16.5; var input = ParseShift(timeShift); var intersections = shifts .Select(shift => shift.GetIntersection(input)) .ToArray(); intersections.Length.Should().Be(3); var actualHours = intersections.Select(range => (range.Maximum - range.Minimum).TotalHours).ToArray(); var totalActualHours = actualHours.Sum(); totalActualHours.Should().Be(totalExpectedHours); actualHours[0].Should().Be(11); actualHours[1].Should().Be(5); actualHours[2].Should().Be(0.5); } private IRange ParseShift(string period, string format = "HH:mm") { var tokens = period .Split(new[] { "to", "-" }, StringSplitOptions.RemoveEmptyEntries) .Select(s => s.Trim().Replace(" ", string.Empty)) .ToArray(); if (tokens.Length != 2) throw new FormatException("time period not well formatted"); var startDate = DateTime.ParseExact(tokens[0], format, CultureInfo.InvariantCulture); var stopDate = DateTime.ParseExact(tokens[1], format, CultureInfo.InvariantCulture); var beginTime = startDate.TimeOfDay; var endTime = stopDate.TimeOfDay; if (endTime < beginTime) { stopDate = stopDate.AddDays(1); } return Range.Of(startDate, stopDate); } } 

我想我找到了解决方案:

 private double GetHours(TimeSpan start, TimeSpan end, TimeSpan startTarget, TimeSpan endTarget) { double result = 0; if (startTarget >= start && endTarget <= end) { result = (endTarget - startTarget).TotalHours; } if ((startTarget >= start && startTarget < end) && endTarget > end) { result = (end - startTarget).TotalHours; } if (startTarget < start && (endTarget > start && endTarget <= end)) { result = (endTarget - start).TotalHours; } if (startTarget < start && endTarget > end) { result = (end - start).TotalHours; } return result; }