无法从 Java 中的结果集中获取日期值

Posted

技术标签:

【中文标题】无法从 Java 中的结果集中获取日期值【英文标题】:Unable to fetch Date Values from Result Set in Java 【发布时间】:2018-02-20 06:44:55 【问题描述】:

我正在尝试使用结果集从 Oracle 数据库中检索日期值。日期的格式类似于 dd-mmm-yy(如 17-MAY-18)。此处的列名称为 VALID_TO。默认值设置为 TO_DATE DB中的01.01.4000。我正在编写如下代码。

String sql_qry = "SELECT a.VALID_TO from table1 a where a.VALID_FROM > '01-JAN-
18' and a.VALID_TO > '31-JAN-18'";
this.preparedStatement = dbconnection.prepareStatement(sql_qry);
ResultSet rs = this.preparedStatement.executeQuery();

while (rs.next()) 
            AccountDetails detailsVo = new AccountDetails();
            detailsVo.setDateColumn(rs.getDate("VALID_TO"));
            accountDetails.add(detailsVo);
         

我得到的是默认值 01.01.4000,而不是数据库中的实际日期。如何获取实际值。我在上面导入了 java.sql.Date。

【问题讨论】:

你在哪里格式化日期? SQL 语句在哪里,顺便说一句? 这里少了很多:数据库中DATE的列定义; setDateColumn() 的代码;用于打印获得01/01/4000 的日期的代码。 @MauricePerry 对不起,我错过了。我已经编辑了这个问题。请你帮我解决这个问题 类别中的另一个问题“为什么我的数据库会做这种奇怪的事情?” 通常事实证明数据库并没有做奇怪的事情,只是两者之间存在一些差距数据库的实际状态以及您认为的状态。我的猜测是数据与您的预期不同,可能是因为您尚未提交更改。或者您填充了没有世纪的 VALID_TO(即年份 = 0018),这在使用 YY 格式掩码而不是 YYYY 时总是很危险。 【参考方案1】:

tl;博士

使用 java.time 类而不是旧的日期时间类。具体来说,LocalDate 表示仅日期值。 在您的 SQL 和准备好的语句中使用占位符。 通过 JDBC 4.2 直接传递 java.time 对象。

例子:

myPreparedStatement.setObject( 1 , startLocalDate ) ;
myPreparedStatement.setObject( 2 , stopLocalDate ) ;

……和……

myResultSet.getObject( … , LocalDate.class) 

java.time

使用 JDBC 4.2 及更高版本,您可以与数据库交换智能对象,而不是哑字符串。

占位符

使用占位符而不是文字来设置准备好的语句。

String sql = "SELECT * FROM tbl WHERE fromCol >= ? AND toCol < ? ;" ;

LocalDate

设置值以填充这些占位符。对于仅限日期的列,例如 SQL 标准类型 DATE,请使用 java.time.LocalDate 类。 LocalDate 类表示没有时间和时区的仅日期值。

LocalDate start = LocalDate.of( 2018 , Month.JANUARY , 1 ) ;  // First of January 2018.

半开

通常在日期时间工作中最好使用半开方法来定义时间跨度,其中开始是包含,而结束是独占。因此,如果您想要一月份的整个月份,请查询“等于或晚于该月的第一天并且小于 下个月的第一天”。

LocalDate stop = start.plusMonths( 1 ) ;           // First of February 2018.

或者,使用YearMonth 类来表示整个月,您的意图可能会更清楚。

YearMonth ym = YearMonth.of( 2018 , 1 ) ;         // January 2018.
LocalDate start = ym.atDay( 1 ) ;                 // First of January 2018.
LocalDate stop = ym.plusMonths( 1 ).atDay( 1 ) ;  // First of February 2018.

PreparedStatement & ResultSet

无论哪种方式,我们现在都有一对 LocalDate 对象来输入我们准备好的语句的占位符。

myPreparedStatement.setObject( 1 , start ) ;
myPreparedStatement.setObject( 2 , stop ) ;

从结果集中检索时:

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

避免使用旧的日期时间类

不需要java.util.Datejava.sql.Date 或任何其他与早期 Java 版本捆绑在一起的设计不佳的 hack 日期时间类。


关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。

使用符合JDBC 4.2 或更高版本的JDBC driver,您可以直接与您的数据库交换java.time 对象。不需要字符串也不需要 java.sql.* 类。

从哪里获得 java.time 类?

Java SE 8Java SE 9 及更高版本 内置。 标准 Java API 的一部分,带有捆绑实现。 Java 9 添加了一些小功能和修复。 Java SE 6Java SE 7 大部分 java.time 功能在ThreeTen-Backport 中向后移植到 Java 6 和 7。 Android java.time 类的 android 捆绑包实现的更高版本。 对于早期的 Android,ThreeTenABP 项目采用 ThreeTen-Backport(如上所述)。见How to use ThreeTenABP…

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuarter 和more。

【讨论】:

以上是关于无法从 Java 中的结果集中获取日期值的主要内容,如果未能解决你的问题,请参考以下文章

我无法从引导日历中获取日期值

在获取结果时,仅考虑从日期开始的前两个值

即使日期值相同,但无法获取记录器 [重复]

熊猫从python中的日期字符串列获取日期值

使用java在sqlite中选择两个日期之间的行

如何从java中的结果集中获取列名[重复]