Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compare java.sql.Timestamp and java.util.Date

I know java Date was poor designed, but I don't know how until today.

I saved a date to DB and when I get it from DB and compare to original date, it told me it's different!

And I wrote a test which looks strange but it PASSED!

@Test
public void date_equals() {
    Date now = new Date();
    Timestamp timestamp = new Timestamp(now.getTime());

    assertFalse(timestamp.equals(now));
    assertTrue(now.equals(timestamp));

    assertTrue(timestamp.compareTo(now) == 0);
    assertFalse(now.compareTo(timestamp) == 0);

    assertTrue(timestamp.getTime() == now.getTime());
    assertTrue(now.getTime() == timestamp.getTime());
}

I noticed that java.sql.Timestamp has a little different than Date about nanoseconds which I don't care.

Can anyone told me how to compare this two in best practice? I don't want to compare date use getTime() everywhere, is there any common library or other ways to do this?

BTW I'm using JDK 6

like image 865
Eric Avatar asked Jan 04 '23 01:01

Eric


2 Answers

tl;dr

originalInstant.equals( 
    org.threeten.bp.DateTimeUtils.toInstant( mySqlTimestamp ) 
) 

Avoid legacy date-time classes

The old date-time classes bundled with the earliest versions of Java are an awful mess, with poor designs and awkward hacks. One of those bad hacks is making java.sql.Timestamp a subclass of java.util.Date while telling you to ignore that fact of inheritance.

To quote the class doc (emphasis mine):

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

You were told to pretend they are not related classes. So your attempt to compare objects of each type is inappropriate.

Data loss

The Timestamp has a resolution up to nanoseconds. The java.util.Date class is limited to milliseconds. So the two will not compare as equal.

Using java.time

Instead, use the java.time classes. Much of their functionality is available as a back-port to Java 6 – see below.

When you get your Timestamp, immediately convert to the java.time types. In Java 8 and later you could call the new methods added to those old classes for conversion. In the ThreeTen-Backport library for Java 6 & 7, use org.threeten.bp.DateTimeUtils.toInstant( Timestamp )

An Instant is a moment on the timeline in UTC with a resolution of nanoseconds.

Instant instant = DateTimeUtils.toInstant( mySqlTimestamp ) ;

Now compare to your original Instant.

boolean isOriginal = originalInstant.equals( instant ) ;

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, and later
    • Built-in.
    • Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
    • The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
    • See How to use ThreeTenABP….
like image 118
Basil Bourque Avatar answered Jan 08 '23 06:01

Basil Bourque


You have Timestamp::compareTo(java.util.Date o) in java.sql.TimeStamp class. Use it.

like image 30
Anil Avatar answered Jan 08 '23 06:01

Anil