tags:

views:

432

answers:

7

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 ignore milliseconds (or any precision I would like it set to)?

Example of a failing assert that I would like to pass:

Date dateOne = new Date();
dateOne.setTime(61202516585000L);
Date dateTwo = new Date();
dateTwo.setTime(61202516585123L);
assertEquals(dateOne, dateTwo);
+3  A: 

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.

Joachim Sauer
+1  A: 

I don't know if there is support in JUnit, but one way to do it:

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!"); }
    }
}
Michael Easter
If you call the method `assertEqualDates` then I'd make its return type `void` and make the last line `assertEquals(d1, d2)`. This way it would behave the same as all the JUnit `assert*` methods.
Joachim Sauer
Agreed. I wanted to run the code and didn't have JUnit at hand.
Michael Easter
Be wary of global date formatters. They are not thread-safe. It's not a problem with this code, but it's a bad habit to have.
itsadok
This doesn't handle the case where the two Date objects have a sub-second difference but they cross the second threshold.
Ophidian
+1  A: 

You could do something like this:

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

No String comparisons needed.

Seth
I think you meant "/" versus "%"? This gets messy regarding arbitrary precision, IMHO. Good point though.
Michael Easter
Whoops! Good catch.I don't think precision is an issue though. Date.getTime() always returns a long of ms since the epoch.
Seth
+1  A: 

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

assertTrue("Dates aren't close enough to each other!", (date2.getTime() - date1.getTime()) < 1000);
Esko
+1 for comparing variance, but does not account for absolute variance (e.g. what if date1 is after date2?)
Ophidian
A: 

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

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

Dan Watt
A: 

This is actually a harder problem than it appears because of the boundary cases where the variance that you don't care about crosses a threshold for a value you are checking. e.g. the millisecond difference is less than a second but the two timestamps cross the second threshold, or the minute threshold, or the hour threshold. This makes any DateFormat approach inherently error-prone.

Instead, I would suggest comparing the actual millisecond timestamps and provide a variance delta indicating what you consider an acceptable difference between the two date objects. An overly verbose example follows:

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);
}
Ophidian
A: 

Something like this might work:

assertEquals(new SimpleDateFormat("dd MMM yyyy").format(dateOne), new SimpleDateFormat("dd MMM yyyy").format(dateTwo));

Bino B. Manjasseril