ResultSet.getDate() returning wrong date - java

I am having a problem using the ResultSet.getDate() method. I have a date field in MySQL and when I try to get the value, the date obtained is today's date instead of the date in the table specified. I don't know what is causing this error, I have searched other posts, but other errors with getDate() were different, like parsing or data mismatch errors or other kinds of errors. It could be an error due to time zone, because the values of the dates are from yesterday, but there's one row with date of two days ago and it's also returning today's date.
Here's the code:
package dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.joda.time.LocalDate;
import model.Paciente;
import teste.ConnectionFactory;
public class PacienteDao {
// a conexão com o banco de dados
private Connection connection;
public PacienteDao() {
this.connection = new ConnectionFactory().getConnection();
}
public void adiciona(Paciente paciente) {
String sql = "insert into paciente" +
" (nome_paciente,cpf_paciente,rg_paciente,data_nasc)" +
"values (?,?,?,?)";
try {
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, paciente.getNome_paciente());
stmt.setString(2, paciente.getCpf());
stmt.setString(3, paciente.getRg());
java.sql.Date data_nasc = new java.sql.Date(paciente.getData_nasc().toDate().getTime());
stmt.setDate(4, data_nasc);
stmt.execute();
stmt.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public List<Paciente> listaPacientes() {
List<Paciente> pacientes = new ArrayList<Paciente>();
try {
PreparedStatement stmt = this.connection.prepareStatement("select * from paciente");
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
Paciente paciente = new Paciente();
paciente.setId_paciente(rs.getInt("id_paciente"));
paciente.setNome_paciente(rs.getString("nome_paciente"));
paciente.setCpf(rs.getString("cpf_paciente"));
paciente.setRg(rs.getString("rg_paciente"));
LocalDate dt = new LocalDate();
dt.fromDateFields(rs.getDate("data_nasc"));
paciente.setData_nasc(dt);
pacientes.add(paciente);
}
rs.close();
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
return pacientes;
}
Here's the data that should be returned (CSV):
"1","Lucas","1111111111","12222222","2017-12-19"
"2","Lucas","1111111111","12222222","2017-12-20"
"3","Lucas","1111111111","12222222","2017-12-20"
"4","Leandro","2321","21232","2017-12-20"
Here's the data that is been returned (StackTrace):
Id: 1
Nome: Lucas
CPF: 1111111111
RG: 12222222
Data de Nascimento: 2017-12-21
Id: 2
Nome: Lucas
CPF: 1111111111
RG: 12222222
Data de Nascimento: 2017-12-21
Id: 3
Nome: Lucas
CPF: 1111111111
RG: 12222222
Data de Nascimento: 2017-12-21
Id: 4
Nome: Leandro
CPF: 2321
RG: 21232
Data de Nascimento: 2017-12-21
Like I said one of the rows has a date of two days ago, but it's showing today's date too, so I think isn't a time zone error.
PS: The name of the variables and methods are in Portuguese, because the application is in Portuguese too.

The problem is here
LocalDate dt = new LocalDate();
dt.fromDateFields(rs.getDate("data_nasc"));
The first statement creates a new LocalDate set to today. The second statement is a call to the static method fromDateFields, which should have been flagged as a warning by your IDE an/or compiler. This method returns a new LocalDate object, which you discarded, and does not modify dt. The above should be:
LocalDate dt = LocalDate.fromDateFields(rs.getDate("data_nasc"));

The Answer by Jim Garrison is correct. The much simpler and more intuitive code seen below would have prevented that particular mistake.
In addition, you are:
Ignoring the crucial issue of time zone in determining a date.
Using an older library from a project that recommends you move to their modern replacement classes.
tl;dr
Using java.time classes that replaced Joda-Time.
myResultSet().getObject( … , Instant.class ) // Extract a moment on the timeline in UTC, an `Instant` object.
.atZone( ZoneId.of( "Asia/Kolkata" ) ) // Adjust into a time zone, to determine a date, rendering a `ZonedDateTime` object.
.toLocalDate() // Extract a date-only object, a `LocalDate` without time-of-day and without a time zone.
Avoid legacy classes
You should not be using PreparedStatement::getDate(). Avoid all of the troublesome old date-time classes bundled with the earliest versions of Java, such as Date, Calendar, and the related java.sql types. These are entirely supplanted with the java.time classes and a JDBC 4.2 driver.
Likewise, the Joda-Time project is now in maintenance mode. Its team advises migration to the java.time which they inspired, defined, and implemented in JSR 310.
java.time
Use getObject and setObject methods.
LocalDate ld = myResultSet().getObject( … , LocalDate.class ) ; // For retrieving a standard SQL `DATE` column.
And…
myPrepatedStatement.setObject( … , ld ) ;
That code above is for a standard SQL DATE column which is a date-only value.
But it sounds like you have a moment stored, perhaps the MySQL type TIMESTAMP which seems to track with the standard SQL TIMESTAMP WITH TIME ZONE type. Any provided offset or time zone info is used to adjust the value into UTC upon submission to the database, in MySQL, with a resolution of microseconds.
So the equivalent type in Java is Instant, for a point in the timeline in UTC but with a finer resolution of nanoseconds.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
And…
myPreparedStatement.setObject( … , instant ) ;
Remember that the Instant is always in UTC. But determining a date requires a time zone. For any given moment, the date varies by zone.
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
From there extract the date-only object that seems to be your goal.
LocalDate ld = zdt.toLocalDate() ;

Related

How to store ZonedDateTime of java in TIMESTAMPTZ in oracle?

I want to store the ZonedDateTime in TIMESTAMP WITH TIME ZONE datatype in oracle.
If I am trying to store string directly as a String it throws not a valid month.
then I found that I can convert it to the TIMESTAMPTZ in java then store because we need to convert the string to TIMESTAMPTZ and its throwing error.
String d = "2021-10-28 02:36:08.000000 +02:00";
TIMESTAMPTZ t = new TIMESTAMPTZ(con, d);
PreparedStatement ps = con.prepareStatement(query);
ps.setObject(1,t);
Error/stack trace:
Exception in thread "main" java.lang.IllegalArgumentException: Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]
at java.sql.Timestamp.valueOf(Timestamp.java:251)
at oracle.sql.TIMESTAMPTZ.toBytes(TIMESTAMPTZ.java:1919)
at oracle.sql.TIMESTAMPTZ.<init>(TIMESTAMPTZ.java:253)
at OracleSelectQuery.main(OracleSelectQuery.java:21)
Someone please look into this.
java.time
The following table depicts the mapping of ANSI SQL types with java.time types:
ANSI SQL
Java SE 8
DATE
LocalDate
TIME
LocalTime
TIMESTAMP
LocalDateTime
TIME WITH TIMEZONE
OffsetTime
TIMESTAMP WITH TIMEZONE
OffsetDateTime
Parse the given Date-Time string into OffsetDateTime as shown below:
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSS XXX", Locale.ENGLISH);
String strDateTime = "2021-10-28 02:36:08.000000 +02:00";
OffsetDateTime odt = OffsetDateTime.parse(strDateTime, dtf);
System.out.println(odt);
}
}
Output:
2021-10-28T02:36:08+02:00
ONLINE DEMO
Now, you can store this OffsetDateTime into the database as shown below:
PreparedStatement st = conn.prepareStatement("INSERT INTO mytable (columnfoo) VALUES (?)");
st.setObject(1, odt);
st.executeUpdate();
st.close();
Learn more about the modern Date-Time API* from Trail: Date Time.
* If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time.
The three-arg TIMESTAMPTZ(Connection, Timestamp, ZoneId) constructor
According to the documentation of the Oracle TIMESTAMPTZ class (link at the bottom) it has a constructor that in addition to the connection takes a java.sql.Timestamp and a java.time.ZoneId as arguments (a funny mixture of an outdated and a modern Java class). Since we can extract a ZoneOffset from your string and ZoneOffset is a subclass of ZoneId, we can use this constructor for your purpose:
String d = "2021-10-28 02:36:08.000000 +02:00";
OffsetDateTime odt = OffsetDateTime.parse(d, PARSER);
Instant inst = odt.toInstant();
ZoneId offsetAsZoneId = odt.getOffset();
TIMESTAMPTZ t = new TIMESTAMPTZ(con, Timestamp.from(inst), offsetAsZoneId);
I used this formatter for parsing:
private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendLiteral(' ')
.appendOffsetId()
.toFormatter(Locale.ROOT);
You may also save a time zone to Oracle
That the constructor I used accepts a ZoneId opens the additional possibility that we may store a real time zone ID like Europe/Paris or Asia/Kolkata to the database rather than just a naked UTC offset. At least the way I read the Oracle database documentation, its timestamp with time zone data type can hold a time zone ID. The example given in the documentation is America/Los_Angeles.
For a simple example of converting a ZonedDateTime to a TIMESTAMPTZ:
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Kolkata"));
Instant inst = zdt.toInstant();
ZoneId zid = zdt.getZone();
TIMESTAMPTZ t = new TIMESTAMPTZ(con , Timestamp.from(inst), zid);
Links
Documentation of TIMESTAMPTZ and its TIMESTAMPTZ(Connection, Timestamp, ZoneId) constructor.
Oracle database Datetime Data Types and Time Zone Support help, section Datetime and Interval Data Types. Scroll down to TIMESTAMP WITH TIME ZONE Data Type.

