Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/355.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如果是同一日期,为什么assertEquals为假?冬眠_Java_Hibernate_Junit_Assert_Assertions - Fatal编程技术网

Java 如果是同一日期,为什么assertEquals为假?冬眠

Java 如果是同一日期,为什么assertEquals为假?冬眠,java,hibernate,junit,assert,assertions,Java,Hibernate,Junit,Assert,Assertions,我生成一个日期并通过hibernate保存在数据库中,当我得到该值时,我将其与插入前的值进行比较。结果不一样 我创建的日期如下 Date rightnow = Calendar.getInstance().getTime(); Task t1 = new Task("My task", rightnow); taskDao.saveOrUpdate(t1); Task taskR1 = taskDao.get(t1.getIdTask()); assertEquals("They shoul

我生成一个日期并通过hibernate保存在数据库中,当我得到该值时,我将其与插入前的值进行比较。结果不一样

我创建的日期如下

Date rightnow = Calendar.getInstance().getTime();

Task t1 = new Task("My task", rightnow);
taskDao.saveOrUpdate(t1);

Task taskR1 = taskDao.get(t1.getIdTask());
assertEquals("They should have to be equal dates",taskR1.getDate(),t1.getDate());
我收到这个错误

不同于

Mysql表t_任务

CREATE TABLE IF NOT EXISTS `mytask`.`t_task` (
  `idTask` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `date` DATETIME NOT NULL
  ...
我在Task中创建了一个新的hashCode()和equals()函数,其中只包含日期字段,尽管如此,它还是有所不同

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((date == null) ? 0 : date.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (!(obj instanceof Task))
        return false;
    Task other = (Task) obj;
    if (date == null) {
        if (other.date != null)
            return false;
    } else if (!date.equals(other.date))
        return false;
    return true;
}

有什么想法吗?

我建议您看看在数据库中存储日期的类型。例如,Oracle日期的精度只有第二级,而时间戳的精度可以达到毫秒,就像Java日期一样


这两个日期属于不同的类别(一个是java.util.Date,另一个是java.sql.Timestamp),因此它们不相同

尝试此操作以检查日期值:
assertEquals(新日期(taskR1.getDate().getTime()),t1.getDate())

这是由
java.sql.Timestamp
混乱的设计和Hibernate返回此类实例造成的完全混乱。实际上,您正在将
java.util.Date
实例存储到实体中。Hibernate将其转换为
java.sql.Timestamp
以将其插入数据库。但是当它从数据库读取数据时,它不会将时间戳转换回
java.util.Date
。这很好,因为时间戳会延长日期

但时间戳不应该有延长的日期。事实上,日期精确到毫秒,而时间戳精确到纳秒。为了能够比较两个Timestamp的纳秒部分,Timestamp重写了equals()方法,但这样做打破了它的一般约定。最终的结果是,
date.equals(timestamp)
为真,而
timestamp.equals(date)
为假


我的建议是:永远不要将日期实例与
equals()
进行比较。请改用
compareTo()

Sun关于使用java客户端级别(而不是Hibernate)的解释,在中指出:

引用: 公共类时间戳扩展日期

围绕java.util.Date的薄型包装器,允许JDBCAPI 将其标识为SQL时间戳值。它增加了保持平衡的能力 SQL时间戳Nano值,并提供格式化和解析 支持时间戳值的JDBC转义语法的操作

注意:此类型是java.util.Date和单独的 纳秒值。只有整数秒存储在内存中 java.util.Date组件。分数秒-纳米-是 分离Timestamp.equals(Object)方法在 传递了java.util.Date类型的值,因为 日期不详。因此,Timestamp.equals(Object)方法是 相对于java.util.Date.equals(对象)不对称 方法。此外,hashcode方法使用底层java.util.Date 实现,因此在its中不包括nanos 计算

由于Timestamp类和 上面提到的java.util.Date类,建议代码不要 以java.util.Date实例的形式查看时间戳值。 Timestamp和java.util.Date之间的继承关系 表示实现继承,而不是类型继承

从javadoc我们可以看出:

Timestamp=java.util.Date+纳秒

Timestamp.equals(Object)方法在传递 类型为java.util.Date的值,因为日期的Nano组件是 不知道

时间戳比较()函数

public int compareTo(java.util.Date o) {
    if(o instanceof Timestamp) {
    // When Timestamp instance compare it with a Timestamp
    // Hence it is basically calling this.compareTo((Timestamp))o);
    // Note typecasting is safe because o is instance of Timestamp
    return compareTo((Timestamp)o);
    } else {
    // When Date doing a o.compareTo(this)
    // will give wrong results.
    Timestamp ts = new Timestamp(o.getTime());
    return this.compareTo(ts);
    }
}

对于那些正在寻找比较日期的简单单元测试答案的人,我使用了
SimpleDataFormatter
将日期作为
字符串进行比较。这允许您指定在比较中寻求的精度,而无需大量数学运算

SimpleDateFormatter formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
assertEquals(formatter.format(someExpectedDate), formatter.format(someActualDate));

您可以根据需要修改格式。

:55 vs:54?在我看来不一样-我最初的预感是数据库本身正在设置值。它们是相同的
Date
类型吗?它们看起来有不同的
toString
格式。我添加了另一个执行、hashCode和equal函数,我不知道还能做什么?这里是JB Nizet所说的,日期和时间戳类之间的差异。在Java中,我使用Date,在MySQL中使用DATETIME。我也尝试了@Temporal注释(TemporalType.TIMESTAMP),但也尝试了.DATE和TIME注释。它们都不起作用:(只是用MongoDB和java.time.LocalDateTime检查了这一点,那里也存在毫秒纳秒的问题。使用LocalDateTime设置时修剪日期解决了这个问题。我遇到了同样的问题,但我使用了mybatis。它们有相同的原因吗?请参阅SimpleDateFormat formatter=new SimpleDateFormat(“yyyy-MM-dd'HH:MM:ss”);
@Test
public void testTimestampVsDate() {
    java.util.Date date = new java.util.Date();
    java.util.Date stamp = new java.sql.Timestamp(date.getTime());
    assertTrue("date.equals(stamp)", date.equals(stamp));            //TRUE
    assertTrue("stamp.compareTo(date)", stamp.compareTo(date) == 0); //TRUE
    assertTrue("date.compareTo(stamp)", date.compareTo(stamp) == 0); //FALSE
    assertTrue("stamp.equals(date)", stamp.equals(date));            //FALSE
}
public int compareTo(java.util.Date o) {
    if(o instanceof Timestamp) {
    // When Timestamp instance compare it with a Timestamp
    // Hence it is basically calling this.compareTo((Timestamp))o);
    // Note typecasting is safe because o is instance of Timestamp
    return compareTo((Timestamp)o);
    } else {
    // When Date doing a o.compareTo(this)
    // will give wrong results.
    Timestamp ts = new Timestamp(o.getTime());
    return this.compareTo(ts);
    }
}
SimpleDateFormatter formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
assertEquals(formatter.format(someExpectedDate), formatter.format(someActualDate));