代码之家  ›  专栏  ›  技术社区  ›  brainimus user417509

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

  •  66
  • brainimus user417509  · 技术社区  · 15 年前

    我希望通过的失败断言示例:

    Date dateOne = new Date();
    dateOne.setTime(61202516585000L);
    Date dateTwo = new Date();
    dateTwo.setTime(61202516585123L);
    assertEquals(dateOne, dateTwo);
    
    18 回复  |  直到 15 年前
        1
  •  68
  •   Joachim Sauer    15 年前

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

    assertTrue("Dates aren't close enough to each other!", (date2.getTime() - date1.getTime()) < 1000);
    
        2
  •  67
  •   Dan Watt    7 年前

    阿帕奇公地酒店

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

    从3.7.0版开始, AssertJ isCloseTo 断言,如果您使用的是Java8日期/时间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));
    

    它也适用于传统的java日期:

    Date d1 = new Date();
    Date d2 = new Date();
    assertThat(d1).isCloseTo(d2, within(100, ChronoUnit.MILLIS).getValue());
    
        3
  •  25
  •   Joachim Sauer    15 年前

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

        4
  •  7
  •   Seth    15 年前

    你可以这样做:

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

        5
  •  6
  •   Gabriel Belingueres    12 年前

    在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);
      }
    }
    
        6
  •  5
  •   Ognjen Stanić    6 年前

    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);
    
        7
  •  4
  •   Michael Easter    15 年前

    我不知道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!"); }
        }
    }
    
        8
  •  3
  •   Ophidian    14 年前

    这实际上是一个比看起来更难的问题,因为在边界情况下,您不关心的方差超过了您正在检查的值的阈值。e、 g.毫秒差小于一秒,但两个时间戳跨过第二阈值、分钟阈值或小时阈值。这使得任何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);
    }
    
        9
  •  2
  •   Torbjörn Österdahl    14 年前

    匹配器 用于根据您选择的精度确定测试日期。在本例中,匹配器将字符串格式表达式作为参数。对于这个例子,代码没有更短。但是,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());
            }
        };
    }
    
        10
  •  2
  •   ysl    10 年前

    对Joda Time使用AssertJ断言( 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.
    
        11
  •  1
  •   kdombeck    11 年前

    如果你用的是乔达,你可以用 Fest Joda Time .

        12
  •  1
  •   Oliver Hernandez    11 年前

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

    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));
    
        13
  •  1
  •   w25r    8 年前

    JUnit有一个内置的断言,用于比较double,并指定它们需要接近的程度。在本例中,增量是指您认为日期相等的毫秒数。此解决方案没有边界条件,测量绝对方差,可以轻松指定精度,并且不需要编写额外的库或代码。

        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进行比较。

        14
  •  1
  •   deamon    4 年前

    isEqualToIgnoringMillis isCloseTo

    assertThat(thing)
      .usingRecursiveComparison()
      .withComparatorForType(
          (a, b) -> a.truncatedTo(ChronoUnit.MILLIS).compareTo(b.truncatedTo(ChronoUnit.MILLIS)),
          OffsetDateTime.class
      )
    
        15
  •  0
  •   javanna Jayendra    13 年前

    类似的方法可能会奏效:

    assertEquals(new SimpleDateFormat("dd MMM yyyy").format(dateOne),
                       new SimpleDateFormat("dd MMM yyyy").format(dateTwo));
    
        16
  •  0
  •   timomeinen    10 年前

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

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

    新日期 dateBuilder.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();
        }
    }
    
        17
  •  0
  •   Roberto    9 年前

    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String expectedDate = formatter.format(dateOne));
    String dateToTest = formatter.format(dateTwo);
    assertEquals(expectedDate, dateToTest);
    
        19
  •  0
  •   abasar    5 年前

    这是一个实用函数,它为我完成了这项工作。

        private boolean isEqual(Date d1, Date d2){
            return d1.toLocalDate().equals(d2.toLocalDate());
        }
    
    
        20
  •  0
  •   Sarvar Nishonboyev    3 年前

    isEqualToIgnoringSeconds 方法忽略秒并仅按分钟进行比较:

    Date d1 = new Date();
    Thread.sleep(10000);
    Date d2 = new Date();
    assertThat(d1).isEqualToIgnoringSeconds(d2); // true
    
        21
  •  -2
  •   Grubhart    11 年前

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

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