How to add a datetime Into my SQL database using JDBC [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
Currently, I am trying to add my datetime into SQL from JavaFX GUI, but I keep getting the number format exception error. The Datetime format is yyyy-MM-dd HH:mm:ss, but I can also add in just like 12:30 etc.
private void doAdd() {
//Input from the user in GUI format
int EntryID = Integer.valueOf(tfEntryID.getText());
String PersonName = tfPersonName.getText();
int CheckInTime = Integer.parseInt(tfCheckInTime.getText());
String CheckTime = String.valueOf(CheckInTime);
Date date = new Date(CheckInTime);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") ;
String currentDateTime = format.format(date);
String insertSql = String.format("INSERT INTO entry_records(
EntryID, PersonName, CheckTime) VALUES ('%s', '%s', %s)",
EntryID , PersonName ,currentDateTime );
int rowsAdded = DBUtil.execSQL(insertSql);
if (rowsAdded == 1) {
System.out.println("STATUS: ADD Entry Record (ID" + EntryID + ") Successful!");
} else {
System.out.println("Adding failed!");
}
}
Never use Date and SimpleDateFormat classes. They are terribly flawed in design. They were years ago supplanted by the modern java.time classes defined in JSR 310.
With JDBC 4.2 and later, you can exchange date-time objects with your database use java.time objects. No need for string manipulations.
Parse your input string into a LocalDateTime object if you have only date and time-of-day and intend to ignore time zones.
DateTimeFormatter f = DateTimeFormatter.ofPattern( … ) ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
Write that value to your database using a PreparedStatement to avoid the security risks of SQL-injection.
myPreparedStatement.setObject( … , ldt ) ;
Retrieval.
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;
The LocalDateTime class is appropriate to a database column of a type akin to SQL-standard TIMESTAMP WITHOUT TIME ZONE. These types are inherently ambiguous as they both purposely lack the context of a time zone or offset-from-UTC. So they cannot represent a moment, are not a specific point on the timeline.
To represent a moment, use classes Instant/OffsetDateTime/ZonedDateTime, with OffsetDateTime being appropriate to SQL exchange. For database column type, use a type akin to the SQL-standard TIMESTAMP WITH TIME ZONE.
All of this has been covered many times already on Stack Overflow. Search to learn more.

