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?
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.