【问题标题】:Check if at least two hours have been spent within a time range, when given two dates当给定两个日期时,检查一个时间范围内是否至少花费了两个小时
【发布时间】:2014-12-16 08:45:00
【问题描述】:

我有两个日期,我需要检查在这些日期的凌晨 1 点到 5 点之间是否至少连续花费了 2 个小时。

例如,如果 dateFrom 是 2014-05-05 17:00:00 并且 dateTo 是 2014-05-06 6:00:00,这意味着在这两个日期之间的凌晨 1 点到 5 点之间连续花费了 2 个小时.

时间(凌晨 1 点和凌晨 5 点)是可配置的,而不是硬编码的 - 因此,表示为变量。

这是我到目前为止所做的:

//The timeFromResidencyRange and timeToResidencyRange are 1AM and 5AM respectively.  
//They are collected from two `DateTimePicker` .NET controls.

timeFromResidencyRange = dtpTime1.Value; //For testing, it is 1AM (but can be any time)
timeToResidencyRange = dtpTime2.Value; //For testing, it is 5AM (but can be any time)

private bool IsWithinResidencyRange(DateTime dateFrom, DateTime dateTo, double consecutiveHours)
{
    var totalDiff = (dateTo - dateFrom).TotalHours;

    if (totalDiff < consecutiveHours)
    {
        return false;
    }

    DateTime desireFromDate = new DateTime();

    if ((dateFrom.TimeOfDay.Hours < timeToResidencyRange.Hour) || (dateFrom.TimeOfDay.Hours == timeToResidencyRange.Hour && dateFrom.TimeOfDay.Minutes == timeToResidencyRange.Minute && dateFrom.TimeOfDay.Seconds == 0))
    {
        desireFromDate = dateFrom;
    }
    else
    {
        desireFromDate = dateFrom.AddDays(1);
    }

    var endOfDesireDate = new DateTime(desireFromDate.Year,
                                       desireFromDate.Month,
                                       desireFromDate.Day, timeToResidencyRange.Hour, timeToResidencyRange.Minute, 0);

    if ((endOfDesireDate - dateFrom).TotalHours < consecutiveHours)
    {
        endOfDesireDate = endOfDesireDate.AddDays(1);
    }
    else
    {
        return true;
    }

    desireFromDate = endOfDesireDate.AddHours(-((timeToResidencyRange - timeFromResidencyRange).TotalHours));

    return (dateTo - desireFromDate).TotalHours >= consecutiveHours;
}

作为测试用例,我进行了以下操作:

IsWithinResidencyRange(DateTime.Parse("2014-05-05 1:00:00"), DateTime.Parse("2014-05-05 5:00:00"), (double)amountOfHours); //true
IsWithinResidencyRange(DateTime.Parse("2014-05-05 2:30:00"), DateTime.Parse("2014-05-05 5:00:00"), (double)amountOfHours); //true
IsWithinResidencyRange(DateTime.Parse("2014-05-05 1:00:00"), DateTime.Parse("2014-05-06 17:00:00"), (double)amountOfHours); //true
IsWithinResidencyRange(DateTime.Parse("2014-05-05 15:00:00"), DateTime.Parse("2014-05-05 1:59:00"), (double)amountOfHours); //false
IsWithinResidencyRange(DateTime.Parse("2014-05-05 15:00:00"), DateTime.Parse("2014-05-05 2:59:00"), (double)amountOfHours); //false
IsWithinResidencyRange(DateTime.Parse("2014-05-05 15:00:00"), DateTime.Parse("2014-05-06 3:00:00"), (double)amountOfHours); //true
IsWithinResidencyRange(DateTime.Parse("26/08/2013 17:17:13"), DateTime.Parse("26/08/2013 20:20:30"), (double)amountOfHours); //false
IsWithinResidencyRange(DateTime.Parse("26/08/2013 17:17:13"), DateTime.Parse("29/08/2013 20:20:30"), (double)amountOfHours); //true
IsWithinResidencyRange(DateTime.Parse("2014-05-04 1:00:00"), DateTime.Parse("2014-05-06 5:00:00"), (double)amountOfHours); //true
IsWithinResidencyRange(DateTime.Parse("2014-05-05 1:00:00"), DateTime.Parse("2014-05-15 5:00:00"), (double)amountOfHours); //true
IsWithinResidencyRange(DateTime.Parse("2014-05-05 1:00:00"), DateTime.Parse("2014-06-05 5:00:00"), (double)amountOfHours); //true
IsWithinResidencyRange(DateTime.Parse("2014-05-05 3:00:00"), DateTime.Parse("2014-05-05 5:00:00"), (double)amountOfHours); //true
IsWithinResidencyRange(DateTime.Parse("2014-05-05 3:00:00"), DateTime.Parse("2014-05-05 4:59:00"), (double)amountOfHours); //false
IsWithinResidencyRange(DateTime.Parse("2014-05-05 1:25:00"), DateTime.Parse("2014-05-05 2:25:00"), (double)amountOfHours); //false
IsWithinResidencyRange(DateTime.Parse("2014-05-05 1:25:00"), DateTime.Parse("2014-05-05 3:25:00"), (double)amountOfHours); //true

右边的 cmets 应该是预期的结果 - 在这个集合中,第 6 个失败了,但我怀疑其他的工作是巧合 - 否则他们会全部工作,或者全部失败。

有人知道是什么原因造成的吗?

