Java日期和时间(JSR 310):时间范围是否包含值而不迭代所有时间

时间:2016-04-12 07:32:58

标签: java java-time jsr310

我有一个自定义范围(〜Collection),它有2 Temporal个边界(fromto)并且可以按时间枚举这两个边界之间的所有值使用给定的TemporalUnit incrementUnitType递增。

private final Temporal_ from;
private final Temporal_ to;
private final TemporalUnit incrementUnitType; // For example Month, Day,  Minute, ...

在其中,我需要实现一个contains方法,以检查迭代该范围是否包含特定值。例如,如果它包含3月8日。以下是我想写这种方法的方法:

public boolean contains(Temporal_ value) {
    ...
    if (from.until(value, incrementUnitType) < 0
            || value.until(to, incrementUnitType) <= 0) {
        return false; // Out of bounds
    }
    // This doesn't work because 1-MAR + 1 month doesn't include 8-MAR
    return true;
}

这里进行了几次迭代:

  • from - to(incrementUnitType)
  • 1-MAR - 10-APR(1天): 1-MAR,2-MAR,3-MAR,4-MAR,...,8-APR,9-APR < / LI>
  • 1-MAR - 10-APR(1周):1-MAR,8-MAR,15-MAR,22-MAR,29-MAR,5-APR
  • 1-MAR - 10-APR(1个月):1-MAR,1-APR

在最后一种情况下,上面的代码将错误地返回8-MAR的true。通过执行for循环并检查每个可能的值,我需要编写代码才能工作:

public boolean contains(Temporal_ value) {
    ...
    if (from.until(value, incrementUnitType) < 0
            || value.until(to, incrementUnitType) <= 0) {
        return false; // Out of bounds
    }
    // This works but it kills scalability
    for (long i = 0; i < getSize(); i++) {
        Temporal_ temporal = get(i);
        if (value.equals(temporal)) {
            return true;
        }
    }
    return false;
}

这是一个可扩展性问题。有什么办法可以避免吗?

2 个答案:

答案 0 :(得分:3)

您可以使用Temporal.until方法获取结果。当它返回“两个时间段之间的完整单位数”(doc)时,您可以将此数字添加到from并查看它是否等于该值,但这不会立即生效。

long wholeAmount = from.until(value, incrementUnitType)
return value.equals(from.plus(wholeAmount, incrementUnitType));

正如您所注意到的,问题是某些时间单位并不总是相同的持续时间(例如,一个月可能是28,29,30或31天)。 untilplus可能不一致(即temporal.until(temporal.plus(1,ChronoUnit.MONTHS),ChronoUnit.MONTHS)可能为0,而我们添加了一个月)。

引用doc

  

在某些情况下,未完全定义更改字段。例如,如果   目标对象是代表1月31日的日期,然后添加   一个月不清楚。在这种情况下,该领域是   负责解决结果。通常它会选择   上一个有效日期,也就是二月份的最后一个有效日期   这个例子。

这意味着我们还应该检查wholeAmount + 1,以防整个金额被舍入。

// ... out of bound check
// ...
long wholeAmount = from.until(value, incrementUnitType)
return value.equals(from.plus(wholeAmount, incrementUnitType)) || value.equals(from.plus(wholeAmount + 1, incrementUnitType));

处理Temporal似乎很棘手所以我无法确定它是否适用于每个单元和每个时间(确保检查incrementUnitType是否与您的时间兼容)。可能有几个边缘情况需要测试。

答案 1 :(得分:2)

最有效的解决方案是每个增量单元的单独逻辑。

  • 使用DAYS,您只需检查日期是否在开始和结束之间。
  • 使用WEEKS,您可以同时拨打unserialize,减去它们并检查它是否除以7
  • 使用MONTHS,您可以检查日期是否相同

如果您可以避免使用toEpochDays()作为输入类型,我会提醒您,因为它会使处理更加困难。一个选项,如果您必须使用它来调用输入上的Temporal以允许逻辑在LocalDate.from(temporal)内部工作。