1. 개요
이 빠른 사용방법(예제)에서는 Java에서 두 날짜 간의 차이를 계산하는 여러 가능성을 탐색합니다.
2. 코어 자바
2.1. java.util.Date 를 사용하여 일의 차이 찾기
핵심 Java API를 사용하여 계산을 수행하고 두 날짜 사이의 일 수를 결정하는 것으로 시작하겠습니다.
@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(6, diff);
}
2.2. java.time.temporal.ChronoUnit 을 사용 하여 차이점 찾기
Java 8의 Time API는 TemporalUnit 인터페이스를 사용하여 날짜-시간 단위(예: 초 또는 일)를 나타 냅니다.
각 단위는 특정 단위를 기준으로 두 시간 객체 사이의 시간을 계산하기 위해 사이 에 명명된 메서드에 대한 구현을 제공합니다 .
예를 들어 두 LocalDateTime 사이의 초를 계산하려면 다음을 수행합니다 .
@Test
public void givenTwoDateTimesInJava8_whenDifferentiatingInSeconds_thenWeGetTen() {
LocalDateTime now = LocalDateTime.now();
LocalDateTime tenSecondsLater = now.plusSeconds(10);
long diff = ChronoUnit.SECONDS.between(now, tenSecondsLater);
assertEquals(10, diff);
}
ChronoUnit 은 TemporalUnit 인터페이스를 구현하여 구체적인 시간 단위 세트를 제공합니다. 가독성을 높이 려면 ChronoUnit 열거형 값을 정적으로 가져오는 것이 좋습니다 .
import static java.time.temporal.ChronoUnit.SECONDS;
// omitted
long diff = SECONDS.between(now, tenSecondsLater);
또한 두 개의 호환 가능한 시간 객체를 사이 메서드에 전달할 수 있습니다( 심지어 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(6, diff);
}
2.3. 사용 ) (때까지 임시 #을
어떠한 시간적 같은 객체 LOCALDATE 또는 ZonedDateTime는 , 을 제공 할 때까지 다른까지 시간 계산 방법 시공간 지정된 단위 환산 :
@Test
public void givenTwoDateTimesInJava8_whenDifferentiatingInSecondsUsingUntil_thenWeGetTen() {
LocalDateTime now = LocalDateTime.now();
LocalDateTime tenSecondsLater = now.plusSeconds(10);
long diff = now.until(tenSecondsLater, ChronoUnit.SECONDS);
assertEquals(10, diff);
}
까지 시간적 # 및 사이 TemporalUnit # 동일한 기능을위한 두 가지의 API이다.
2.4. 사용 java.time.Duration 및 java.time.Period을
Java 8에서 Time API는 Duration 및 Period 라는 두 가지 새로운 클래스를 도입했습니다 .
시간 기반(시간, 분 또는 초) 시간에서 두 날짜-시간의 차이를 계산하려면 Duration 클래스를 사용할 수 있습니다 .
@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(6, diff);
}
그러나 Period 클래스를 사용하여 두 날짜 간의 차이를 나타내 려고 하면 함정에 주의해야 합니다 .
예를 들어 이 함정을 빠르게 설명할 수 있습니다.
Period 클래스를 사용하여 두 날짜 사이의 일수를 계산해 보겠습니다 .
@Test
public void givenTwoDatesInJava8_whenUsingPeriodGetDays_thenWorks() {
LocalDate aDate = LocalDate.of(2020, 9, 11);
LocalDate sixDaysBehind = aDate.minusDays(6);
Period period = Period.between(aDate, sixDaysBehind);
int diff = Math.abs(period.getDays());
assertEquals(6, diff);
}
위의 테스트를 실행하면 통과합니다. Period 클래스가 문제를 해결하는 데 편리 하다고 생각할 수 있습니다. 여태까지는 그런대로 잘됐다.
이 방법이 6일의 차이로 작동한다면 60일 동안도 작동할 것이라는 데 의심의 여지가 없습니다.
따라서 위의 테스트 에서 6 을 60으로 변경하고 어떤 일이 발생하는지 봅시다 .
@Test
public void givenTwoDatesInJava8_whenUsingPeriodGetDays_thenDoesNotWork() {
LocalDate aDate = LocalDate.of(2020, 9, 11);
LocalDate sixtyDaysBehind = aDate.minusDays(60);
Period period = Period.between(aDate, sixtyDaysBehind);
int diff = Math.abs(period.getDays());
assertEquals(60, diff);
}
이제 테스트를 다시 실행하면 다음이 표시됩니다.
java.lang.AssertionError:
Expected :60
Actual :29
앗! 기간 클래스가 차이를 29 일로 보고한 이유는 무엇 입니까?
이는 Period 클래스가 "x년, y개월, z일" 형식으로 날짜 기반 시간을 나타내기 때문 입니다. getDays() 메서드를 호출 하면 "z일" 부분만 반환합니다.
따라서 위 테스트 의 기간 개체는 "0년 1개월 29일" 값을 보유합니다.
@Test
public void givenTwoDatesInJava8_whenUsingPeriod_thenWeGet0Year1Month29Days() {
LocalDate aDate = LocalDate.of(2020, 9, 11);
LocalDate sixtyDaysBehind = aDate.minusDays(60);
Period period = Period.between(aDate, sixtyDaysBehind);
int years = Math.abs(period.getYears());
int months = Math.abs(period.getMonths());
int days = Math.abs(period.getDays());
assertArrayEquals(new int[] { 0, 1, 29 }, new int[] { years, months, days });
}
Java 8의 Time API를 사용하여 일수 차이를 계산하려면 ChronoUnit.DAYS.between() 메서드가 가장 간단한 방법입니다.
3. 외부 라이브러리
3.1. 조다타임
JodaTime을 사용 하여 비교적 간단하게 구현할 수도 있습니다 .
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.9</version>
</dependency>
Maven Central에서 최신 버전의 Joda-time 을 얻을 수 있습니다 .
LocalDate 케이스:
@Test
public void givenTwoDatesInJodaTime_whenDifferentiating_thenWeGetSix() {
org.joda.time.LocalDate now = org.joda.time.LocalDate.now();
org.joda.time.LocalDate sixDaysBehind = now.minusDays(6);
long diff = Math.abs(Days.daysBetween(now, sixDaysBehind).getDays());
assertEquals(6, diff);
}
마찬가지로 LocalDateTime 사용 :
@Test
public void givenTwoDateTimesInJodaTime_whenDifferentiating_thenWeGetSix() {
org.joda.time.LocalDateTime now = org.joda.time.LocalDateTime.now();
org.joda.time.LocalDateTime sixMinutesBehind = now.minusMinutes(6);
long diff = Math.abs(Minutes.minutesBetween(now, sixMinutesBehind).getMinutes());
assertEquals(6, diff);
}
3.2. 데이트4J
Date4j 는 또한 간단하고 간단한 구현을 제공 합니다 . 이 경우 명시적으로 TimeZone을 제공해야 합니다 .
Maven 의존성부터 시작하겠습니다.
<dependency>
<groupId>com.darwinsys</groupId>
<artifactId>hirondelle-date4j</artifactId>
<version>1.5.1</version>
</dependency>
다음은 표준 DateTime으로 작업하는 빠른 테스트입니다 .
@Test
public void givenTwoDatesInDate4j_whenDifferentiating_thenWeGetSix() {
DateTime now = DateTime.now(TimeZone.getDefault());
DateTime sixDaysBehind = now.minusDays(6);
long diff = Math.abs(now.numDaysFrom(sixDaysBehind));
assertEquals(6, diff);
}
4. 결론
이 기사에서는 일반 Java와 외부 라이브러리를 사용하여 날짜(시간이 있는 것과 없는 것) 간의 차이를 계산하는 몇 가지 방법을 설명했습니다.