java—比较具有不同精度级别的日期对象

ssgvzors  于 2021-06-30  发布在  Java
关注(0)|答案(19)|浏览(486)

我有一个junit测试失败,因为毫秒不同。在这种情况下,我不关心毫秒。如何将assert的精度更改为忽略毫秒(或我希望它设置为的任何精度)?
我想通过的失败Assert示例:

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

ppcbkaq51#

使用simpledatefromat将日期转换为字符串,在构造函数中指定所需的日期/时间字段并比较字符串值:

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String expectedDate = formatter.format(dateOne));
String dateToTest = formatter.format(dateTwo);
assertEquals(expectedDate, dateToTest);
dluptydi

dluptydi2#

而不是使用 new Date 您可以直接创建一个小型协作者,您可以在测试中模拟它:

public class DateBuilder {
    public java.util.Date now() {
        return new java.util.Date();
    }
}

创建datebuilder成员并更改调用 new DatedateBuilder.now() ```
import java.util.Date;

public class Demo {

DateBuilder dateBuilder = new DateBuilder();

public void run() throws InterruptedException {
    Date dateOne = dateBuilder.now();
    Thread.sleep(10);
    Date dateTwo = dateBuilder.now();
    System.out.println("Dates are the same: " + dateOne.equals(dateTwo));
}

public static void main(String[] args) throws InterruptedException {
    new Demo().run();
}

}

主要方法将产生:

Dates are the same: false

在测试中你可以注入一个 `DateBuilder` 让它返回任何你喜欢的值。例如,使用mockito或重写 `now()` :

public class DemoTest {

@org.junit.Test
public void testMockito() throws Exception {
    DateBuilder stub = org.mockito.Mockito.mock(DateBuilder.class);
    org.mockito.Mockito.when(stub.now()).thenReturn(new java.util.Date(42));

    Demo demo = new Demo();
    demo.dateBuilder = stub;
    demo.run();
}

@org.junit.Test
public void testAnonymousClass() throws Exception {
    Demo demo = new Demo();
    demo.dateBuilder = new DateBuilder() {
        @Override
        public Date now() {
            return new Date(42);
        }
    };
    demo.run();
}

}

axzmvihb

axzmvihb3#

我将对象强制转换为java.util.date并进行比较

assertEquals((Date)timestamp1,(Date)timestamp2);
jum4pzuy

jum4pzuy4#

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

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

r7s23pms5#

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

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

w8ntj3qf6#

如果你用的是乔达,你可以用节日乔达时间。

flvtvl50

flvtvl507#

你可以这样做:

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

不需要字符串比较。

e5nqia27

e5nqia278#

使用 DateFormat 对象,其格式仅显示要匹配的部分并执行 assertEquals() 在结果字符串上。你也可以很容易地用你自己的 Package assertDatesAlmostEqual() 方法。

cngwdvgl

cngwdvgl9#

在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);
  }
}
tyg4sfes

tyg4sfes10#

我上了一个小班,可能对一些最终来到这里的谷歌用户有用:https://stackoverflow.com/a/37168645/5930242

x6492ojm

x6492ojm11#

只需比较你感兴趣的日期部分:

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

assertEquals(dateOne.getMonth(), dateTwo.getMonth());
assertEquals(dateOne.getDate(), dateTwo.getDate());
assertEquals(dateOne.getYear(), dateTwo.getYear());

// alternative to testing with deprecated methods in Date class
Calendar calOne = Calendar.getInstance();
Calendar calTwo = Calendar.getInstance();
calOne.setTime(dateOne);
calTwo.setTime(dateTwo);

assertEquals(calOne.get(Calendar.MONTH), calTwo.get(Calendar.MONTH));
assertEquals(calOne.get(Calendar.DATE), calTwo.get(Calendar.DATE));
assertEquals(calOne.get(Calendar.YEAR), calTwo.get(Calendar.YEAR));
3z6pesqy

3z6pesqy12#

使用JUnit4,您还可以实现一个匹配器,根据您选择的精度来测试日期。在本例中,matcher将字符串格式表达式作为参数。对于这个例子,代码并不短。但是matcher类可以重用;如果你给它一个描述性的名字,你就可以用一种优雅的方式来记录测试的意图。

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());
        }
    };
}
ev7lccsx

ev7lccsx13#

这实际上是一个比看起来更难的问题,因为在边界情况下,您不关心的方差会超过您正在检查的值的阈值。e、 g.毫秒差小于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);
}
siv3szwd

siv3szwd14#

junit有一个内置的Assert,用于比较double,并指定它们需要有多接近。在本例中,delta是指您认为日期相等的毫秒数。这个解决方案没有边界条件,测量绝对方差,可以很容易地指定精度,并且不需要编写额外的库或代码。

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

请注意,它必须是100.0而不是100(或者需要转换为double)才能强制将它们作为double进行比较。

2uluyalo

2uluyalo15#

对joda time使用assertjAssert(http://joel-costigliola.github.io/assertj/assertj-joda-time.html)

import static org.assertj.jodatime.api.Assertions.assertThat;
import org.joda.time.DateTime;

assertThat(new DateTime(dateOne.getTime())).isEqualToIgnoringMillis(new DateTime(dateTwo.getTime()));

测试失败消息更具可读性

java.lang.AssertionError: 
Expecting:
  <2014-07-28T08:00:00.000+08:00>
to have same year, month, day, hour, minute and second as:
  <2014-07-28T08:10:00.000+08:00>
but had not.

相关问题