converting string date to sql Date format in java

I would like to achieve below:
I have date in string format as e.g. "2015-05-12 15:15:24",
I would like to convert it to sql date in the format "dd-MMM-yy".
However, this is not working. below is the code snippet:
String rawDate="2015-05-12 15:15:24";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date =format.parse(rawDate);
Date sqlDate = new java.sql.Date(date.getTime());
SimpleDateFormat changedFormat = new SimpleDateFormat("dd-MMM-yy");
Date date2=changedFormat.parse(changedFormat.format(sqlDate));
Date sqlDate2 = new java.sql.Date(date2.getTime());
System.out.println("sqlDate : "+sqlDate +" :::::: Date2 : "+date2+" :::: sqlDate2 "+sqlDate2);ow here is the Test : "+sqlDate2);
The output of the program is :
sqlDate : 2015-05-12 :::::: Date2 : Tue May 12 00:00:00 BST 2015 :::: sqlDate2 2015-05-12
The aim was to get date in the format of 12-May-15 java.sql format, but May is not being translated into alphabet month rather its printed as number.
am I missing anything. any help would be appreciated.
tl;dr
Use objects, not strings, to communicate with database.
Use only java.time classes, never java.util.Date, Calendar, or java.sql.Date classes.
myPreparedStatement.setObject( // Use smart objects, not dumb strings.
… , // Specify which placeholder `?` in you SQL.
LocalDateTime.parse( // Parse input string lacking any zone or offset as a `LocalDateTime` object. *NOT* a moment, just a vague idea about *potential* moments.
"2015-05-12 15:15:24".replace( " " , "T" ) // Alter your input string to comply with ISO 8601 standard format, with `T` in the middle.
) // Returns a `LocalDateTime` object.
.atOffset( // Apply an offset-from-UTC to determine a moment, a specific point on the timeline.
ZoneOffset.UTC // Apply UTC if the input string was intended to be a moment in UTC.
) // Returns a `OffsetDateTime` object.
.toLocalDate() // Extract a date-only value, a `LocalDate` object from the date-with-time `OffsetDateTime` object.
)
Details
convert it to sql date in the format "dd-MMM-yy"
There is no such SQL-standard format. SQL-standard format for a date is the same as ISO 8601 standard format: YYYY-MM-DD.
java.time
You are using terrible old classes that were supplanted years ago by the modern java.time classes.
LocalDateTime
Your input string lacks any indicator of time zone or offset-from-UTC. So parse as a LocalDateTime.
The java.time classes use standard ISO 8601 format by default when parsing and generating strings. Your input string is nearly compliant with the standard. Just replace the SPACE in the middle with a T.
String input = "2015-05-12 15:15:24".replace( " " , "T" ) ;
Parse.
LocalDateTime ldt = LocalDateTime.parse( input ) ;
OffsetDateTime
A LocalDateTime does not represent a moment. It represents potential moments along a span of about 26-27 hours, the range of time zones around the globe. If you know the intended time zone, apply a ZoneId to get a ZonedDateTime object. If you know only a mere offset rather than a zone, apply a ZoneOffset to get a OffsetDateTime object. I will assume your value is intended to represent a moment in UTC, in other words, an offset-from-UTC of zero.
OffsetDateTime odt = ldt.atOffset( Offset.UTC ) ;
Smart objects, not dumb strings
You should use class types appropriate to your SQL data types to exchange data with your database. Use smart objects, not dumb strings.
As of JDBC 4.2, we can directly exchange java.time objects.
myPreparedStatement.setObject( … , odt ) ;
Retrieval.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
LocalDate
You care only about the date, not the time-of-day. So extract a LocalDate object.
LocalDate ld = odt.toLocalDate() ;
Submit to your database.
myPreparedStatement.setObject( … , ld ) ;
Retrieval.
LocalDate ld = myPreparedStatement.getObject( … , LocalDate.class ) ;
Complete example
Here is a complete example app, in a single .java.
Using the H2 Database Engine. We specify an in-memory database, never persisted to storage, as this is just a demo.
package com.basilbourque.example;
import java.sql.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.UUID;
public class DateIntoDatabase {
public static void main ( String[] args ) {
DateIntoDatabase app = new DateIntoDatabase();
app.doIt();
}
private void doIt () {
try {
Class.forName( "org.h2.Driver" );
} catch ( ClassNotFoundException e ) {
e.printStackTrace();
}
try (
Connection conn = DriverManager.getConnection( "jdbc:h2:mem:date_into_db_example_" ) ;
Statement stmt = conn.createStatement() ;
) {
String sql = "CREATE TABLE event_ (\n" +
" id_ UUID DEFAULT random_uuid() PRIMARY KEY ,\n" +
" name_ VARCHAR NOT NULL ,\n" +
" when_ DATE NOT NULL\n" +
") ; ";
System.out.println( sql );
stmt.execute( sql );
// Insert row.
sql = "INSERT INTO event_ ( name_ , when_ ) " + "VALUES ( ? , ? ) ;";
try ( PreparedStatement preparedStatement = conn.prepareStatement( sql ) ; ) {
String name = "whatever";
LocalDate ld = LocalDateTime.parse( "2015-05-12 15:15:24".replace( " " , "T" ) ).atOffset( ZoneOffset.UTC ).toLocalDate();
preparedStatement.setString( 1 , name );
preparedStatement.setObject( 2 , ld );
preparedStatement.executeUpdate();
}
// Query all.
sql = "SELECT * FROM event_ ;";
try ( ResultSet rs = stmt.executeQuery( sql ) ; ) {
while ( rs.next() ) {
//Retrieve by column name
UUID id = ( UUID ) rs.getObject( "id_" ); // Cast the `Object` object to UUID if your driver does not support JDBC 4.2 and its ability to pass the expected return type for type-safety.
String name = rs.getString( "name_" );
LocalDate ld = rs.getObject( "when_" , LocalDate.class );
//Display values
System.out.println( "id: " + id + " | name: " + name + " | when: " + ld );
}
}
} catch ( SQLException e ) {
e.printStackTrace();
}
}
}
When run:
id: 0a4fd38c-7d4e-4049-bc21-e349582c8bc5 | name: whatever | when: 2015-05-12
About java.time
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?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.
You computed it, but never printed it:
String rawDate = "2015-05-12 15:15:24";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = format.parse(rawDate);
java.sql.Date sqlDate = new java.sql.Date(date.getTime());
SimpleDateFormat changedFormat = new SimpleDateFormat("dd-MMM-yy");
System.out.println("Formatted Date: " + changedFormat.format(sqlDate));
You have in your code the date in the format you want, but you are assing into a other object type date .
change this :
Date date2=changedFormat.parse(changedFormat.format(sqlDate));
Date sqlDate2 = new java.sql.Date(date2.getTime());
to this : String dateformat =(changedFormat.format(sqlDate));
you can pass the value from the string yo your object date. but if you print the var date you don´t print in the format you want, and this is becouse :
Date does not store any format into itself.

