[英]Why is assertEquals false if it is the same date? 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());
我收到了这个错误
<2014-04-11 23:13:13.0>
与<Fri Apr 11 23:13:13 CEST 2014>
java.lang.AssertionError:
They should have to be equal dates
expected:<2014-04-11 23:13:13.0>
but was:<Fri Apr 11 23:13:13 CEST 2014>
与问题相关的额外信息
课程任务
@Entity
@Table(name = "t_task")
public class Task {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "idTask")
private long idTask;
...
@Column(name = "date")
private Date date;
...
Mysql表t_task
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;
}
任何想法?
这是由java.sql.Timestamp
混乱设计引起的完全混乱,并且由Hibernate返回此类的实例。 实际上,您将java.util.Date
实例存储到您的实体中。 Hibernate将其转换为java.sql.Timestamp
以将其插入数据库中。 但是当它从数据库中读取数据时,它不会将时间戳转换回java.util.Date
。 这很好,因为Timestamp扩展了Date。
但是时间戳永远不应该延长日期。 实际上,Date精确到毫秒,而Timestamp精确到纳秒。 为了能够比较两个Timestamp的纳秒部分,Timestamp会覆盖equals()方法,但会通过这样做来打破它的总体契约。 最终结果是,您可以将date.equals(timestamp)
为true,但timestamp.equals(date)
为false。
我的建议:永远不要将Date实例与equals()
进行比较。 请改用compareTo()
。
Sun的解释,使用java客户端级别(不使用Hibernate),在java.sql.Timestamp的javadoc中 ,它指出:
Quote:公共类Timestamp扩展日期
java.util.Date的瘦包装器,允许JDBC API将其标识为SQL TIMESTAMP值。 它增加了保存SQL TIMESTAMP nanos值的功能,并提供格式化和解析操作以支持时间戳值的JDBC转义语法。
注意:此类型是java.util.Date和单独的纳秒值的组合。 只有整数秒存储在java.util.Date组件中。 分数秒 - 纳米 - 是分开的。 传递类型为java.util.Date的值时,Timestamp.equals(Object)方法永远不会返回true,因为日期的nanos组件未知。 因此,Timestamp.equals(Object)方法与java.util.Date.equals(Object)方法不对称。 此外,哈希码方法使用底层的java.util.Date实现,因此在其计算中不包括nanos。
由于Timestamp类和上面提到的java.util.Date类之间存在差异,因此建议代码不要将Timestamp值一般视为java.util.Date的实例。 Timestamp和java.util.Date之间的继承关系实际上表示实现继承,而不是类型继承。
@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
}
从javadoc我们可以看出:
时间戳= java.util.Date +纳秒
和
传递类型为java.util.Date的值时,Timestamp.equals(Object)方法永远不会返回true,因为日期的nanos组件未知。
时间戳compareTo()函数
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);
}
}
我建议你看看你用什么类型将日期存储在数据库中。 例如,Oracle DATE只有精度到第二级,而TIMESTAMP可以像在Java日期那样下降到毫秒。
http://docs.oracle.com/cd/B19306_01/server.102/b14220/datatype.htm#CNCPT413
对于那些正在寻找比较日期的简单单元测试答案的人 ,我使用SimpleDateFormatter
将日期作为Strings
进行比较。 这允许您在没有一堆数学的情况下指定您在比较中寻求的精度。
SimpleDateFormatter formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
assertEquals(formatter.format(someExpectedDate), formatter.format(someActualDate));
您可以修改格式以满足您的需求。
这两个日期是不同的类(一个是java.util.Date,另一个是java.sql.Timestamp),所以它们不一样。
试试这个来检查日期值:assertEquals(new Date(taskR1.getDate()。getTime()),t1.getDate());
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.