Compare Date objects with different levels of precision

前端 未结 19 1980
日久生厌
日久生厌 2020-12-08 13:01

I have a JUnit test that fails because the milliseconds are different. In this case I don\'t care about the milliseconds. How can I change the precision of the assert to i

相关标签:
19条回答
  • 2020-12-08 13:05

    Using JUnit 4 you could also implement a matcher for testing dates according to your chosen precision. In this example the matcher takes a string format expression as a parameter. The code is not any shorter for this example. However the matcher class may be reused; and if you give it a describing name you can document the intention with the test in an elegant way.

    import static org.junit.Assert.assertThat;
    // further imports from org.junit. and org.hamcrest.
    
    @Test
    public void testAddEventsToBaby() {
        Date referenceDate = new Date();
        // Do something..
        Date testDate = new Date();
    
        //assertThat(referenceDate, equalTo(testDate)); // Test on equal could fail; it is a race condition
        assertThat(referenceDate, sameCalendarDay(testDate, "yyyy MM dd"));
    }
    
    public static Matcher<Date> sameCalendarDay(final Object testValue, final String dateFormat){
    
        final SimpleDateFormat formatter = new SimpleDateFormat(dateFormat);
    
        return new BaseMatcher<Date>() {
    
            protected Object theTestValue = testValue;
    
    
            public boolean matches(Object theExpected) {
                return formatter.format(theExpected).equals(formatter.format(theTestValue));
            }
    
            public void describeTo(Description description) {
                description.appendText(theTestValue.toString());
            }
        };
    }
    
    0 讨论(0)
  • 2020-12-08 13:12

    Use a DateFormat object with a format that shows only the parts you want to match and do an assertEquals() on the resulting Strings. You can also easily wrap that in your own assertDatesAlmostEqual() method.

    0 讨论(0)
  • 2020-12-08 13:12

    Yet another workaround, I'd do it like this:

    assertTrue("Dates aren't close enough to each other!", (date2.getTime() - date1.getTime()) < 1000);
    
    0 讨论(0)
  • 2020-12-08 13:12

    JUnit has a built in assertion for comparing doubles, and specifying how close they need to be. In this case, the delta is within how many milliseconds you consider dates equivalent. This solution has no boundary conditions, measures absolute variance, can easily specify precision, and requires no additional libraries or code to be written.

        Date dateOne = new Date();
        dateOne.setTime(61202516585000L);
        Date dateTwo = new Date();
        dateTwo.setTime(61202516585123L);
        // this line passes correctly 
        Assert.assertEquals(dateOne.getTime(), dateTwo.getTime(), 500.0);
        // this line fails correctly
        Assert.assertEquals(dateOne.getTime(), dateTwo.getTime(), 100.0);
    

    Note It must be 100.0 instead of 100 (or a cast to double is needed) to force it to compare them as doubles.

    0 讨论(0)
  • 2020-12-08 13:14

    There are libraries that help with this:

    Apache commons-lang

    If you have Apache commons-lang on your classpath, you can use DateUtils.truncate to truncate the dates to some field.

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

    There is a shorthand for this:

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

    Note that 12:00:00.001 and 11:59:00.999 would truncate to different values, so this might not be ideal. For that, there is round:

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

    AssertJ

    Starting with version 3.7.0, AssertJ added an isCloseTo assertions, if you are using the Java 8 Date / Time API.

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

    It also works with legacy java Dates as well:

    Date d1 = new Date();
    Date d2 = new Date();
    assertThat(d1).isCloseTo(d2, within(100, ChronoUnit.MILLIS).getValue());
    
    0 讨论(0)
  • 2020-12-08 13:16

    Something like this might work:

    assertEquals(new SimpleDateFormat("dd MMM yyyy").format(dateOne),
                       new SimpleDateFormat("dd MMM yyyy").format(dateTwo));
    
    0 讨论(0)
提交回复
热议问题