0

I'm storing measurements in a MySQL database. The measurements contain a timestamp field which stores timestamps in the following format:

2015-10-10 10:10:10.11 (so with two digits of milliseconds)

In my Java code I retrieve this value with:

resultSet.getTimestamp(id)

When I print this value it gives me:

2015-10-10 11:11:11.000000011

So I'm trying to figure out WHY it behaves like this and HOW I should solve this issue so I get the right value?

EDIT:

The values show correctly inside the database itself when using select * from measurement

My guess it should be somewhere in the way it is retrieved by Java / JDBC. Both getTimestamp and getString give me the same result.

EDIT 2:

resultSet = statement.executeQuery("select * from measurement");

Measurement m;

while(resultSet.next()) {
    m = new Measurement(
        resultSet.getString(1), 
        resultSet.getString(2), 
        resultSet.getDouble(4), 
        resultSet.getTimestamp(3));
    System.out.println(m);
}
10
  • can you please add more code, i can bet you store timestamp in a long or a double in some moment, then you lose precision.... Commented Oct 15, 2015 at 9:01
  • Which version of MySQL are you using? Commented Oct 15, 2015 at 9:08
  • @Tunaki I'm using MySQL 5.6.26 as I require at least 5.6.4 to store fractional seconds. Commented Oct 15, 2015 at 9:15
  • @Jordi Castilla I'm not storing the data by code yet, I've inserted it manually through PHPmyAdmin Commented Oct 15, 2015 at 9:15
  • as per your last comment: You are probable right as getTimestamp().getNano() return the numbers I'm looking for. So somehow Java takes the fractional part and turns them into nanoseconds., please paste your java code that retrieves and converts from sql timestamp to java Date.... Commented Oct 15, 2015 at 10:55

2 Answers 2

1

I've never been a fan of how MySQL's JDBC driver deals with the TIMESTAMP type. I'd use:

select ROUND(UNIX_TIMESTAMP(col1)*1000) FROM measurement

And then read it with

java.util.Date d = new java.util.Date(resultSet.getLong(1));
Sign up to request clarification or add additional context in comments.

1 Comment

This looks indeed like a solid workaround for my problem. But then I could also just go and store the UNIX_TIMESTAMP I guess...
0

I've been looking into the implementation. Even though it's a bit over my head I found out some 'interesting' information.

The implementation of com.mysql.jdbc.ResultSet.getTimestamp() has some clues:

int year = 0;
int month = 0;
int day = 0;
int hour = 0;
int minutes = 0;
int seconds = 0;
int nanos = 0; <<< CLUE

and

if (numDigits < 9) {
    int factor = (int) (Math.pow(10, 9 - numDigits));
    nanos = nanos * factor;
}

and

TimeUtil.fastTimestampCreate(tz, year, month, day, hour, minutes, seconds, nanos);

So it seems to parse everything after the '.' as nanoseconds ending up with leading zeroes. so .11 becomes .000000011.

So I think this explains the WHY it is happening...

The HOW to fix this could be in many ways, some being:

  1. Getting the UNIX_TIMESTAMP as user5449350's answer.
  2. Storing UNIX_TIMESTAMPS instead of TIMESTAMP / DATETIME
  3. Correct the faulty Date object and correct it using Calendar

    Date t = resultSet.getTimestamp(3);
    Calendar c = Calendar.getInstance();
    c.setTime(t);
    c.set(Calendar.MILLISECOND, ((Timestamp)t).getNanos());
    t = c.getTime();
    

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.