9

我想检查一个日期期间是否包含 2 月 29 日。

private static final MonthDay LEAP = MonthDay.of(Month.FEBRUARY, 29);

我试过了:

if (LEAP.isAfter(beginDate) && LEAP.isBefore(maturity)) {

    }

但是beginDatematurity是从类型LocalDate 所以方法.isAfter.isBefore不能使用。

例子

beginDate是 15.01.2012
maturity是 20.01.2013

在此期间,2 月 29 日存在

解决方案

我终于找到了解决方案:

for (int i = beginDate.getYear(); i <= maturity.getYear(); i++) {
    final Year year = Year.of(i);
    if (year.isLeap()) {
        if (beginDate.compareTo(LEAP.atYear(i)) <= 0 || maturity.compareTo(LEAP.atYear(i)) >= 0) {
            minMaturity.plusDays(1);
        }
    }
    return false;
}
4

5 回答 5

3

一种方法是创建一个TemporalAdjuster返回下一个 2 月 29 日的值,并检查maturity是在该日期之前还是之后。示例(未测试):

public static TemporalAdjuster nextOrSame29Feb() {
  return temporal -> {
    LocalDate input = LocalDate.from(temporal);
    if (input.isLeapYear()) {
      LocalDate feb29 = input.with(MonthDay.of(FEBRUARY, 29));
      if (!input.isAfter(feb29)) return feb29;
    }
    for (int year = input.getYear() + 1; ; year++) {
      if (Year.isLeap(year)) return LocalDate.of(year, FEBRUARY, 29);
    }
  };
}

你的代码变成:

boolean contains29Feb = !maturity.isBefore(beginDate.with(nextOrSame29Feb()));
于 2014-10-16T14:37:55.923 回答
1

我喜欢从测试用例的角度来思考。什么值beginDateendDate导致这样的方法返回真或假?

例如,如果他们在同一年怎么办?也许这两个值都在 2 月 29 日的同一侧,或者它们跨越它。

如果他们在不同的年份呢?如果这些年份是相邻的,或者中间还有其他年份怎么办?也许中间的年份都不是闰年。

在这种情况下,您可以做的是将这些情况的示例放在一起,然后编写一个方法,对其进行调整,直到所有断言都通过。

以下是您可以采取的方法。您可能想要添加闰日beginDate和/或maturity降落的情况。

public class Q26403911 {
    @Test
    public void testContainsLeapYear() throws Exception {
        Assert.assertTrue(isContainsLeapYear(LocalDate.of(1984, 2, 28), LocalDate.of(1984, 3, 1)));
        Assert.assertFalse(isContainsLeapYear(LocalDate.of(1985, 2, 28), LocalDate.of(1985, 3, 1)));
        Assert.assertFalse(isContainsLeapYear(LocalDate.of(1984, 2, 27), LocalDate.of(1984, 2, 28)));
        Assert.assertFalse(isContainsLeapYear(LocalDate.of(1984, 3, 1), LocalDate.of(1984, 3, 2)));
        Assert.assertTrue(isContainsLeapYear(LocalDate.of(1984, 2, 28), LocalDate.of(1985, 3, 1)));
        Assert.assertTrue(isContainsLeapYear(LocalDate.of(1983, 3, 1), LocalDate.of(1984, 3, 1)));
        Assert.assertFalse(isContainsLeapYear(LocalDate.of(1984, 3, 1), LocalDate.of(1985, 3, 1)));
        Assert.assertFalse(isContainsLeapYear(LocalDate.of(1983, 2, 28), LocalDate.of(1984, 2, 28)));
        Assert.assertTrue(isContainsLeapYear(LocalDate.of(1983, 3, 1), LocalDate.of(1985, 2, 28)));
        Assert.assertFalse(isContainsLeapYear(LocalDate.of(1985, 3, 1), LocalDate.of(1987, 2, 28)));
    }

    public boolean isContainsLeapYear(LocalDate beginDate, LocalDate maturity) {
        if (beginDate.getYear() == maturity.getYear())
        {
            if (!Year.isLeap(beginDate.getYear()))
            {
                return false;
            }

            if (maturity.isBefore(LocalDate.of(beginDate.getYear(), Month.FEBRUARY, 29)))
            {
                return false;
            }

            if (beginDate.isAfter(LocalDate.of(maturity.getYear(), Month.FEBRUARY, 29)))
            {
                return false;
            }

            return true;
        }
        else if (Year.isLeap(beginDate.getYear())
                        && !beginDate.isAfter(LocalDate.of(beginDate.getYear(), Month.FEBRUARY, 29)))
        {
            return true;
        }
        else if (Year.isLeap(maturity.getYear())
                        && !maturity.isBefore(LocalDate.of(maturity.getYear(), Month.FEBRUARY, 29)))
        {
            return true;
        }
        else
        {
            for (int year = beginDate.getYear() + 1; year < maturity.getYear(); year++)
            {
                if (Year.isLeap(year))
                {
                    return true;
                }
            }
        }
        return false;
    }
}
于 2014-10-16T14:56:27.097 回答
1

您是否尝试过将LocalDateand转换MonthDay为分别DateTime使用toDateTimeAtStartOfDaytoDateTime

当年份不是闰年时,您需要测试这是否会导致 true。它可能。

于 2014-10-16T12:13:13.520 回答
1

如何创建一个间隔并检查它?就像是:

    LocalDate beginDate, maturity;
    final Interval interval = new Interval(beginDate.toDateTimeAtStartOfDay(), maturity.toDateTimeAtStartOfDay());
    if (interval.contains(new DateTime(beginDate.getYear(), Month.FEBRUARY, 29, 0, 1)) ||
        interval.contains(new DateTime(maturity.getYear(), Month.FEBRUARY, 29, 0, 1))) {
        // It does
    }
于 2014-10-16T12:20:58.493 回答
0

我可以为您提供下一个解决方案,无需MonthDay

   static int LEAP = 31 + 29;  

   public static boolean conatins29Feb(LocalDate dateFrom, LocalDate dateTo)  
   {
      final int yearFrom = dateFrom.getYear(),
              yearTo = dateTo.getYear(),
              dayOfYearFrom = dateFrom.getDayOfYear(),
              dayOfYearTo = dateTo.getDayOfYear(),
              nearestLeapYear = (yearTo / 4) * 4; // nearest to `dateTo`

      return (yearFrom <= nearestLeapYear && yearTo >= nearestLeapYear)
              && (yearFrom < nearestLeapYear || dayOfYearFrom <= LEAP) 
                  && (yearTo > nearestLeapYear || dayOfYearTo >= LEAP);
   }
于 2014-10-16T15:01:37.070 回答