使用 H2 数据库 JDBC 中的年份从负 -509 变为正 510
Year changing from negative -509 to a positive 510 in JDBC with H2 Database
-509
对比 510
我发现使用 JDBC 时出现了某种更改或错误的数据。所以我观察到在 Java 8 更新 151.
上使用 H2 Database 版本 1.4.196
这是一个完整的例子。
注意我们如何检索日期值三次,第一次作为 LocalDate
对象,第二次作为文本,第三次作为从强制转换 LocalDate
对象中提取的 int
年份数字.在文字版中我们可以看到年份确实是负数。神秘的是 LocalDate
有一个不同的年份数字,它是正数而不是负数。似乎是一个错误。
private void doIt ( )
{
System.out.println( "BASIL - Running doIt." );
try
{
Class.forName( "org.h2.Driver" );
} catch ( ClassNotFoundException e )
{
e.printStackTrace( );
}
try (
Connection conn = DriverManager.getConnection( "jdbc:h2:mem:" ) ; // Unnamed throw-away in-memory database.
)
{
conn.setAutoCommit( true );
String sqlCreate = "CREATE TABLE history ( id IDENTITY , when DATE ); ";
String sqlInsert = "INSERT INTO history ( when ) VALUES ( ? ) ; ";
String sqlQueryAll = "SELECT * FROM history ; ";
PreparedStatement psCreate = conn.prepareStatement( sqlCreate );
psCreate.executeUpdate( );
PreparedStatement psInsert = conn.prepareStatement( sqlInsert );
psInsert.setObject( 1 , LocalDate.of( 2017 , 1 , 23 ) );
psInsert.executeUpdate( );
psInsert.setObject( 1 , LocalDate.of( -509 , 1 , 1 ) );
psInsert.executeUpdate( );
PreparedStatement psQueryAll = conn.prepareStatement( sqlQueryAll );
ResultSet rs = psQueryAll.executeQuery( );
while ( rs.next( ) )
{
long l = rs.getLong( 1 ); // Identity column.
// Retrieve the same date value in three different ways.
LocalDate ld = rs.getObject( 2 , LocalDate.class ); // Extract a `LocalDate`, and implicitly call its `toString` method that uses standard ISO 8601 formatting.
String s = rs.getString( 2 ); // Extract the date value as text from the database using the database-engine’s own formatting.
int y = ( ( LocalDate ) rs.getObject( 2 , LocalDate.class ) ).getYear( ); // Extract the year number as an integer from a `LocalDate` object.
String output = "ROW: " + l+ " | " + ld + " | when as String: " + s+ " | year: " + y ;
System.out.println( output );
}
conn.close( );
} catch ( SQLException e )
{
e.printStackTrace( );
}
}
当运行.
ROW: 1 | 2017-01-23 | when as String: 2017-01-23 | year: 2017
ROW: 2 | 0510-01-01 | when as String: -509-01-01 | year: 510
因此,JDBC 似乎正在发生一些事情。请注意年份是如何显示为正 510 而不是负 509。我不理解这种行为。
我可以推断这是 JDBC rather than within LocalDate
. See this example code run live in IdeOne.com 中的一个问题,表明 LocalDate
对象确实携带并报告负年份。
LocalDate ld = LocalDate.of( -509 , 1 , 1 ) ;
System.out.println( "ld.toString(): " + ld ) ;
System.out.println( "ld.getYear(): " + ld.getYear() ) ;
注意我们如何做 not 在只处理 LocalDate
而没有 JDBC.[=27= 时从 -509 转换为 510 ]
ld: -0509-01-01
ld.getYear(): -509
我在H2项目上开了一个Issue ticket
问题是由java.sql.Date
转换成LocalDate
引起的
.
因为它是负数年份,所以 Calendar
实例保存获取的结果会将 year 转换为 1 - year 但是当转换为 LocalDate
java 没有考虑附加信息 (era==BC) 表明 year < 0
以下是返回之前执行的最终方法结果。
试试这个:
public class Test {
public static void main(String[] args) {
Calendar instance = Calendar.getInstance();
instance.set(-509,1,1);
java.sql.Date d = new Date(instance.getTime().getTime());
System.out.println(d.toLocalDate().getYear());// 510
}
}
谢谢奥莱 V.V。征求意见!!!
TL;DR:如果 JDBC 驱动程序内部使用 java.sql.Date
并使用 java.sql.Date.toLocalDate()
转换它,则可能是已弃用 Date.getYear()
将(至少有时)导致您观察到的行为。
这是猜测,但我发现它很有趣,可以分享。
我从 了解到,驱动程序确实使用了一个或多个遗留日期和时间 类,至少 Calendar
和 GregorianCalendar
。从 Calendar
到 LocalDate
的转换路径更多,因此通过 java.sql.Date
的转换路径只是其中之一。不过,其他转化路径可能会遇到同样的错误。
事实:toLocalDate
方法依赖于已弃用的 getYear
方法。资料来源:
@SuppressWarnings("deprecation")
public LocalDate toLocalDate() {
return LocalDate.of(getYear() + 1900, getMonth() + 1, getDate());
}
要查看 getYear
在公历前一年的表现,我尝试了:
OffsetDateTime dateTimeBce
= OffsetDateTime.of(-509, 1, 1, 0, 0, 0, 0, ZoneOffset.ofHours(1));
Date d = Date.from(dateTimeBce.toInstant());
System.out.println("d.toInstant() " + d.toInstant());
System.out.println("d.getYear() (deprecated): " + d.getYear()
+ ", means " + (d.getYear() + 1900));
由于 getYear
的年份是“基于 1900 年”,因此预期年份为 -2409。如果我们将 1900 添加到此,我们将得到 -509,即我们开始的年份。然而,该片段打印:
d.toInstant() -0510-12-31T23:00:00Z
d.getYear() (deprecated): -1390, means 510
第一行显示 Date
确实包含负年份(UTC 的偏移量转换将年份从 -509 更改为 -510;我选择了计算机时间的标准时间偏移量区域设置)。该片段使用 java.util.Date
,但 java.sql.Date
继承了 getYear
方法,我也用 java.sql.Date
重现了类似的行为。
我在 Internet 上进行了简短的搜索,没有找到任何关于可疑错误的提及。我们可能想更加努力。
错误,已修复
此问题是由 bug in H2 引起的。
现已修复,截至 2018-01。
-509
对比 510
我发现使用 JDBC 时出现了某种更改或错误的数据。所以我观察到在 Java 8 更新 151.
上使用 H2 Database 版本 1.4.196这是一个完整的例子。
注意我们如何检索日期值三次,第一次作为 LocalDate
对象,第二次作为文本,第三次作为从强制转换 LocalDate
对象中提取的 int
年份数字.在文字版中我们可以看到年份确实是负数。神秘的是 LocalDate
有一个不同的年份数字,它是正数而不是负数。似乎是一个错误。
private void doIt ( )
{
System.out.println( "BASIL - Running doIt." );
try
{
Class.forName( "org.h2.Driver" );
} catch ( ClassNotFoundException e )
{
e.printStackTrace( );
}
try (
Connection conn = DriverManager.getConnection( "jdbc:h2:mem:" ) ; // Unnamed throw-away in-memory database.
)
{
conn.setAutoCommit( true );
String sqlCreate = "CREATE TABLE history ( id IDENTITY , when DATE ); ";
String sqlInsert = "INSERT INTO history ( when ) VALUES ( ? ) ; ";
String sqlQueryAll = "SELECT * FROM history ; ";
PreparedStatement psCreate = conn.prepareStatement( sqlCreate );
psCreate.executeUpdate( );
PreparedStatement psInsert = conn.prepareStatement( sqlInsert );
psInsert.setObject( 1 , LocalDate.of( 2017 , 1 , 23 ) );
psInsert.executeUpdate( );
psInsert.setObject( 1 , LocalDate.of( -509 , 1 , 1 ) );
psInsert.executeUpdate( );
PreparedStatement psQueryAll = conn.prepareStatement( sqlQueryAll );
ResultSet rs = psQueryAll.executeQuery( );
while ( rs.next( ) )
{
long l = rs.getLong( 1 ); // Identity column.
// Retrieve the same date value in three different ways.
LocalDate ld = rs.getObject( 2 , LocalDate.class ); // Extract a `LocalDate`, and implicitly call its `toString` method that uses standard ISO 8601 formatting.
String s = rs.getString( 2 ); // Extract the date value as text from the database using the database-engine’s own formatting.
int y = ( ( LocalDate ) rs.getObject( 2 , LocalDate.class ) ).getYear( ); // Extract the year number as an integer from a `LocalDate` object.
String output = "ROW: " + l+ " | " + ld + " | when as String: " + s+ " | year: " + y ;
System.out.println( output );
}
conn.close( );
} catch ( SQLException e )
{
e.printStackTrace( );
}
}
当运行.
ROW: 1 | 2017-01-23 | when as String: 2017-01-23 | year: 2017
ROW: 2 | 0510-01-01 | when as String: -509-01-01 | year: 510
因此,JDBC 似乎正在发生一些事情。请注意年份是如何显示为正 510 而不是负 509。我不理解这种行为。
我可以推断这是 JDBC rather than within LocalDate
. See this example code run live in IdeOne.com 中的一个问题,表明 LocalDate
对象确实携带并报告负年份。
LocalDate ld = LocalDate.of( -509 , 1 , 1 ) ;
System.out.println( "ld.toString(): " + ld ) ;
System.out.println( "ld.getYear(): " + ld.getYear() ) ;
注意我们如何做 not 在只处理 LocalDate
而没有 JDBC.[=27= 时从 -509 转换为 510 ]
ld: -0509-01-01
ld.getYear(): -509
我在H2项目上开了一个Issue ticket
问题是由java.sql.Date
转换成LocalDate
引起的
.
因为它是负数年份,所以 Calendar
实例保存获取的结果会将 year 转换为 1 - year 但是当转换为 LocalDate
java 没有考虑附加信息 (era==BC) 表明 year < 0
以下是返回之前执行的最终方法结果。
试试这个:
public class Test {
public static void main(String[] args) {
Calendar instance = Calendar.getInstance();
instance.set(-509,1,1);
java.sql.Date d = new Date(instance.getTime().getTime());
System.out.println(d.toLocalDate().getYear());// 510
}
}
谢谢奥莱 V.V。征求意见!!!
TL;DR:如果 JDBC 驱动程序内部使用 java.sql.Date
并使用 java.sql.Date.toLocalDate()
转换它,则可能是已弃用 Date.getYear()
将(至少有时)导致您观察到的行为。
这是猜测,但我发现它很有趣,可以分享。
我从 Calendar
和 GregorianCalendar
。从 Calendar
到 LocalDate
的转换路径更多,因此通过 java.sql.Date
的转换路径只是其中之一。不过,其他转化路径可能会遇到同样的错误。
事实:toLocalDate
方法依赖于已弃用的 getYear
方法。资料来源:
@SuppressWarnings("deprecation")
public LocalDate toLocalDate() {
return LocalDate.of(getYear() + 1900, getMonth() + 1, getDate());
}
要查看 getYear
在公历前一年的表现,我尝试了:
OffsetDateTime dateTimeBce
= OffsetDateTime.of(-509, 1, 1, 0, 0, 0, 0, ZoneOffset.ofHours(1));
Date d = Date.from(dateTimeBce.toInstant());
System.out.println("d.toInstant() " + d.toInstant());
System.out.println("d.getYear() (deprecated): " + d.getYear()
+ ", means " + (d.getYear() + 1900));
由于 getYear
的年份是“基于 1900 年”,因此预期年份为 -2409。如果我们将 1900 添加到此,我们将得到 -509,即我们开始的年份。然而,该片段打印:
d.toInstant() -0510-12-31T23:00:00Z
d.getYear() (deprecated): -1390, means 510
第一行显示 Date
确实包含负年份(UTC 的偏移量转换将年份从 -509 更改为 -510;我选择了计算机时间的标准时间偏移量区域设置)。该片段使用 java.util.Date
,但 java.sql.Date
继承了 getYear
方法,我也用 java.sql.Date
重现了类似的行为。
我在 Internet 上进行了简短的搜索,没有找到任何关于可疑错误的提及。我们可能想更加努力。
错误,已修复
此问题是由 bug in H2 引起的。
现已修复,截至 2018-01。