【问题标题】:LocalDate.parse(String, formatter) return wrong format [duplicate]LocalDate.parse(String,formatter)返回错误的格式[重复]
【发布时间】:2020-10-10 18:00:00
【问题描述】:

我必须在数据库中查询日期,然后使用 LocalDate 和格式化程序以不同的格式进行可视化。问题是,无论我尝试了多少不同的格式,查询都会以 JDBC 默认格式(yyyy-mm-dd)可视化。 请注意,日期存储在 DATE 字段中(如 01-GEN-20)。 一个典型的输出是:日期: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);
            
            
        }
    }

【问题讨论】:

  • 那是因为您正在打印LocalDate 对象。 LocalDate 本身没有格式,toString() 只是返回对象的合理表示。如果您想格式化LocalDate,请使用ld.format(formatter)
  • 你不能只打印dataord吗?数据库版本?如果您真的想使用 LocalDate 变量,请重用格式化程序(请参阅here

标签: java formatter localdate


【解决方案1】:

LocalDate::format

正如其他人指出的那样,您的行 System.out.println("Date: " + ld); 隐式调用 LocalDate::toString 而不使用您的 DateTimeFormatter 对象。所以你的自定义格式模式永远不会被应用。

在生成文本时应用您的格式化程序。不要调用LocalDate::toString,而是调用LocalDate::format

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

20/06/2020

你说:

查询以 JDBC 默认格式 (yyyy-mm-dd) 可视化。

不,没有“JDBC 默认格式”之类的东西。 LocalDate::toString 生成的文本是标准的ISO 8601 格式,YYYY-MM-DD。这与JDBC无关。

您的代码还有其他问题。所以请继续阅读。

使用智能对象,而不是哑字符串

假设您的数据库列的类型类似于 SQL 标准类型 DATE,请使用符合 JDBC 4.2 或更高版本的 JDBC 驱动程序将值作为 LocalDate 对象检索。停止思考文本。考虑智能对象,而不是愚蠢的字符串。

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

同样,将适当的对象发送到数据库,而不仅仅是文本。 Use a prepared statement? 占位符。

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

将检索与格式化/展示分开

只有稍后您才应该考虑格式化数据以呈现给用户。通常最好将数据的检索与数据的格式/呈现分开。首先将数据收集到对象中,然后生成用于演示的文本。

使用即将推出的记录功能previewed in Java 14arriving in Java 15,将数据收集到对象中变得更加容易和简单。构造函数、getter方法、toStringequals&hashCode等都是在后台自动合成的。

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.

以标准ISO 8601 格式生成表示对象内值的文本。请注意,LocalDate 对象没有文本,没有“格式”。这样的对象知道怎么解析文本,知道怎么生成文本,不是本身就是文本。

String output = localDate.toString() ;

java.time在生成文本的同时自动本地化。

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.

或者,如果您坚持,请指定您自己的自定义格式模式。

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

示例

这是一个完整示例的源代码。

此示例使用H2 Database Engine。我们选择in-memory database 选项,当JVM 关闭时它会消失。

首先,建立一个DataSource对象。

// 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" );

在第一次连接时,数据库是隐式创建的。该名称来自我们上面DataSource 的URL 字段。然后我们执行SQL创建表order_。我们使用尾随下划线来避免命名冲突,因为 SQL 标准承诺永远不会以这种方式命名关键字。

顺便说一句,当text blocks feature 到达 Java 15 (previewed in Java 14) 时,在 Java 中嵌入 SQL 代码会容易得多。

// 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();
}

我们插入一行。

// 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 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();
}

运行时。

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

顺便说一句,养成使用分号来终止 SQL 语句的习惯。在某些情况下你可以避免它的遗漏,但在其他情况下会导致问题。

【讨论】:

  • 感谢您的回答,非常有趣,我以后一定会使用它。但正如我所说,我是一名学生,他们正在解释现在使用更简单的对象;)
【解决方案2】:

您正在将日期转换为数据库中的字符串 ('to_char'),然后在 Java 中将该字符串转换为日期,但随后您想打印它,因此它使用默认格式将日期转换为一个字符串。

所以日期 -> 字符串 -> 日期 -> 字符串。

我建议你要么使用 'to_char' 来获取你想要的格式,要么只获取一个日期,然后使用 SimpleDateFormat 将其转换为你想要的格式的字符串。

【讨论】:

  • 仅供参考,java.util.Datejava.sql.DateSimpleDateFormat 类现在都已过时,被 java.time 类所取代。
【解决方案3】:

如果不指定格式,您将始终获得相同的输出,因为System.out.println 显示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));
    }
}

输出:

Date: 2020-06-20
Date: 20200620
Date: Sat Jun 20 2020
Date: 20/06/2020

【讨论】:

    猜你喜欢
    • 2020-06-21
    • 2015-09-02
    • 2023-04-05
    • 1970-01-01
    • 2018-01-02
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多