Water Cooler v2
Water Cooler v2

Reputation: 33850

Conversion of java.util.Date to java.sql.Date truncates the time part

I am trying to save a java.util.Date from an application to my SQL Server database using JDBC.

When I convert the java.util.Date to a java.sql.Date using the method below, it truncates the time part.

java.sql.Date javaSqlExpiryDate = new java.sql.Date(javaUtilExpiryDate.getTime());
System.out.println("javaUtilExpiryDate: " + javaUtilExpiryDate.toString());
System.out.println("javaSqlExpiryDate: " + javaSqlExpiryDate.toString());

The Console window reports the output as:

javaUtilExpiryDate: Thu Sep 01 18:19:08 IST 2016

javaSqlExpiryDate: 2016-09-01

How do I get it to retain the time part as well?

Upvotes: 1

Views: 927

Answers (3)

Basil Bourque
Basil Bourque

Reputation: 338426

tl;dr

myPreparedObject.setObject(
    1 ,
    myJavaUtilDate.toInstant()  // Convert legacy object to modern java.time object, `Instant`.
)

Details

The other Answers are correct. The java.util.Date class represents a date and a time-of-day in UTC. The java.sql.Date represents only a date, without the time-of-day. Well, actually, the java.sql.Date pretends to represent only a date but actually, as a badly-designed hack, subclasses the java.util.Date class and therefore does have a time-of-day. Confusing? Yes. One of many reasons to avoid these awful old legacy classes.

Now we have a better way, the java.time classes.

java.time

In the old days you would convert your java.util.Date object to a java.sql.Timestamp.

Now, with a JDBC driver supporting JDBC 4.2 and later, you can send your java.time objects directly to/from the database. No need for either the java.util nor java.sql classes, just stick with java.time classes.

If you have to interface with old code using java.util.Date, convert to java.time.Instant using new methods added to the old classes.

The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

Instant instant = myJavaUtilDate.toInstant() ;  

Exchange an Instant with the database via PreparedStatement::setObject and ResultSet::getObject.

myPreparedStatement.setObject( … , instant ) ;

And…

Instant instant = myResultSet.getObject( … , Instant.class ) ;

To see this moment through some other time zone than UTC, apply a ZoneId to get a ZonedDateTime.

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

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?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Upvotes: 0

Amy
Amy

Reputation: 4032

Just change your import from java.sql.Date TO java.sql.Timestamp

Upvotes: 0

user330315
user330315

Reputation:

Yes, that's the expected and documented behavior.

Quote from the JavaDocs

To conform with the definition of SQL DATE, the millisecond values wrapped by a java.sql.Date instance must be 'normalized' by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated.

If you want to keep the time, you need to use java.sql.Timestamp (especially if the column in the database is defined as datetime).

Upvotes: 6

Related Questions