Reputation: 11
I have an Oracle table with Date column in it.
+--------+-----------------------+
| ID | CURR_DATE |
+--------+-----------------------+
| 1 |2003-04-06 02:59:59 |
+--------+-----------------------+
When I do a
select * from tablename
in the database console, I get the correct column value for CURR_DATE.
But when I do the same from a java program using JDBC, the time shifts one hour forward due to daylight saving. Here is a link that explains it. https://www.timeanddate.com/time/change/usa/new-york?year=2003.
So I receive the value 2003-04-06 03:59:59 instead of 2003-04-06 02:59:59.
This happens because the DB and the JVM are in PST and PST follows DST.(Pls correct me if I am wrong)
Here is my code
String query="select * from tablename";
PreparedStatement psmt = con.prepareStatement(query);
ResultSet results=psmt.executeQuery();
while(results.next()) {
System.out.println(results.getString(2));
}
What can be done so that results.getString()
returns me the same value which is in the database(without any adjustments).
I want it to return me the original value 2003-04-06 02:59:59 instead of the adjusted value 2003-04-06 03:59:59.
Upvotes: 1
Views: 827
Reputation: 339462
java.time.LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;
You storing a date-time value in a date-time column, so use a date-time type in Java. Currently your are using strings.
The Oracle DATE
type holds only a date and a time-of-day without any concept of time zone or offset-from-UTC. As such, a DATE
column cannot be used to represent a moment. The equivalent in standard SQL is TIMESTAMP WITHOUT TIME ZONE
.
For example, if a row stores a value in that column for the 23rd of January of this year at noon, we have know way to know if this is noon in Tokyo, noon in Kolkata, noon in Paris, or noon in Montréal. These various noons all occur in different moments, hours apart.
The appropriate type in Java to match an Oracle DATE
column is LocalDateTime
. This class also lacks any concept of time zone or offset-from-UTC. So it cannot be used to represent a moment. But when you have only a date and time-of-day without zone/offset, this is the class for you.
JDBC 4.2 and later requires support for directly exchanging java.time objects with the database.
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;
Writing data.
myPreparedStatemen.setObject( … , ldt ) ;
By exchanging a Java object without any zone/offset with a database column of a types without any zone/offset, you will have no issue with zone/offset. But be aware of the limitations of this kind of date-time value:
Upvotes: 1
Reputation: 4604
As @gord-thompson explained you should use an up to date ojdbc8 or ojdbc10, ideally 19.3 or 18.3, you can use these even if your database is 11.2g https://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.html#01_02
results.getObject(2, LocalDateTime.class)
Explanation
The issue is really with the implementation of the java.sql.Timestamp
class. It represents the milliseconds since 1970-01-01 00:00:00 GMT and 2003-04-06 02:59:59 in JVM time zone, 2003-04-06 02:59:59 does not exist in JVM time zone so the parser is off by the DST change.
LocalDateTime
is not bound to any time zone and just year-month-day-hour-minute-second-nano and therefore has no issues representing 2003-04-06 02:59:59 whatever the JVM time zone.
Upvotes: 2