4

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

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

在其中,我需要实现一个 contains 方法,以检查遍历该范围是否包含特定值。例如,如果它包含 8 March。这是我想编写该方法的方式:

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;
}

这里有几个迭代:

  • 从 - 到 (incrementUnitType)
  • 3 月 1 日 - 4 月 10 日(1 天): 3 月 1 日、3 月 2 日、3 月 3 日、3 月 4 日、...、4 月 8 日、4 月 9 日
  • 3 月 1 日 - 4 月 10 日(1 周):3 月 1 日、3 月 8 日、3 月 15 日、3 月 22 日、3 月 29 日、4 月 5 日
  • 3 月 1 日 - 4 月 10 日(1 个月):3 月 1 日、 4 月 1 日

在最后一种情况下,上面的代码将不正确地返回 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;
}

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

4

2 回答 2

3

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

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

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

引用文档

在某些情况下,更改字段并没有完全定义。例如,如果目标对象是表示 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));

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

于 2016-04-12T10:43:31.483 回答
2

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

  • 使用 DAYS,您可以检查日期是否在开始和结束之间。
  • 使用 WEEKS,您可以同时调用toEpochDays()两者,减去它们并检查它是否除以 7
  • 使用 MONTHS,您可以检查月份中的日期是否相同

Temporal如果可以避免,我会告诫不要将其用作输入类型,因为它会使处理变得更加困难。如果您必须使用它来调用LocalDate.from(temporal)输入以允许逻辑在内部工作,这是一种选择LocalDate

于 2016-04-12T10:11:27.217 回答