Reputation: 708
I have a field called deadline_date
of type timestamp with time zone
with value 2018-05-03 19:00:00-05.
select deadline_date from invoice_details where file_name='BHDHSB.pdf';
deadline_date
------------------------
2018-05-03 19:00:00-05
(1 row)
But on querying from my java code it is returning the value as 2018-05-04 05:30:00+05:30
.
I think it is converting the the date according to my local timezone.
Is there any way to get the value as stored in the table?
I am using the following maven dependency for Postgres
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4.1212</version>
</dependency>
Test.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class Test {
public static Connection connection;
public void createConnection()
{
try {
if (connection==null) {
Class.forName("org.postgresql.Driver");
connection = DriverManager.getConnection("jdbc:postgresql://localhost:5432/abc", "abc", "Welcome");
connection.setSchema("iiv_location");
}
} catch (Exception e) {
e.printStackTrace();
System.err.println(e.getClass().getName() + ": " + e.getMessage());
}
}
public static void main(String[] args) {
try {
test object = new test();
object.createConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select iiv_prescan_invoice_details.deadline_date from iiv_prescan_invoice_details");
while (resultSet.next()) {
System.out.println(resultSet.getString("deadline_date"));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Upvotes: 1
Views: 7492
Reputation: 338564
Postgres always stores a moment in UTC in a column of type TIMESTAMP WITH TIME ZONE
.
Beware of your database access tool: It may alter the retrieved UTC value, applying a zone/offset adjustment. This creates the illusion of the moment having been stored in that zone/offset when in fact it was stored in UTC.
Use objects, not strings, to exchange date-time values with your database.
Use only java.time classes, never the legacy Date
/Calendar
. For UTC moments, use java.time.Instant
class.
Instant instant = Instant.now() ;
myPreparedStatement.setObject( … , instant ) ;
Retrieval.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
The other Answers are correct in advising you to use objects rather than strings when exchanging date-time values between Java and your database. That is the whole point to JDBC and your JDBC driver, to marshal data back-and-forth while mediating the differences & details.
However those other Answers incorrectly advise the wrong classes to use in Java.
Postgres saves moments only in UTC. Any time zone or offset-from-UTC information accompanying an input to a database column of type TIMESTAMP WITH TIME ZONE
is used to adjust the value into UTC. Then the UTC value is saved to the database, and the original zone/offset forgotten.
Likewise, when retrieving a value from a database column of type TIMESTAMP WITH TIME ZONE
, you always get a value in UTC.
However, your middleware or tool being used between you and the database may be choose in alter the UTC value in transit, to apply a time zone or offset, thereby adjusting the value. I consider this to be a poor design choice, though I understand the good intentions behind it. But such behavior creates the illusion that a zone/offset was in the stored data when it was not.
Be aware that I am describing Postgres behavior here. The SQL standard defines the data types I discuss here, but not their behavior. The SQL standard barely touches on the issues of date-time, unfortunately. So various database implementations differ in their behavior. The adjust-to-UTC behavior of Postgres makes sense to me. But note that if you care about a date-time value’s original zone/offset, you must store that yourself in a separate column.
On the Java side, just use Instant
for sending and retrieving a moment from a database column of type TIMESTAMP WITH TIME ZONE
.
Sending.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
myPreparedStatement.setObject( … , instant ) ;
Retrieving.
Instant instant = myResultSet.getObject( … , Instant.class );
You can adjust from UTC to some particular time zone.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
If you were working in your business logic with an OffsetDateTime
or ZonedDateTime
object, extract an Instant
by calling their toInstant
method.
Instant instant = myZonedDateTime.toInstant() ; // Extract an `Instant` object, effectively adjusting from some particular time zone to UTC.
An entirely different kind of date-time is one intentionally lacking any concept of time zone or offset-from-UTC. As such, this kind does not represent a specific moment, is not a point on the timeline. This type represents potential moments along a range of about 26-27 hours (the range of various time zones).
For this kind of date-time:
LocalDateTime
class.TIMESTAMP WITHOUT TIME ZONE
type.When an input is sent to a column of this type in Postgres, any accompanying zone/offset information is ignored. The date and time-of-day are taken as-is and stored directly in the database. When retrieved you get the same date and time-of-day, with no adjustment to any particular time zone.
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.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
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: 4
Reputation:
Do not use getString()
to retrieve a timestamp (actually: only use it for strings. Not for numbers, not for dates, not for timestamps).
If you are dealing with timestamps that are time zone aware, you should use a OffsetDateTime
in Java.
The Postgres JDBC driver supports this directly through the getObject()
method:
OffsetDateTime deadline = resultSet.getObject("deadline_date", OffsetDateTime.class);
Upvotes: 4
Reputation: 2109
you can do it in sql, all you have to do is change your query.
select to_char(iiv_prescan_invoice_details.deadline_date, "yyyy:MM:dd HH24:MI:SS") as deadline_date
from iiv_prescan_invoice_details
or you can do it in java
LocalDateTime dateTime = resultSet.getTimestamp("deadline_date").toLocalDateTime();
System.out.println("Date Time: " + dateTime);
Upvotes: 0