java - 获得重叠时间的最简单方法

标签 java validation date

我面临着一个让我头晕的验证。 我有一个对象,我现在称之为“Downtime”,它看起来像这样:

public class Downtime {

  /** The start date of the downtime. */
  private ZonedDateTime downtimeFrom;

  /** The end date of the downtime. */
  private ZonedDateTime downtimeTo;

  /**
   * Gets the downtime from.
   *
   * @return the downtime from
   */
  public ZonedDateTime getDowntimeFrom()
  {
    return downtimeFrom;
  }

  /**
   * Gets the downtime to.
   *
   * @return the downtime to
   */
  public ZonedDateTime getDowntimeTo()
  {
    return downtimeTo;
  }

  /**
   * Sets the downtime from.
   *
   * @param downtimeFrom the new downtime from
   */
  protected void setDowntimeFrom( ZonedDateTime downtimeFrom )
  {
    this.downtimeFrom = downtimeFrom;
  }

  /**
   * Sets the downtime to.
   *
   * @param downtimeTo the new downtime to
   */
  protected void setDowntimeTo( ZonedDateTime downtimeTo )
  {
    this.downtimeTo = downtimeTo;
  }
}

当我通过 CRUD 实现创建新的停机时间时,我已经验证了开始时间实际上早于结束时间等。
现在我必须添加验证,即当我创建新的停机时间时,它不会干扰已创建的停机时间。这意味着新停机时间的开始日期尚不存在处于另一个停机时间中。 (在已创建的停机时间的开始和结束之间)。

所以我现在这样做的方式是这样的,因为我在本地化方面对面向日期/时间的事情很糟糕,所以我现在这样做的方式是这样的:

private boolean isNewDowntimeValid(Downtime newDowntime, List<Downtime> createdDowntimes){
  // let's just assume I already filtered out that the list only contains the same day. That's actually pretty easy.
  List<ZonedDateTime> dateRange = new LinkedList<>();
  ZonedDateTime newTime = newDowntime.getDowntimeFrom();

  for(Downtime downtime : createdDowntimes){
    ZonedDateTime downtimeStart = downtime.getDowntimeFrom();
    ZonedDateTime downtimeEnd = downtime.getDowntimeTo();

    for(ZonedDateTime start = downtimeStart; !start.isAfter(downtimeEnd); start = start.plusHours(1)){
      dateRange.add(start);
    }
  }
  if(dateRange.contains(newTime)){
    return false;
  }
  return true;
}

这里的代码是我凭空写出来的,因此可能存在语法错误,但我认为您可以明白我想要的内容。

现在回答我的问题。
上面的代码看起来像是一个开销,我想知道如何用更少的代码更快地验证它。

编辑: 让我提供一个清晰的示例

我有一个这样的停机时间列表:

List<Downtime> createdDowntimes = [
{
  start:2015-01-10T00:00Z,
  end:2015-01-10T02:00Z
},
{
  start:2015-01-10T04:00Z,
  end:2015-01-10T06:00Z
},
{
  start:2015-01-10T07:00Z,
  end:2015-01-10T09:00Z
}
]

然后我就有了我想要创建的新停机时间:

Downtime newDowntime = 
{ 
  start:2015-01-10T05:00Z,
  end:2015-01-10T05:30Z
}

在此示例中,新的停机时间无效,因为它实际上处于另一个已创建的停机时间段内。

希望它能让事情变得更加清晰。

编辑2: 虽然标记的重复项包含原因并提供了解决方案,但我也想感谢 Hugo,他考虑到我的标准,提供了很好的答案。

这是我准备的另一个解决方案,它提供了许多更详细的异常和信息处理

/*
 * Collision 1 = the new downtime starts before the created ones but ends in their span
 * Collision 2 = the new downtime starts after created ones and also ends after their span
 * Collision 3 = the new downtime starts after created ones and ends in their span
 */
List<Downtime> collision1 = createdDowntimes.stream().filter( e -> e.getDowntimeFrom().isAfter( newTimeStart ) )
    .filter( e -> e.getDowntimeTo().isAfter( newTimeEnd ) ).collect( Collectors.toList() );

List<Downtime> collision2 = createdDowntimes.stream().filter( e -> e.getDowntimeFrom().isBefore( newTimeStart ) )
    .filter( e -> e.getDowntimeTo().isBefore( newTimeEnd ) ).collect( Collectors.toList() );

List<Downtime> collision3 = createdDowntimes.stream().filter( e -> e.getDowntimeFrom().isBefore( newTimeStart ) )
    .filter( e -> e.getDowntimeTo().isAfter( newTimeEnd ) ).collect( Collectors.toList() );

请记住,我的“解决方案”是众多解决方案之一,而且在性能方面也相当密集,因为流是繁重的操作。因此,如果您不需要确切知道有多少碰撞以及它们碰撞的原因,请考虑 Hugo 的答案。

最佳答案

考虑到:

Meaning the start date of the new downtime is not already existent and is not in another downtime. (between the start and end of an already created downtime).

在这种情况下,您需要将新 DowntimestartDate (downtimeFrom) 与所有现有 Downtime的:

private boolean isNewDowntimeValid(Downtime newDowntime, List<Downtime> createdDowntimes) {
    // the start of the new downtime
    ZonedDateTime newStartTime = newDowntime.getDowntimeFrom();

    for (Downtime downtime : createdDowntimes) {
        ZonedDateTime downtimeStart = downtime.getDowntimeFrom();
        ZonedDateTime downtimeEnd = downtime.getDowntimeTo();

        if (newStartTime.equals(downtimeStart)) {
            // start date of new downtime already exists
            return false;
        }

        // start date of new downtime is in the existent downtime
        // (existent startDate < new startDate and new startDate < existent endDate)
        if (downtimeStart.isBefore(newStartTime) && newStartTime.isBefore(downtimeEnd)) {
            return false;
        }
    }

    // no invalid cases found, it's valid
    return true;
}

注意: 在此代码中,如果新的 startDate 等于现有 的结束时间,则 Downtime有效停机时间。如果您不希望这样,可以将第二个 if 更改为:

if (downtimeStart.isBefore(newStartTime) && (! newStartTime.isAfter(downtimeEnd))) {
    return false;
}

关于java - 获得重叠时间的最简单方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44066779/

相关文章:

java - ProtocolException:流的意外结束

java - 无法从另一个类更改 Imageview 的图像

date - 如何使用 Chrono crate 在 Rust 中获取当前工作日?

javascript - Jquery 日期规则在 Firefox 和 IE 中不起作用

java - 如何通过java中的构造函数验证输入

mysql - 在mysql中根据用户ID获取购买编号

c# - C# 中的日期时间

java - 保存图表时 GWT Autobean 卡住

java - 在 Java Web 应用程序中更改数据库连接字符串

objective-c - 更具体的 NSNumberFormatter 失败行为