William Wino
William Wino

Reputation: 3829

Converting java.sql.Timestamp to java.util.Calendar without losing precision

I'm trying to fetch timestamp values from a database, convert them to Calendar, and convert them back to Timestamp, but they lose their precision.

Here's the code to reproduce the problem

import java.sql.Timestamp;
import java.util.Calendar;

public class Test {
    public static void main(String[] args)
    {
        Timestamp timestamp = new Timestamp(112, 10, 5, 15, 39, 11, 801000000);
        System.out.println("BEFORE "+timestamp.toString());
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timestamp.getTime());
        timestamp = new Timestamp(calendar.getTimeInMillis());
        System.out.println("AFTER "+timestamp.toString());
    }
}

Here is the sample result of conversion

BEFORE 2012-10-18 14:30:13.362001
AFTER 2012-10-18 14:30:13.362

It loses its precision. What do I do to keep the decimal value as it is?

Upvotes: 32

Views: 68559

Answers (2)

Basil Bourque
Basil Bourque

Reputation: 340098

java.time

In Java 8 and later we now have a solution: the new java.time framework is built in. Defined by JSR 310, inspired by Joda-Time, extended by the ThreeTen-Extra project.

This new framework has nanosecond resolution. That's enough to handle the old java.util.Date values, Joda-Time values, both being milliseconds. And it's enough to handle the microseconds used by some databases such as Postgres. Some databases such as H2 use nanoseconds. So java.time can handle it all, or least all the mainstream situations. The only exceptions would be niche scientific or engineering situations.

Image

With Java 8, the old classes got new methods for converting to/from java.time. On java.sql.Timestamp use the new toInstant and fromInstant methods. The Instant class contains a count of nanoseconds from epoch, first moment of 1970 UTC (basically, see class doc for details).

From an Instant you can get a ZonedDateTime object.

java.sql.Timestamp ts = myResultSet.getTimestamp( 1 );
Instant instant = ts.toInstant();
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( zoneId );

Upvotes: 8

Bohemian
Bohemian

Reputation: 425328

You are setting the time in milliseconds, but your input precision is in microseconds, so of course you are going to lose any precision finer than milliseconds.

Calendar doesn't support finer granularity than milliseconds. There is no work-around.

Upvotes: 31

Related Questions