-2

I have to query a DB for a date, then use LocalDate and a formatter to visualize in a different format. The problem is, no matter how many different formats i try, the query get visualized in the JDBC default format (yyyy-mm-dd). Please note, the date is stored in a DATE field (like 01-GEN-20). A typical output is: Date: 2019-03-12

String q5= "select to_char(dataord, 'dd/mm/yyyy') as DATAORD\r\n" + 
            "from orders" ;
    executeQuery.query5(q5);

public static void query5(String query) throws SQLException {
        Statement stmt =conn.createStatement();
        ResultSet rs = stmt.executeQuery(query);

        while(rs.next()) {
            
            String dataord = rs.getString("DATAORD");
            
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy", Locale.ITALY);
            LocalDate ld = LocalDate.parse(dataord,formatter);
            
            System.out.println("Date: " + ld);
            
            
        }
    }
EllC01
  • 1
  • 1
  • 1
  • 2
    That's because you are printing the `LocalDate` object. A `LocalDate` itself has no format, `toString()` is just returning a sensible presentation of the object. If you want to *format* a `LocalDate`, use `ld.format(formatter)`. – MC Emperor Jun 20 '20 at 15:47
  • Can't you just print dataord? DB version? Reuse the formatter if you really want to use LocalDate variable (see [here](https://stackoverflow.com/questions/28177370/how-to-format-localdate-to-string)) – WoAiNii Jun 20 '20 at 15:48

3 Answers3

5

LocalDate::format

As others pointed out, your line System.out.println("Date: " + ld); implicitly calls LocalDate::toString without making use of your DateTimeFormatter object. So your custom formatting pattern is never applied.

Apply your formatter while generating text. Instead of calling LocalDate::toString, call LocalDate::format.

String output = ld.format( formatter ) ;
System.out.println( "output: " + output ) ;

20/06/2020

You said:

the query get visualized in the JDBC default format (yyyy-mm-dd).

No, there is no such thing as a “JDBC default format”. The text produced by LocalDate::toString is in standard ISO 8601 format, YYYY-MM-DD. This has nothing to do with JDBC.

Your code has other issues. So read on.

Use smart objects, not dumb strings

Assuming your database column is of a type akin to the SQL standard type DATE, retrieve the value as a LocalDate object using a JDBC driver compliant with JDBC 4.2 or later. Stop thinking in terms of text. Think in terms of smart objects, not dumb strings.

LocalDate localDate = myResultSet.getObject( … , LocalDate.class ) ;

Likewise, send appropriate objects to the database rather than mere text. Use a prepared statement with ? placeholders.

myPreparedStatement.setObject( … , localDate ) ;  // Send object to database, to be written into row in table.

Separate retrieval from formatting/presentation

Only later should you think about formatting the data for presentation to the user. Generally best to separate the retrieval of data from the formatting/presentation of data. Collect your data into objects first, then later generate text for presentation.

Collecting data into objects is much easier and simpler with the upcoming Records feature previewed in Java 14 and arriving in Java 15. Constructor, getter methods, toString, equals & hashCode, and so on are all synthesized automatically behind the scenes.

record Order ( UUID id , String description , LocalDate whenPlaced ) {} // That is all the code you need. Constructor, getter methods, `toString`, `equals` & `hashCode`, and so on are all synthesized automatically behind the scenes.

Generate text in standard ISO 8601 format that represents the value within the object. Be aware that a LocalDate object has no text, has no “format”. Such an object knows how to parse text, and knows how to generate text, is not itself text.

String output = localDate.toString() ;

Let java.time automatically localize while generating text.

Locale locale = Locale.CANADA_FRENCH ;  // or Locale.US, Locale.ITALY, etc.
DateTimeFormatter f = 
    DateTimeFormatter
    .ofLocalizedDate( FormatStyle.MEDIUM )
    .withLocale( locale ) ;
String output = localDate.format( f ) ;  // Generate text representing the value of this object, while automatically localizing.

Or, if you insist, specify your own custom formatting pattern.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/uuuu" ) ;
String output = localDate.format( f ) ;

Example

Here is source-code for a complete example.

This example uses the H2 Database Engine. We take the option of an in-memory database that disappears when the JVM shutdown.

First, establish a DataSource object.

// Establish `DataSource`.
org.h2.jdbcx.JdbcDataSource dataSource = new JdbcDataSource();
// Set `DB_CLOSE_DELAY` to `-1` to keep in-memory database in existence after connection closes.
dataSource.setURL( "jdbc:h2:mem:pstmt_localdate_example_db;DB_CLOSE_DELAY=-1" );
dataSource.setUser( "scott" );
dataSource.setPassword( "tiger" );

On first connection, the database is implicitly created. The name comes from the URL field of our DataSource above. Then we execute SQL to create the table order_. We use a trailing underscore to avoid naming conflicts, per the SQL standard’s promise to never name keyword in that manner.

By the way, embedding SQL code in Java will be much easier when the text blocks feature arrives in Java 15 (previewed in Java 14).

