如何计算出一段时间跨度在多个时间跨度的范围内

时间:2017-09-11 18:39:17

标签: c# linq timespan

假设我有两个时间范围

07.00.00 - 18.59.59
19.00.00 - 06.59.59

现在我有一个时间跨度范围,我们称之为持续时间。

public class Duration {
  public TimeSpan StartingTime{get; set;}
  public TimeSpan EndingTime{get; set;}
}

初始化为

StartingTime 05.00.00
EndingTime 06.00.00

我想生成一种方法,其中我在时间跨度范围列表中传递,以及一个新的Timespan,它将返回正确的时间范围。

我尝试修改Check if a date range is within a date range for TimeSpan,同时尝试将我的时间跨度范围转换为日期时间,但导致失败(不返回任何内容)。

我也尝试过

var fee = fees.Where(a=> parking.StartTime <= a.EndingTime && parking.EndTime >= a.StartingTime).First();

停车位是持续时间等级,费用将是一个时间范围列表。

我也看了c# check if a timespan range is between timespan range and how many hours,但这也没有导致工作解决方案。

我已经非常沮丧,无法想出解决方案。

编辑:以@NetMage为例,有一个案例,19.40 - 20.35会导致失败,我修复了另外一个条件。

var fee = fees
                .First(r => (r.StartingTime <= r.EndingTime) ?
                        (r.StartingTime <= parking.StartTime && parking.StartTime <= r.EndingTime) :
                        (parking.StartTime <= r.EndingTime) ?
                        (r.StartingTime <= parking.StartTime + oneDay && parking.StartTime <= r.EndingTime)
                        : (r.StartingTime <= parking.StartTime + oneDay && parking.StartTime <= r.EndingTime + oneDay)
                        );

EDIT2 //

现在我仍然遇到检查endTime重叠的问题。尝试使用NetMage告诉的方法,但到目前为止没有什么

EDIT3 //

要检查结束部分,它将是

fees.First(r => (r.StartingTime <= r.EndingTime) ?
                        (r.EndingTime >= end && end >= r.StartingTime) :
                        (end >= r.StartingTime) ?
                        (r.EndingTime >= end + oneDay && end >= r.StartingTime) :
                        (r.EndingTime >= end + oneDay && end >= r.StartingTime + oneDay)
                        );

最后检查一下它是否重叠:

fees.First(r => r.StartingTime >= start && r.EndingTime <= end);

2 个答案:

答案 0 :(得分:1)

假设您的时间范围列表是List<Duration>,您可以这样查询:

var OneDay = new TimeSpan(24,0,0);

var startAns = ranges.First(r => {
    var rEndingTime = (r.StartingTime > r.EndingTime) ? r.EndingTime + OneDay : r.EndingTime;
    return (r.StartingTime <= parking.StartingTime && parking.StartingTime <= rEndingTime) ||
           (r.StartingTime <= parking.StartingTime + OneDay && parking.StartingTime + OneDay <= rEndingTime);
});

var endAns = ranges.First(r => {
    var rEndingTime = (r.StartingTime > r.EndingTime) ? r.EndingTime + OneDay : r.EndingTime;
    return (r.StartingTime <= parking.EndingTime && parking.EndingTime <= rEndingTime) ||
           (r.StartingTime <= parking.EndingTime + OneDay && parking.EndingTime + OneDay <= rEndingTime);
});

我将上面的原始(基于概念)Let的答案替换为上述答案,同时使用了OP使用的漂亮First变体。

var ans = ranges.Select(r => new { r, r.StartingTime, EndingTime = (r.StartingTime > r.EndingTime ? r.EndingTime + OneDay : r.EndingTime)})
                .Where(r => (r.StartingTime <= parking.StartingTime && parking.StartingTime <= r.EndingTime) ||
                            (r.StartingTime <= parking.StartingTime+OneDay && parking.StartingTime+OneDay <= r.EndingTime))
                .Select(r => r.r).First();

答案 1 :(得分:0)

已更新,可解决期间翻转至第二天的问题

使用TimeSpan非常简洁,但是如果一个句点滚动到第二天,这将使查询变得非常复杂和笨拙。

通过将涵盖两天的期间分为两个期间,可以轻松解决此问题:

00.00.00 - 06.59.59 //off peak 1
07.00.00 - 18.59.59 //peak
19.00.00 - 23.59.59 //off peak 2

在您的示例中,您有两种可能需要处理的案例:

  1. 停车时间完全在一个费用期间 - 您的查询处理。
  2. 停车时间与两个(或更多个时段)重叠 - 您的查询将无法与此相符,因为您正在使用.First()
  3. 要获得更准确的答案,您需要指定所需的行为。关于这些可能适合的机会,这里有两种可能性:

    此查询将返回停车启动

    中的费用期限:

    var fee = fees.Where(period => parking.StartTime >= period.StartingTime && parking.StartTime <= period.EndingTime).First();

    此查询将返回停车结束

    中的费用期限:

    var fee = fees.Where(period => parking.EndTime >= period.StartingTime && parking.EndTime <= period.EndingTime).First();