【问题讨论】:

  • 你的哪些测试失败了?
  • 在该集合中,第 6 个失败了,但我怀疑其他人的工作是巧合 - 否则他们会全部工作,或者全部失败。
  • 能否请您添加 1AM 和 5AM 变量的声明?
  • 什么是timeToResidencyRange?如果您可以在代码中添加一些 cmets 来解释可能对我们有所帮助的逻辑
  • 你们说的都是对的——很抱歉。现在编辑它。

标签: c# .net date datetime


【解决方案1】:

好吧,抛开语法,真相是什么:

A: Period Begin 1AM;
B: Period End   5AM;
a-b range between a Date1 and b Date2

在 (A-B) 内连续两个小时:

if
 (
  (
   a <= B - 2h
   OR
   b >= A + 2h
  )
  AND
  (b-a) >= 2h
 )
 bool = true
 else
 bool = false

你能测试一下吗?

    DateTime A = DateTime.Parse("1900-01-01 01:00:00");
    DateTime B = DateTime.Parse("1900-01-01 05:00:00");
    int amountOfHours = 2;

public bool IsWithinResidencyRange(DateTime a, DateTime b, double c)
{
if ((b - a).TotalHours >= c 
&& (a.TimeOfDay.Hours <= this.B.TimeOfDay.Hours - c 
||  b.TimeOfDay.Hours >= this.A.TimeOfDay.Hours + c))
{
return true;
}
//else
return false;
}

【讨论】:

  • 我已经尝试了代码,但它在以下测试中失败了:IsWithinResidencyRange(DateTime.Parse("2013-08-26 17:17:13"), DateTime.Parse("2013-08-26 20:20:30"), (double)amountOfHours); //falseIsWithinResidencyRange(DateTime.Parse("2013-08-26 17:17:13"), DateTime.Parse("2013-08-29 20:20:30"), (double)amountOfHours); //true
  • 感谢您确认此格式无效。我的对他们也失败了。忽略这两行,我得到了预期的结果......我认为:)
  • 精心设计的答案!很高兴看到有人在思考逻辑而不是仅仅编写代码。
【解决方案2】:

考虑到这个问题,我认为它可以用更少的逻辑来解决。涂鸦了一下并考虑了一下,我将解决这个问题如下;

编辑:更新代码以检查 GIVEN 范围的日期中的所有可能范围。 EDIT2:现在返回给定范围内的出现次数。

private int IsWithinResidencyRange(DateTime dateFrom, DateTime dateTo, double consecutiveHours){

    var dates = new List<DateTime>();
    for (var date = dateFrom.Date; date <= dateTo; date = date.AddDays(1))
        dates.Add(date);

    var occurances = 0;
    foreach (var testDate in dates)
    {
        var testFrom = new DateTime(testDate.Year, testDate.Month, testDate.Day, timeFromResidencyRange.TimeOfDay.Hours, timeFromResidencyRange.TimeOfDay.Minutes,0);
        var testTo = new DateTime(testDate.Year, testDate.Month, testDate.Day, timeToResidencyRange.TimeOfDay.Hours, timeToResidencyRange.TimeOfDay.Minutes, 0);

        if (WithinFrame(dateFrom, dateTo, consecutiveHours, testFrom, testTo))
            occurances++;
    }
    return occurances;

}

private bool WithinFrame(DateTime from, DateTime to, double consecutiveHours, DateTime rangeFrom, DateTime rangeTo)
{
    if (from < rangeFrom)
    {
        return ((to - rangeFrom).TotalHours >= consecutiveHours);
    }
    else if (to > rangeTo)
    {
        return ((rangeTo - from).TotalHours >= consecutiveHours);
    }
    else
    {
        //Is completely within range.
        return ((to - from).TotalHours >= consecutiveHours);
    }
}

这基本上会检查输入的日期是否与“想要的范围”重叠。如果设置的日期在凌晨 1 点之前开始,它会检查从想要的开始到给定的结束日期至少有两个小时(或您指定的任何值)。

如果它不是在早上 5 点之前开始而是在凌晨 5 点之后结束,它会检查它从给定的开始到想要的结束至少有两个小时。

如果在范围内,请检查以小时为单位的总差异是否大于 2(或给定的任何值)。

希望这个解释足够清楚:)

【讨论】:

  • 感谢您提供的信息和代码 - 我会用一些案例对其进行测试,并让您知道结果是什么 :) 从逻辑上讲,它或多或少是我想出的,但在很大程度上更简洁的方式!
  • 我在解析时遇到了#7 和#8 的问题,但我认为这是本地格式配置。让我知道它是否有效!
  • 我刚刚尝试了上述所有情况 - 不幸的是,该函数对所有内容都返回 false。
  • 由于 timeFromResidencyRange 和 timeToResidencyRange 取自仅向用户显示时间的 DateTimePicker,因此每个的实际 DateTime 值显示为今天的日期,即凌晨 1 点和今天的日期凌晨 5 点。因此,看起来第一个 if 语句总是被输入。我怀疑这是问题所在。
  • 可能,在我的示例中,我只是将值设置为“2014-05-05 1AM”和“2014-05-05 5AM”。如果要计算它将是哪一天,那么它将需要更多的代码和逻辑(例如,如果日期跨度超过两天,它将选择上午 1 点到 5 点的时间间隔)。
猜你喜欢
  • 1970-01-01
  • 2020-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-26
相关资源
最近更新 更多