// Create database implicitly upon connection, and create first table.
try (
        Connection conn = dataSource.getConnection() ;
        Statement stmt = conn.createStatement() ;
)
{
    String sql =
            "DROP TABLE IF EXISTS order_ ; \n "
                    +
                    "CREATE TABLE IF NOT EXISTS \n" +
                    "  order_ \n" +
                    "  ( \n" +
                    "      pkey_ UUID NOT NULL DEFAULT RANDOM_UUID() PRIMARY KEY , \n" +
                    "      description_ VARCHAR NOT NULL , \n" +
                    "      when_placed_ DATE NOT NULL \n" +
                    "  ) \n" +
                    ";";
    System.out.println( "sql = \n" + sql );
    stmt.execute( sql );
}
catch ( SQLException e )
{
    e.printStackTrace();
}

We insert a row.

// Insert row.
try (
        Connection conn = dataSource.getConnection() ;
        Statement stmt = conn.createStatement() ;
)
{
    String sql = "INSERT INTO order_ ( description_ , when_placed_ ) \n";
    sql += "VALUES (  ? , ?  ) \n";
    sql += ";";
    System.out.println( "sql = " + sql );
    try (
            PreparedStatement pstmt = conn.prepareStatement( sql , Statement.RETURN_GENERATED_KEYS ) ;
    )
    {

        pstmt.setString( 1 , "blah" );
        pstmt.setObject( 2 , LocalDate.now( ZoneId.of( "America/Montreal" ) ) );
        pstmt.executeUpdate();

        ResultSet rs = pstmt.getGeneratedKeys();
        System.out.println( "INFO - Reporting generated keys." );
        while ( rs.next() )
        {
            UUID uuid = rs.getObject( 1 , UUID.class );
            System.out.println( "generated keys: " + uuid );
        }
    }
}
catch ( SQLException e )
{
    e.printStackTrace();
}

Dump the row(s) to console. If you look further down this bit of code, you will see how we generate text using automatic localization. And we generate text using a custom formatter. I suggest going with localization generally over a hard-coded custom format.

// Dump all rows.
try (
        Connection conn = dataSource.getConnection() ;
        Statement stmt = conn.createStatement() ;
)
{
    System.out.println( "INFO - Reporting all rows in table `order_`." );
    String sql = "SELECT * FROM order_ ; ";
    System.out.println( "sql = " + sql );
    try ( ResultSet rs = stmt.executeQuery( sql ) ; )
    {
        while ( rs.next() )
        {
            UUID pkey = rs.getObject( "pkey_" , UUID.class );
            String description = rs.getString( "description_" );
            LocalDate whenPlaced = rs.getObject( "when_placed_" , LocalDate.class );

            // Dump to console.
            System.out.println( "-----------------" );

            System.out.println( "pkey = " + pkey );
            System.out.println( "description = " + description );
            System.out.println( "whenPlaced = " + whenPlaced );  // Standard ISO 8601 format.

            // Localized.
            Locale locale = new Locale( "fr" , "DZ" );  // French language, Algeria culture.
            DateTimeFormatter formatterLocalized = DateTimeFormatter.ofLocalizedDate( FormatStyle.SHORT ).withLocale( locale );
            String outputLocalized = whenPlaced.format( formatterLocalized );
            System.out.println( "whenPlaced (localized): " + outputLocalized );

            // Custom format.
            DateTimeFormatter formatterCustom = DateTimeFormatter.ofPattern( "dd/MM/uuuu" );
            String outputCustom = whenPlaced.format( formatterCustom );
            System.out.println( "whenPlaced (custom-format): " + outputCustom );

            System.out.println( "-----------------" );
        }
    }
}
catch ( SQLException e )
{
    e.printStackTrace();
}

When run.

-----------------
pkey = a4388a40-738b-44bd-b01a-2c487c7e08bf
description = blah
whenPlaced = 2020-06-20
whenPlaced (localized): 20/06/2020
whenPlaced (custom-format): 20/06/2020
-----------------

By the way, make a habit of including the semicolon to terminate your SQL statement. You can get away with its omission in some cases, but will cause problems in others.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Thank you for the answer, very interesting and i'll be sure to use it in the future. But as i said i'm a student, and they are explaining to use simpler object for now ;) – EllC01 Jun 20 '20 at 16:21
3

You are converting a Date to a string in your Database ('to_char'), then in Java you turn that string into a Date, but then you want to print it, so it uses the default format to turn your Date into a string.

So Date -> String -> Date -> String.

I suggest you either use 'to_char' to get the format you want, OR just fetch a date and then use SimpleDateFormat to turn it into a string of your desired format.

Benjamin Maurer
  • 3,602
  • 5
  • 28
  • 49
  • FYI, the `java.util.Date`, `java.sql.Date`, and `SimpleDateFormat` classes are all obsolete legacy now, supplanted by the *java.time* classes. – Basil Bourque Jun 20 '20 at 16:27
0

Without specifying a format, you will always get the same output because System.out.println displays LocalDate#toString().

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String dataord = "20/06/2020";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy", Locale.ITALY);
        LocalDate ld = LocalDate.parse(dataord, formatter);

        System.out.println("Date: " + ld);// Will display LocalDate#toString()

        // Display in specified formats
        System.out.println("Date: " + ld.format(DateTimeFormatter.BASIC_ISO_DATE));
        System.out.println("Date: " + ld.format(DateTimeFormatter.ofPattern("EEE MMM dd yyyy")));
        System.out.println("Date: " + ld.format(formatter));
    }
}

Output:

Date: 2020-06-20
Date: 20200620
Date: Sat Jun 20 2020
Date: 20/06/2020
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110