无法重现您的测试失败
您的代码:
LocalDate.parse( "1900-01-01" )
...按照记录工作,产生 1900 年 1 月 1 日的值。
LocalDate ld = LocalDate.parse("1900-01-01") ;
System.out.println( ld ) ;
看到code run live at IdeOne.com。
1900-01-01
➥ 你的代码肯定比你向我们展示的要多。
使用 H2 的示例应用
你说:
我猜想更改是在 H2 数据库的保存操作期间进行的。
让我们试试吧。这是一个使用 H2 版本 1.4.200 的完整示例应用程序。从带有 Java 14 的 macOS Mojave 上的 IntelliJ 2020.1 运行。
我们有一个表event_,其中有一个UUID 类型的id_ 列和一个LocalDate 类型的列when_。我们为值 1900-01-01 写入单个值。
如您所见,如果您运行此代码,我们会返回一个 LocalDate 对象,toString 方法为其返回 1900-01-01。
package work.basil.example;
import org.h2.jdbcx.JdbcDataSource;
import java.sql.*;
import java.time.LocalDate;
import java.util.Objects;
import java.util.UUID;
public class H2Example
{
public static void main ( String[] args )
{
H2Example app = new H2Example();
app.doIt();
}
private void doIt ( )
{
JdbcDataSource dataSource = Objects.requireNonNull( new JdbcDataSource() ); // Implementation of `DataSource` bundled with H2.
dataSource.setURL( "jdbc:h2:mem:localdate_example_db;DB_CLOSE_DELAY=-1" ); // Set `DB_CLOSE_DELAY` to `-1` to keep in-memory database in existence after connection closes.
dataSource.setUser( "scott" );
dataSource.setPassword( "tiger" );
String sql = null;
try (
Connection conn = dataSource.getConnection() ;
)
{
String tableName = "event_";
sql = "CREATE TABLE " + tableName + " (\n" +
" id_ UUID DEFAULT random_uuid() PRIMARY KEY ,\n" +
" when_ DATE NOT NULL\n" +
");";
try ( Statement stmt = conn.createStatement() ; )
{
stmt.execute( sql );
}
// Insert row.
sql = "INSERT INTO event_ ( when_ ) " + "VALUES ( ? ) ;";
try (
PreparedStatement preparedStatement = conn.prepareStatement( sql ) ;
)
{
LocalDate localDate = LocalDate.parse( "1900-01-01" );
preparedStatement.setObject( 1 , localDate ); // Yesterday.
preparedStatement.executeUpdate();
}
// Query all.
sql = "SELECT * FROM event_ ;";
try (
Statement stmt = conn.createStatement() ;
ResultSet rs = stmt.executeQuery( sql ) ;
)
{
while ( rs.next() )
{
//Retrieve by column name
UUID id = rs.getObject( "id_" , UUID.class ); // Pass the class to be type-safe, rather than casting returned value.
LocalDate localDate = rs.getObject( "when_" , LocalDate.class ); // Ditto, pass class for type-safety.
//Display values
System.out.println( "id_: " + id + " | when_: " + localDate );
}
}
}
catch ( SQLException e )
{
e.printStackTrace();
}
}
}
当示例应用运行时:
id_: 949830e0-77c8-49a3-8804-0972ff70ca2c |当_:1900-01-01
不要依赖默认时区
您的代码:
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
……部署时风险很大。设置时区会立即影响在该 JVM 中运行的所有应用程序的所有线程中的所有代码。您可能正在从其他应用程序或您自己应用程序的任何其他部分的脚下拉开地毯。
➥ 最好不要依赖 JVM 当前的默认时区。
要捕捉以 UTC 显示的当前时刻,只需调用 Instant.now。 Instant 代表 UTC 中的时刻,分辨率为纳秒。此类替换java.util.Date。
Instant instant = Instant.now() ; // Capture the current moment in UTC.
对于数据库工作,使用更灵活的类OffsetDateTime。 JDBC 4.2 规范莫名其妙地需要支持OffsetDateTime,而不是更常用的Instant 和ZonedDateTime。
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ; // Capture the current moment in UTC.
将其写入数据库。
myPreparedStatement.setObject( … , odt ) ;
检索。
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
当记录一个时刻(时间线上的一个特定点)时,例如OffsetDateTime 表示的那个时刻,你在数据库中的列必须是类似于 SQL 标准类型 TIMESTAMP WITH TIME ZONE 的数据类型(不是WITHOUT)。在 H2 中,要使用的数据类型就是 TIMESTAMP WITH TIME ZONE。