比较具有不同精度级别的Date对象

bra*_*mus 71 java junit

我有一个JUnit测试失败,因为毫秒是不同的.在这种情况下,我不关心毫秒.如何更改断言的精度以忽略毫秒(或我想要设置的任何精度)?

我想传递的失败断言的示例:

Date dateOne = new Date();
dateOne.setTime(61202516585000L);
Date dateTwo = new Date();
dateTwo.setTime(61202516585123L);
assertEquals(dateOne, dateTwo);
Run Code Online (Sandbox Code Playgroud)

Esk*_*sko 59

还有另一种解决方法,我会这样做:

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

  • 我通常采用类似的方法用Math.abs()包装它 (10认同)
  • +1用于比较方差,但不考虑绝对方差(例如,如果date1在date2之后怎么办?) (3认同)

Dan*_*att 52

有些库可以帮助解决这个问题:

Apache commons-lang

如果在类路径上有Apache commons-lang,则可以使用DateUtils.truncate截断日期到某个字段.

assertEquals(DateUtils.truncate(date1,Calendar.SECOND),
             DateUtils.truncate(date2,Calendar.SECOND));
Run Code Online (Sandbox Code Playgroud)

有一个简写:

assertTrue(DateUtils.truncatedEquals(date1,date2,Calendar.SECOND));
Run Code Online (Sandbox Code Playgroud)

请注意,12:00:00.001和11:59:00.999会截断为不同的值,因此这可能不太理想.为此,有圆:

assertEquals(DateUtils.round(date1,Calendar.SECOND),
             DateUtils.round(date2,Calendar.SECOND));
Run Code Online (Sandbox Code Playgroud)

AssertJ

从版本3.7.0开始,如果您使用的是Java 8 Date/Time API ,AssertJ会添加一个isCloseTo断言.

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));
Run Code Online (Sandbox Code Playgroud)

它也适用于遗留的Java日期:

Date d1 = new Date();
Date d2 = new Date();
assertThat(d1).isCloseTo(d2, within(100, ChronoUnit.MILLIS).getValue());
Run Code Online (Sandbox Code Playgroud)

  • Round 也可以。它会向上或向下舍入,而 truncate 将始终向下。根据 [docs](https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/time/DateUtils.html),round 还处理夏令时。 (2认同)

Joa*_*uer 22

使用DateFormat格式仅显示要匹配的部分的对象,assertEquals()并对生成的字符串执行操作.您也可以轻松地将其包装在您自己的assertDatesAlmostEqual()方法中.

  • 不处理第二个边界上毫秒差异的情况,10.000和09.999会有所不同. (9认同)

dea*_*mon 14

使用 AssertJ,您可以提供一个自定义比较器,如果您要比较整个对象结构而不是单个值,则该比较器特别方便,因此其他方法(例如isEqualToIgnoringMillis或 )isCloseTo不实用。

assertThat(thing)
  .usingRecursiveComparison()
  .withComparatorForType(
      (a, b) -> a.truncatedTo(ChronoUnit.MILLIS).compareTo(b.truncatedTo(ChronoUnit.MILLIS)),
      OffsetDateTime.class
  )
Run Code Online (Sandbox Code Playgroud)


Set*_*eth 6

你可以这样做:

assertTrue((date1.getTime()/1000) == (date2.getTime()/1000));
Run Code Online (Sandbox Code Playgroud)

不需要字符串比较.

  • 如果一个值为 3.999 秒而另一个值为 4.000,这将失败。换句话说,有时它会容忍长达一秒的差异,有时它会因 2 毫秒的差异而失败。 (2认同)

Gab*_*res 5

在JUnit中,您可以编写两个断言方法,如下所示:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)


Ogn*_*nić 5

您可以在比较日期时选择所需的精度级别,例如:

LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS);
// e.g. in MySQL db "timestamp" is without fractional seconds precision (just up to seconds precision)
assertEquals(myTimestamp, now);
Run Code Online (Sandbox Code Playgroud)