[java] 정밀도 수준이 다른 Date 객체 비교

밀리 초가 다르기 때문에 실패한 JUnit 테스트가 있습니다. 이 경우 밀리 초는 신경 쓰지 않습니다. 밀리 초 (또는 설정하려는 정밀도)를 무시하도록 어설 션의 정밀도를 어떻게 변경할 수 있습니까?

통과하고 싶다고 주장하는 실패의 예 :

Date dateOne = new Date();
dateOne.setTime(61202516585000L);
Date dateTwo = new Date();
dateTwo.setTime(61202516585123L);
assertEquals(dateOne, dateTwo);



답변

DateFormat일치하려는 부분 만 표시하는 형식 의 개체를 사용 assertEquals()하고 결과 문자열에 대해 수행합니다 . 자신의 assertDatesAlmostEqual()방법으로 쉽게 포장 할 수도 있습니다 .


답변

또 다른 해결 방법은 다음과 같습니다.

assertTrue("Dates aren't close enough to each other!", (date2.getTime() - date1.getTime()) < 1000);


답변

이를 도와주는 라이브러리가 있습니다.

Apache commons-lang

당신이있는 경우 아파치 평민 – 랭을 클래스 패스에, 당신이 사용할 수있는 DateUtils.truncate몇 가지 필드에 날짜를 절단 할 수 있습니다.

assertEquals(DateUtils.truncate(date1,Calendar.SECOND),
             DateUtils.truncate(date2,Calendar.SECOND));

이에 대한 속기가 있습니다.

assertTrue(DateUtils.truncatedEquals(date1,date2,Calendar.SECOND));

12 : 00 : 00.001 및 11 : 59 : 00.999는 다른 값으로 잘 리므로 이상적이지 않을 수 있습니다. 이를 위해 원형이 있습니다.

assertEquals(DateUtils.round(date1,Calendar.SECOND),
             DateUtils.round(date2,Calendar.SECOND));

AssertJ

버전 3.7.0부터 Java 8 날짜 / 시간 API를 사용하는 경우 AssertJisCloseTo어설 션을 추가했습니다 .

LocalTime _07_10 = LocalTime.of(7, 10);
LocalTime _07_42 = LocalTime.of(7, 42);
assertThat(_07_10).isCloseTo(_07_42, within(1, ChronoUnit.HOURS));
assertThat(_07_10).isCloseTo(_07_42, within(32, ChronoUnit.MINUTES));

레거시 자바 날짜에서도 작동합니다.

Date d1 = new Date();
Date d2 = new Date();
assertThat(d1).isCloseTo(d2, within(100, ChronoUnit.MILLIS).getValue());


답변

다음과 같이 할 수 있습니다.

assertTrue((date1.getTime()/1000) == (date2.getTime()/1000));

문자열 비교가 필요하지 않습니다.


답변

JUnit에서 다음과 같이 두 가지 assert 메서드를 프로그래밍 할 수 있습니다.

public class MyTest {
  @Test
  public void test() {
    ...
    assertEqualDates(expectedDateObject, resultDate);

    // somewhat more confortable:
    assertEqualDates("01/01/2012", anotherResultDate);
  }

  private static final String DATE_PATTERN = "dd/MM/yyyy";

  private static void assertEqualDates(String expected, Date value) {
      DateFormat formatter = new SimpleDateFormat(DATE_PATTERN);
      String strValue = formatter.format(value);
      assertEquals(expected, strValue);
  }

  private static void assertEqualDates(Date expected, Date value) {
    DateFormat formatter = new SimpleDateFormat(DATE_PATTERN);
    String strExpected = formatter.format(expected);
    String strValue = formatter.format(value);
    assertEquals(strExpected, strValue);
  }
}


답변

JUnit에 지원이 있는지 모르겠지만 한 가지 방법은 다음과 같습니다.

import java.text.SimpleDateFormat;
import java.util.Date;

public class Example {

    private static SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss");

    private static boolean assertEqualDates(Date date1, Date date2) {
        String d1 = formatter.format(date1);
        String d2 = formatter.format(date2);
        return d1.equals(d2);
    }

    public static void main(String[] args) {
        Date date1 = new Date();
        Date date2 = new Date();

        if (assertEqualDates(date1,date2)) { System.out.println("true!"); }
    }
}


답변

이것은 당신이 신경 쓰지 않는 분산이 당신이 체크하고있는 값에 대한 임계 값을 넘는 경계 케이스 때문에 나타나는 것보다 실제로 더 어려운 문제입니다. 예를 들어 밀리 초 차이가 1 초 미만이지만 두 타임 스탬프가 두 번째 임계 값, 분 임계 값 또는 시간 임계 값을 교차합니다. 따라서 DateFormat 접근 방식은 본질적으로 오류가 발생하기 쉽습니다.

대신 실제 밀리 초 타임 스탬프를 비교하고 두 날짜 개체 간의 허용 가능한 차이를 나타내는 분산 델타를 제공하는 것이 좋습니다. 지나치게 자세한 예는 다음과 같습니다.

public static void assertDateSimilar(Date expected, Date actual, long allowableVariance)
{
    long variance = Math.abs(allowableVariance);

    long millis = expected.getTime();
    long lowerBound = millis - allowableVariance;
    long upperBound = millis + allowableVariance;

    DateFormat df = DateFormat.getDateTimeInstance();

    boolean within = lowerBound <= actual.getTime() && actual.getTime() <= upperBound;
    assertTrue(MessageFormat.format("Expected {0} with variance of {1} but received {2}", df.format(expected), allowableVariance, df.format(actual)), within);
}