Java 8日期时间:检查时间段是否包含特定日期

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

只需检查二月份的最后一天日期。 - Roshan
这是一个关于Joda Time还是Java 8 Time API的问题吗?答案可能不同... - assylias
@assylias Java 8。谢谢 :-) - YvesHendseth
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()));

谢谢!我明天会测试它 :-) - YvesHendseth

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
    }

2
当到期年份是闰年的2月29日时,它将会失败。 - YvesHendseth
真的,同时检查两个是丑陋的。:-/ - Claes Mogren

1

我喜欢以测试用例的形式思考。什么样的 beginDateendDate 值会导致该方法返回 true 或 false?

例如,如果它们在同一年内怎么办?也许两个值都在 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;
    }
}

1
你尝试过使用toDateTimeAtStartOfDaytoDateTimeLocalDateMonthDay转换为DateTime吗?请注意,当年份不是闰年时,需要测试结果是否为真。

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

你确定这样写没问题吗:nearestLeapYear = (yearTo / 4) * 4;?比如说1900年就不是闰年...使用内置方法可能比手动计算更好... - assylias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接