Why is assertEquals false if it is the same date? to winter

I generate a single date and save it to the database through sleep mode, and when I get the value and I compare it with the value before inserting it. The result is not equal!

I created the date as follows

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

I get this error

<2014-04-11 23:13:13.0> differs from <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> 

Additional information related to the problem

Class task

 @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 table

 CREATE TABLE IF NOT EXISTS `mytask`.`t_task` ( `idTask` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, `date` DATETIME NOT NULL ... 

I created new hashCode () and equals () functions in Task with only a date field and even both.

 @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; } 

Any idea?

+6
source share
5 answers

Sun's explanation, working with the java client level (not with Hibernate), in javadoc for java.sql.Timestamp , it says:

Quote: Open class Timestamp extends date

A thin shell around java.util.Date that allows the JDBC API to define this as a SQL TIMESTAMP value. This adds the ability to hold nanos for SQL TIMESTAMP and provides formatting and parsing of the operation to support JDBC escape syntax for timestamp values.

Note. This type is an integral part of java.util.Date and a separate nanosecond. Only whole seconds are stored in the java.util.Date component. Fractional seconds - nano - are separate. The Timestamp.equals (Object) method never returns true if it passed a value of type java.util.Date, because the nano date component is unknown. As a result, the Timestamp.equals (Object) method is not symmetrical with respect to the java.util.Date.equals (Object) method. In addition, the hashcode method uses the underlying java.util.Date and therefore does not include nano computing.

Due to the differences between the Timestamp class and java.util.Date mentioned above, it is recommended that the code not view the timestamp values ​​as an instance of java.util.Date. The inheritance relationship between timestamp and java.util.Date actually means implementation inheritance, not type inheritance.

 @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 } 

From javadoc we can understand that:

Timestamp = java.util.Date + nanoseconds

and

The Timestamp.equals (Object) method never returns true when passing a value of type java.util.Date, because the sediment component of the date is unknown.

Timestamp Comparison Function ()

 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); } } 
+2
source

This is a complete mess caused by the flawed design of java.sql.Timestamp , and Hibernate returns instances of this class. Indeed, you store an instance of java.util.Date in your entity. Hibernate converts this value to java.sql.Timestamp to paste it into the database. But when it reads data from the database, it does not convert the timestamp to java.util.Date . This works great because Timestamp extends Date.

But Timestamp should never have an extended date. Indeed, the date is exactly to the millisecond, while the timestamp is exactly to the nanosecond. To be able to compare the nanosecond parts of two timestamps, Timestamp overrides the equals () method, but breaks the general contract by doing this. The end result is that date.equals(timestamp) is true and timestamp.equals(date) is false.

My advice: never compare date instances with equals() . Use compareTo() instead.

+8
source

I would suggest you see what type you use to store dates in the database. For example, Oracle DATE only has accuracy to the second level, while TIMESTAMP can have up to a millisecond, as with a Java date.

http://docs.oracle.com/cd/B19306_01/server.102/b14220/datatype.htm#CNCPT413

+1
source

Two dates have different classes (one of them is java.util.Date, the other is java.sql.Timestamp), so they do not match.

Try checking the date values: assertEquals (new date (taskR1.getDate (). GetTime ()), t1.getDate ());

0
source

For those looking for an easy date comparison response testing unit , I used SimpleDateFormatter to compare dates like Strings . This allows you to specify the accuracy you are looking for in comparison, without a bunch of math.

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

You can change the format to suit your needs.

0
source

All Articles