【问题标题】:How to compare two java.time.Period in java 8?如何比较 Java 8 中的两个 java.time.Period?
【发布时间】:2017-05-10 06:58:34
【问题描述】:

如何比较 java 8 中的两个句点?

例如

Period one = Period.of(10,0,0);
Period two = Period.of(8,0,0);

在这种情况下,一大于二。

【问题讨论】:

  • 周期不可比较。这是有原因的。例如:一个月的周期大于还是小于 30 天的周期?答案是视情况而定。您可以将两个句点添加到给定的 LocalDate,并查看两个 LocalDate 中哪个更大。但结果可能取决于您从哪个 LocalDate 开始。
  • @JBNizet 完全正确的评论并更正 Period 不是也不应该具有可比性,但是 JSR-310 设计者允许/定义了一个具有疯狂定义和实现的方法 isNegative()规避“P1M-30D”问题。病得很重。

标签: java date java-8 period


【解决方案1】:

JB Nizet 说得对。 您无法比较 Periods,根据 Period 类中的 java doc,Java 中提供了与 Period (Duration) 类似的类,您可以根据您的业务需求使用它。

“当添加到 ZonedDateTime 时,持续时间和周期对夏令时的处理有所不同。持续时间将添加精确的秒数,因此一天的持续时间始终是 24 小时。相比之下,周期会增加一个概念日,尽量保持当地时间。”

Period period = Period.of(10, 0, 0);
Period period2 = Period.of(10, 0, 0);

// No compareTo method in period
System.out.println(period.compareTo(period2));

Duration duration = Duration.ofDays(3);
Duration duration2 = Duration.ofDays(3);

// Can compare durations as it gives you the exact time
System.out.println(duration.compareTo(duration2));

【讨论】:

    【解决方案2】:

    由于一个月的标准长度未定义,在一般情况下比较两个Period 对象确实没有意义。

    但是,在许多情况下,您可以很好地使用类似于下面的实现。合约会和compareTo()的合约类似:

    public int comparePeriodsApproximately(Period p1, Period p2) {
        return period2Days(p1) - period2Days(p2);
    }
    
    private int period2Days(Period p) {
        if (p == null) {
            return 0;
        }
        return (p.getYears() * 12 + p.getMonths()) * 30 + p.getDays();
    }
    

    【讨论】:

    • Kotlin 扩展版本:private fun Period.toDayEstimate():Int = years * 12 + months * 30 + days
    【解决方案3】:

    如果您有monthsyears 的周期,您可以执行以下操作:

    Period periodOfMonths = Period.ofMonths(16);
    Period periodOfYears = Period.ofYears(1);
    
    // Check if period of months is ghreather that the period of years
    System.out.println(periodOfMonths.toTotalMonths() > periodOfYears.toTotalMonths()); 
    

    【讨论】:

    • toTotalMonths 不考虑“天”
    【解决方案4】:

    这可以通过从LocalDate 借用的正确compareTo() 方法来完成。

    public static int compareTo(final Period first, final Period second)
    {
        final LocalDate now = LocalDate.now();
        return now.plus(first).compareTo(now.plus(second));
    }
    

    【讨论】:

    • 请注意,对于某些时期,这种方法会在不同的日子给出不同的结果。我认为这是一种令人不快且出乎意料的行为。有人会说是越野车。
    • 根据当前日期给出不同结果的方法值得一票。
    【解决方案5】:

    我喜欢 Martin Cassidy 的回答,但建议使用硬编码的 LocalDate 而不是 LocalDate.now,例如 LocalDate.MIN

    public static int compareTo(final Period first, final Period second)
    {
        return LocalDate.MIN.plus(first).compareTo(LocalDate.MIN.plus(second));
    }
    

    【讨论】:

    • 如果任一周期可能为负数,这将导致下溢错误。例如,您可以尝试LocalDate.EPOCH。除此之外,该方法会产生可能难以理解和预测但可重现的结果。
    【解决方案6】:

    这个应该是防弹的。好用吗?

    我声称,从 2097 年 2 月 1 日开始,您从给定的年数和月数中获得的天数尽可能少,因为您首先数的是 2 月(28 天),并且需要很长时间才能获得两个连续 31 天(7 月和 8 月),并且在您遇到闰年(2104 年)之前会更长。如果计数达到那么远,2200 和 2300 也是非闰年。相反,从同一日期倒数时,您会得到尽可能多的天数。您从 2 个月 @ 31 天(1 月和 12 月)开始计算。你遇到的第一个二月是 2096 年,闰年,所以是 29 天。 2000 年是闰年。

    所以我的诀窍是从提到的日期开始计算两个时期之间的差异。如果计数一致认为差异是正数(或负数),那么无论我们从哪一天开始计数,two(或one)都将始终更长。

    在某些情况下,计数不一致。然后我拒绝打电话给更长的时间。

        Period one = Period.of(10, 0, 0);
        Period two = Period.of(8, 0, 0);
        
        if (one.normalized().equals(two.normalized())) {
            System.out.println("They are the same.");
        } else {
            Period diff = two.minus(one);
            
            LocalDate anchor = LocalDate.of(2097, Month.FEBRUARY, 1);
            
            LocalDate plusDiff = anchor.plus(diff);
            LocalDate minusDiff = anchor.minus(diff);
            if (plusDiff.isAfter(anchor) && minusDiff.isBefore(anchor)) {
                System.out.println("Two is greater (unambiguously)");
            } else if (plusDiff.isBefore(anchor) && minusDiff.isAfter(anchor)) {
                System.out.println("One is greater (unambiguously)");
            } else {
                System.out.println("Cannot decide");
            }
        }
    

    在这种情况下的输出(使用问题中的句点):

    一个更大(明确)

    我在第一次比较中使用的normalized 方法在年份和月份之间进行转换,确保月份在 -11 到 +11 的区间内并且与年份具有相同的符号(除非年份为 0)。这可以毫不含糊地做到,因为一年总是有 12 个月。

    您可以对其进行细化以报告一个时期长于或等于另一个时期。例如,如果 one 是一个月,two 是 31 天,我们知道 two 至少和 one 一样长,尽管我们无法确定它是否也严格 更长。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-12
      • 2016-05-05
      相关资源
      最近更新 更多