Java 中求两日期的差量

本文简短地介绍java 中多种方式求两个日期的差量。

使用java.util.Date

首先我们使用java api中的java.util.Date类,计算两日期之间天数:

@Test
public void givenTwoDatesBeforeJava8_whenDifferentiating_thenWeGetSix()
  throws ParseException {
  
    SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH);
    Date firstDate = sdf.parse("06/24/2017");
    Date secondDate = sdf.parse("06/30/2017");
 
    long diffInMillies = Math.abs(secondDate.getTime() - firstDate.getTime());
    long diff = TimeUnit.DAYS.convert(diffInMillies, TimeUnit.MILLISECONDS);
 
    assertEquals(diff, 6);
}

通过getTime方法获得日期的毫秒数,然后通过TimeUnit转换为天数。

使用java 8 中java.time包中Period和Duration

结合Period 和 Duration使用 LocalDate, LocalDateTime 计算差更直观,它们表示日期(不带或带时间):

LateDate:

@Test
public void givenTwoDatesInJava8_whenDifferentiating_thenWeGetSix() {
    LocalDate now = LocalDate.now();
    LocalDate sixDaysBehind = now.minusDays(6);
 
    Period period = Period.between(now, sixDaysBehind);
    int diff = period.getDays();
 
    assertEquals(diff, 6);
}

LocalDateTime:

@Test
public void givenTwoDateTimesInJava8_whenDifferentiating_thenWeGetSix() {
    LocalDateTime now = LocalDateTime.now();
    LocalDateTime sixMinutesBehind = now.minusMinutes(6);
 
    Duration duration = Duration.between(now, sixMinutesBehind);
    long diff = Math.abs(duration.toMinutes());
 
    assertEquals(diff, 6);
}

使用java.time.temporal.ChronoUnit

java 8 中时间API表示日期作为单元,如秒、天等,在TemporalUnit接口中定义。每个单元提供between方法实现,用于计算两个temporal对象之间的时间量。举例,计算LocalDateTime之间秒数:

@Test
public void givenTwoDateTimesInJava8_whenDifferentiatingInSeconds_thenWeGetTen() {
    LocalDateTime now = LocalDateTime.now();
    LocalDateTime tenSecondsLater = now.plusSeconds(10);
 
    long diff = ChronoUnit.SECONDS.between(now, tenSecondsLater);
 
    assertEquals(diff, 10);
}

ChronoUnit通过实现TemporalUnit 接口提供一组具体时间单元,强烈建议通过静态方式导入ChronoUnit枚举值使代码更直观:

import static java.time.temporal.ChronoUnit.SECONDS;
 
// omitted
long diff = SECONDS.between(now, tenSecondsLater);

我们也可以传递两个兼容的temporal对象至between方法中,甚至ZonedDateTime.ZonedDateTime的强大之处在于,即使它们被设置为不同的时区,计算也能正常工作:

@Test
public void givenTwoZonedDateTimesInJava8_whenDifferentiating_thenWeGetSix() {
    LocalDateTime ldt = LocalDateTime.now();
    ZonedDateTime now = ldt.atZone(ZoneId.of("America/Montreal"));
    ZonedDateTime sixMinutesBehind = now
      .withZoneSameInstant(ZoneId.of("Asia/Singapore"))
      .minusMinutes(6);
     
    long diff = ChronoUnit.MINUTES.between(sixMinutesBehind, now);
     
    assertEquals(diff, 6);
}

使用java.time.temporal.Temporal until()方法

任何Temporal对象,如LocalDate or ZonedDateTime,提供了until方法用于计算日期差:

@Test
public void givenTwoDateTimesInJava8_whenDifferentiatingInSecondsUsingUntil_thenWeGetTen() {
    LocalDateTime now = LocalDateTime.now();
    LocalDateTime tenSecondsLater = now.plusSeconds(10);
 
    long diff = now.until(tenSecondsLater, ChronoUnit.SECONDS);
 
    assertEquals(diff, 10);
}

Temporal#until 和 TemporalUnit#between 两者api不同,但实现功能相同,所谓殊途同归。

总结

本文介绍了多种方式计算两个日期之间差量。当然也可以通过第三方时间库实现,如JodaTime、Date4J,读者可以自己扩展。