Postgresql seem to convert timestamp parameter of PreparedStatement

Postgresql seem to convert timestamp parameter of PreparedStatement which I set using setTimestamp.
[What I want to do]
I want to query today's data. ( 2016-06-30 00:00:00 ~ 2016-06-30 23:59:59)
But, when I got the result from DB, it was data for 2016-06-29 15:00:00 to 2016-06-30 14:59:59. ( 9 hours gap)
My local timezone : GMT+9 (KST)
DB timezone : UTC (GMT+0) ( In table, UTC time is stored as update time. I checked that. )
So 9 hours gap as I guess. When I pass UTC timestamp parameter to postgresql, it subtracted 9 hours from my timestamp parameters. I wonder why postgresql did so, and how I prevent that.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
sdf2.setTimeZone(TimeZone.getTimeZone("UTC"));
Timestamp startTime = Timestamp.valueOf(sdf.format(new Date(System.currentTimeMillis())));
Timestamp endTime = Timestamp.valueOf(sdf2.format(new Date(System.currentTimeMillis())));
PreparedStatement pstmt = conn.prepareStatement(
"SELECT * FROM some_table WHERE update_time BETWEEN ? AND ? "
);
pstmt.setTimestamp(1, startTime);
pstmt.setTimestamp(2, endTime);
ResultSet rs = pstmt.executeQuery();
[Table structure]
CREATE TABLE some_table
(
mem_no bigserial
,data char(2)
,update_time timestamp with time zone DEFAULT current_timestamp
,CONSTRAINT pk_some_table PRIMARY KEY (mem_no)
);
[Something strange]
Using debugging tool, I checked pstmt value. Strangely +09:00:00 was added to my parameters.
pstmt => SELECT * FROM some_table WHERE update_time BETWEEN 2016-06-30 00:00:00 +09:00:00 AND 2016-06-30 23:59:59 +09:00:00
DB : postgresql 9.3
tl;dr
To find all rows with a recorded moment occurring on a certain date, in this SQL: "SELECT * FROM tbl WHERE when !< ? AND when < ? ; " ; that uses the Half-Open approach to a span-of-time.
myPreparedStatement
.setObject(
1 ,
LocalDate // Represent a date-only value, without a time-of-day and without a time zone.
.parse( "2016-06-30" ) // Returns a `LocalDate` object.
.atStartOfDay() // Returns a `OffsetDateTime` object. JDBC 4.2 and later requires support for this class.
) ;
myPreparedStatement
.setObject(
2 ,
LocalDate
.parse( "2016-06-30" )
.plusDays( 1 ) // Add a day, to get first moment of the following day.
.atStartOfDay()
) ;
Details
There are multiple problems with your code. For more discussion, see other Answers such as this one of mine. I'll be brief here as this has been covered many times already.
Use only java.time classes, never the legacy date-time classes they supplanted as of adoption of JSR 310.
Use Half-Open approach to defining a span of time, where the beginning is inclusive while the ending is exclusive.
Be clear on whether you are tracking moments, specific points on the timeline, or vague date with time-of-day but lacking the context of a time zone or offset-from-UTC.
If tracking moments, your column must be of data type TIMESTAMP WITH TIME ZONE rather than WITHOUT.
For any given moment, the date (and time-of-day) varies around the globe by time zone.
Some dates in some time zones do not start at 00:00. Always let java.time determine start of day.
Apparently you want all the rows with a date-time occurring on the date of 2016-06-30.
LocalDate startDate = LocalDate.parse( "2016-06-30" ) ;
LocalDate stopDate = startDate.plusDays( 1 ) ;
Specify the time zone by which you want to interpret the date and get first moment of the day.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
Get the first moment of start and stop dates.
ZonedDateTime zdtStart = startDate.atStartOfDay( z ) ;
ZonedDateTime zdtStop = startDate.atStopOfDay( z ) ;
Support for the ZonedDateTime class is not required in JDBC 4.2. That class may or may not work with your JDBC driver. If not, use the OffsetDateTime class, support for which is required by JDBC 4.2.
OffsetDateTime start = zdtStart.toOffsetDateTime() ;
OffsetDateTime stop = zdtStop.toOffsetDateTime() ;
Write your SQL with placeholders ?. I suggest always including the statement terminator ;. Never use BETWEEN for date-time work as that is full-closed rather than half-open.
String sql = "SELECT * FROM tbl WHERE when !< ? AND when < ? ; " ; // Half-Open span-of-time where beginning is inclusive while the ending is exclusive.
Pass the placeholder objects.
myPreparedStatement.setObject( 1 , start ) ;
myPreparedStatement.setObject( 2 , stop ) ;
Retrieve result.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
That result will be in UTC. You can adjust to your desired time zone. Same moment, same point on the timeline, but different wall-clock time.
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
Always specify zone/offset
My local timezone : GMT+9 (KST)
DB timezone : UTC (GMT+0) ( In table, UTC time is stored as update time. I checked that. )
Write your Java app such that you never depend on the current default time zone of either your JVM or your database server.
Notice that the code above using objects has no surprises with time zone, and explicitly specify desired/expected time zones or offsets. The surprises come with middleware and utilities that are opinionated about injecting a zone or offset into the retrieved values. Postgres itself always stores and retrieves TIMESTAMP WITH TIME ZONE values in UTC (an offset of zero hours-minutes-seconds).
Half-Open
I want to query today's data. ( 2016-06-30 00:00:00 ~ 2016-06-30 23:59:59)
No, you are missing the last second of the day there.
Instead define your spans-of-time using Half-Open approach where the beginning is inclusive while the ending is exclusive. This lets spans of time neatly abut one another without gaps and without overlaps.
So a week starts on Monday and runs up to, but does not include, the following Monday. Lunch period starts at 12:00 noon and runs up to, but does not include, when the clock strikes 13:00. A day starts at the first moment of the day (which is not always 00:00 by the way!), running up to, but not including, the first moment of the following day. Study the SQL and Java shown in this Answer to see how that works.
I solved this ^^
[My answer] (1) WHERE clause (2) String instead of Timestamp
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
sdf2.setTimeZone(TimeZone.getTimeZone("UTC"));
String startTime = sdf.format(new Date(System.currentTimeMillis()));
String endTime = sdf2.format(new Date(System.currentTimeMillis()));
PreparedStatement pstmt = conn.prepareStatement(
"SELECT * FROM some_table " +
"WHERE update_time " +
"BETWEEN (CAST(TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS') AS TIMESTAMP) AT TIME ZONE 'UTC') " +
"AND (CAST(TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS') AS TIMESTAMP) AT TIME ZONE 'UTC')");
pstmt.setString(1, startTime);
pstmt.setString(2, endTime);
ResultSet rs = pstmt.executeQuery();
Clearly, timezone offset +09 is attached automatically. So I decided to give String parameter instead of timestamp. ( JDBC or Postgresql will not change String value ) Then I tested some cases like this.
[Test]
PreparedStatement pstmt = conn.prepareStatement(
"SELECT TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS') test1 " +
"CAST(TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS') AS TIMESTAMP) test2 " +
"(CAST(TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS') AS TIMESTAMP) AT TIME ZONE 'UTC') test3 " +
"FROM some_table " +
"WHERE update_time " +
"BETWEEN TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS') " + => In test, this is not important
"AND TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS') "); => In test, this is not important
pstmt.setString(1, startTime);
pstmt.setString(2, startTime);
pstmt.setString(3, startTime);
pstmt.setString(4, startTime);
pstmt.setString(5, endTime);
ResultSet rs = pstmt.executeQuery();
System.out.println(rs.getString("test1") + "/" +rs.getString("test2") + "/" + rs.getString("test3") );
[Result]
current time : 2016-07-01 15:17:40+00 ( in UTC )
startTime : "2016-07-01 00:00:00" => String
test1 : 2016-07-01 00:00:00+09 => cause subtraction ( 2017-06-30 15:00:00)
test2 : 2016-07-01 00:00:00
test3 : 2016-07-01 09:00:00+09 => Wow ^^
[test3] was what I wanted. When I changed where clause like above, I could get data for 2016-07-01 00:00:00 ~ 2016-07-01 23:59:59

