FULL PRODUCT VERSION :
tested on latest java 6 and 7
ADDITIONAL OS VERSION INFORMATION :
tested on windows 7 and RHEL6
A DESCRIPTION OF THE PROBLEM :
ResultSet.getDate(String columnName, Calendar cal) should return a date from a database column, with timezone offset as specified by the calendar.
However, the implementation is very strange: year, month, day, hour, minute, second are taken from the database column, however the milliseconds are taken from the calendar itself!
I can't find the sources for this in my java distribution, but the following code onlineclearly has the bug:
http://hg.openjdk.java.net/jdk6/jdk6/jdk/file/0c738a3e5791/src/share/classes/com/sun/rowset/CachedRowSetImpl.java
line 6180
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
code snippet, database is H2 with column as timestamp(6) :
private Date fetchTimestampFromDatabase(SqlRowSet rs, String field) {
try {
System.out.println(rs.getTimestamp(field));
for (int i = 0; i < 10; i++) {
System.out.println(rs.getTimestamp(field, Calendar.getInstance(TimeZone.getTimeZone("UTC"))));
Thread.sleep(200);
...
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
2014-06-06 10:44:58.696
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
ACTUAL -
2014-06-06 10:44:58.696
2014-06-06 12:44:58.75
2014-06-06 12:44:58.95
2014-06-06 12:44:58.15
2014-06-06 12:44:58.35
2014-06-06 12:44:58.55
2014-06-06 12:44:58.75
2014-06-06 12:44:58.95
2014-06-06 12:44:58.15
2014-06-06 12:44:58.35
2014-06-06 12:44:58.55
REPRODUCIBILITY :
This bug can be reproduced always.
CUSTOMER SUBMITTED WORKAROUND :
private Date correctDateFromTimestamps(Timestamp stampWithCalendar, Timestamp stampPlain) {
if (stampWithCalendar == null || stampPlain == null) {
return null;
}
// take milliseconds from stampPlain instead of stampWithCalendar
return new Date(stampWithCalendar.getTime() + (stampPlain.getNanos() - stampWithCalendar.getNanos()) / 1000000);
}
adn then:
Timestamp ts1 = rs.getTimestamp(field, dbUtcCalendar);
Timestamp ts2 = rs.getTimestamp(field);
return correctDateFromTimestamps(ts1, ts2);
tested on latest java 6 and 7
ADDITIONAL OS VERSION INFORMATION :
tested on windows 7 and RHEL6
A DESCRIPTION OF THE PROBLEM :
ResultSet.getDate(String columnName, Calendar cal) should return a date from a database column, with timezone offset as specified by the calendar.
However, the implementation is very strange: year, month, day, hour, minute, second are taken from the database column, however the milliseconds are taken from the calendar itself!
I can't find the sources for this in my java distribution, but the following code onlineclearly has the bug:
http://hg.openjdk.java.net/jdk6/jdk6/jdk/file/0c738a3e5791/src/share/classes/com/sun/rowset/CachedRowSetImpl.java
line 6180
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
code snippet, database is H2 with column as timestamp(6) :
private Date fetchTimestampFromDatabase(SqlRowSet rs, String field) {
try {
System.out.println(rs.getTimestamp(field));
for (int i = 0; i < 10; i++) {
System.out.println(rs.getTimestamp(field, Calendar.getInstance(TimeZone.getTimeZone("UTC"))));
Thread.sleep(200);
...
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
2014-06-06 10:44:58.696
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
2014-06-06 12:44:58.123
ACTUAL -
2014-06-06 10:44:58.696
2014-06-06 12:44:58.75
2014-06-06 12:44:58.95
2014-06-06 12:44:58.15
2014-06-06 12:44:58.35
2014-06-06 12:44:58.55
2014-06-06 12:44:58.75
2014-06-06 12:44:58.95
2014-06-06 12:44:58.15
2014-06-06 12:44:58.35
2014-06-06 12:44:58.55
REPRODUCIBILITY :
This bug can be reproduced always.
CUSTOMER SUBMITTED WORKAROUND :
private Date correctDateFromTimestamps(Timestamp stampWithCalendar, Timestamp stampPlain) {
if (stampWithCalendar == null || stampPlain == null) {
return null;
}
// take milliseconds from stampPlain instead of stampWithCalendar
return new Date(stampWithCalendar.getTime() + (stampPlain.getNanos() - stampWithCalendar.getNanos()) / 1000000);
}
adn then:
Timestamp ts1 = rs.getTimestamp(field, dbUtcCalendar);
Timestamp ts2 = rs.getTimestamp(field);
return correctDateFromTimestamps(ts1, ts2);