Inconsistent date format while retrieving from postgres using java 1.7

I'm facing this unique issue while retrieving date column values from postgres and export as a CSV using JDK 1.7 Following is a sample output
ID, Date Created, Date Modified
816271, 8/8/2013 14:35 2/2/2015 16:47
830322 13/08/2013 11:48 AM 2/2/2015 16:48
1128312 10/2/2015 16:53 10/2/2015 16:53
1129465 12/2/2015 16:23 12/2/2015 16:23
1130482 16/02/2015 4:28 PM 15/06/2015 7:01 AM
1019527 19/08/2014 4:40 AM 23/02/2015 12:14 PM
1134334 23/02/2015 8:38 AM 4/6/2015 5:16
The problem is, I see that AM/PM being appended those date values where the DAY part is greater than 12. When I look into the database I don't see any AM/PM. In my DO, I've just declared the variable as Date.
Please let me know why this inconsistent formatting happens.
thanks
Following is how I set the date into my DO.
public void setCreatedDate(Date createdDate) {
if (createdDate == null) {
this.mCreatedDate = createdDate; return;
}
this.mCreatedDate = new Date(createdDate.getTime());
}
I'm not using any formatting code at all. Even there is one, I'm not sure why it is not applied to all record
You need to understand that a date-time value stored in a database using a date-time data type has no format. What you are seeing are String representations of that date-time value generated for the convenient viewing by humans. The String is not the date-time.
So your formatting issue with "AM/PM" relates to some code generating that string outside of Postgres. You do not show us that code, so we cannot directly resolve the Question. But you can avoid the problem in the first place if you consciously work with date-time values/objects rather than Strings.
Storing date-time in Postgres
In Postgres, you should generally be using the TIMESTAMP WITH TIME ZONE data type. This type does not actually keep the time zone. Rather it has respect for the time zone, using any passed offset or time zone information accompanying data input to adjust to UTC. The result is then stored in the database. After adjustment, Postgres discards the original offset or time zone info.
Retrieving date-time from Postgres
When retrieving data (a SELECT), you may get a date-time value or you may get a String, depending on the client app (pgAdmin, psql, SQuirreL SQL Client, and such) or your database driver (JDBC and such). If getting a String, an adjustment to some time zone may have been made on your behalf, but that String is not the date-time value. If getting a date-time value, stick with that value for your work rather than converting to strings. In JDBC, that means using java.sql.Timestamp objects, for example.
Java date-time frameworks
If using Java 8 or later technology, you should make use of the new java.time package. If not possible, use the Joda-Time library. Try to avoid java.util.Date/.Calendar & java.text.SimpleDateFormat as they are troublesome and confusing.
Example
Below is a full example of extracting a java.sql.Timestamp from Postgres 9.4, then using java.time or Joda-Time to work with the value.
Data Loss with Joda-Time & java.util.Date
Note that Joda-Time (like java.util.Date) is limited to millisecond precision of fractional seconds. Postgres resolves to microseconds. So converting from Postgres to Joda-Time/java.util.Date means likely data loss. With java.time, no problem as it resolves to nanoseconds.
Code
Written in Java 8 Update 51, using the postgresql-9.4-1201.jdbc41.jar driver with Postgres 9.4.x on Mac OS X Mountain Lion.
String message = "Example of fetching Timestamp from Postgres.";
StringBuilder sql = new StringBuilder();
sql.append( "SELECT now() " + "\n" );
sql.append( ";" );
java.sql.Timestamp ts = null;
try ( Connection conn = DatabaseHelper.instance().connectionInAutoCommitMode() ;
PreparedStatement pstmt = conn.prepareStatement( sql.toString() ); ) {
try ( ResultSet rs = pstmt.executeQuery(); ) {
// Extract data from result set
int count = 0;
while ( rs.next() ) {
count ++;
ts = rs.getTimestamp( 1 );
}
}
} catch ( SQLException ex ) {
logger.error( "SQLException during: " + message + "\n" + ex );
} catch ( Exception ex ) {
logger.error( "Exception during: " + message + "\n" + ex );
}
java.sql.Timestamp
Beware of how the old Java date-time classes implicitly apply your JVM’s current default time zone. While intended to be helpful, it creates no end of confusion. The time zone seen when running this code is America/Los_Angeles which has an offset of −07:00.
String output_SqlTimestamp = ts.toString(); // Confusingly applies your JVM’s current default time zone.
java.time
Use java.time in Java 8 and later.
// If you have Java 8 or later, use the built-in java.time package.
java.time.Instant instant = ts.toInstant();
java.time.ZoneId zoneId = ZoneId.of( "America/Montreal" );
java.time.ZonedDateTime zdt = java.time.ZonedDateTime.ofInstant( instant , zoneId );
String output_UTC = instant.toString();
String output_Montréal = zdt.toString();
System.out.println( "output_SqlTimestamp: " + output_SqlTimestamp );
System.out.println( "output_UTC: " + output_UTC );
System.out.println( "output_Montréal: " + output_Montréal );
Joda-Time
Before Java 8, use Joda-Time.
// Before Java 8, use Joda-Time. (Joda-Time was the inspiration for java.time.)
// IMPORTANT: Joda-Time, like java.util.Date, is limited to milliseconds for fraction of a second. So you may experience data loss from a Postgres date-time value with microseconds.
org.joda.time.DateTime dateTimeMontréal = new org.joda.time.DateTime( ts.getTime() , DateTimeZone.forID( "America/Montreal" ) ); // WARNING: Data lost with microseconds truncated to milliseconds.
org.joda.time.DateTime dateTimeUtc = dateTimeMontréal.withZone( DateTimeZone.UTC );
String output_Joda_dateTimeMontréal = dateTimeMontréal.toString();
String output_Joda_dateTimeUtc = dateTimeUtc.toString();
System.out.println( "output_Joda_dateTimeMontréal: " + output_Joda_dateTimeMontréal );
System.out.println( "output_Joda_dateTimeUtc: " + output_Joda_dateTimeUtc );
When run.
output_SqlTimestamp: 2015-08-24 12:46:06.979144
output_UTC: 2015-08-24T18:46:06.979144Z
output_Montréal: 2015-08-24T14:46:06.979144-04:00[America/Montreal]
output_Joda_dateTimeMontréal: 2015-08-24T14:46:06.979-04:00
output_Joda_dateTimeUtc: 2015-08-24T18:46:06.979Z

Categories