ResultSet getDate() 返回不正确和正确的日期

Posted

技术标签:

【中文标题】ResultSet getDate() 返回不正确和正确的日期【英文标题】:ResultSet getDate() is returning incorrect and correct dates 【发布时间】:2019-12-03 21:00:22 【问题描述】:

我正在从假期表中创建一个 LocalDate 列表。数据库表中的日期都是正确的,但是当我使用 ResultSet getDate() 方法并使用所有日期填充列表时,其中 4 个日期是错误的,6 个是正确的。我正在寻找任何帮助来弄清楚为什么会这样。

final LocalDate currentDay = LocalDate.now();
final List<LocalDate> holidays = getHolidays(currentDay);

//This method takes in a date and calculates the holidays that occur that year
public static List<LocalDate> getHolidays(final LocalDate date) 
 final List<LocalDate> holidayList = new ArrayList<LocalDate>();

 try 
   final PreparedStatement holidaysByYearQuery = conn.prepareStatement(
      "SELECT fulldate FROM holidays WHERE YEAR(fulldate) = ?");

    holidaysByYearQuery.setObject(1, date.getYear());

    final ResultSet holidaysByYearResult = holidaysByYearQuery.executeQuery();

    while (holidaysByYearResult.next()) 
      final Date holidate = (Date) holidaysByYearResult.getObject(1);
      final LocalDate holiday = holidate.toLocalDate();
      holidayList.add(holiday);
    
   catch (final SQLException e) 
    LOGGER.log(Level.WARNING, "Could not query holiday table: " + e.getMessage());
  
  return holidayList;
 

// This is the query used in Java:
com.mysql.cj.jdbc.PreparedStatement@1c27c773: SELECT fulldate FROM holidays WHERE YEAR(fulldate) = 2019

// Here is the list that is returned from the method
[2018-12-31, 2019-02-17, 2019-04-19, 2019-05-20, 2019-07-01, 2019-08-05, 2019-09-02, 2019-10-14, 2019-12-24, 2019-12-25]

这里是数据库表信息。这是非常基本的。

CREATE TABLE holidays( 
province VARCHAR(255), 
holiday VARCHAR(255), 
fulldate DATETIME);

INSERT INTO holidays(province, holiday, fulldate) VALUES
('Ontario', 'New Years', '2019-01-01'), 
('Ontario', 'Family Day', '2019-02-18'), 
('Ontario', 'Good Friday', '2019-04-19'), 
('Ontario', 'Victoria Day', '2019-05-20'), 
('Ontario', 'Canada Day', '2019-07-01'), 
('Ontario', 'Civic Holiday', '2019-08-05'), 
('Ontario', 'Labour Day', '2019-09-02'), 
('Ontario', 'Thanksgiving', '2019-10-14'), 
('Ontario', 'Christmas Day', '2019-12-25'), 
('Ontario', 'Boxing Day', '2019-12-26');

// This is the select result from the query above

+---------------------+
|       fulldate      |
+---------------------+
| 2019-01-01 00:00:00 |
+---------------------+
| 2019-02-18 00:00:00 |
+---------------------+
| 2019-04-19 00:00:00 |
+---------------------+
| 2019-05-20 00:00:00 |
+---------------------+
| 2019-07-01 00:00:00 |
+---------------------+
| 2019-08-05 00:00:00 |
+---------------------+
| 2019-09-02 00:00:00 |
+---------------------+
| 2019-10-14 00:00:00 |
+---------------------+
| 2019-12-25 00:00:00 |
+---------------------+
| 2019-12-26 00:00:00 |
+---------------------+

如您所见,列表两端的 2 个日期不正确。我假设 getDate() 方法发生了一些事情。任何人都可以对此有所了解吗?干杯。

【问题讨论】:

您的列的数据类型究竟是什么?您使用的是什么数据库系统? 如果您只存储日期,为什么要使用 DateTime 作为类型? ResultSet 有一个 getDate 方法。我的猜测是,这是关于时区和不同的夏令时变化 @BasilBourque DATETIME 和 Mysql(Innodb) @JoakimDanielson 这只是我现在拥有的模式。我之前使用过 DATE,它有完全相同的问题。 您对仅日期值使用了错误的类型。将您的列定义为DATE 【参考方案1】:

您为什么要将糟糕的遗留类Date 与现代LocalDate 混合在一起?你为什么要投射(Date)

SQL 标准 DATE

如果您的列属于类似于 SQL 标准 DATE 的类型,则将 LocalDate 与符合 JDBC 4.2 或更高版本的 JDBC 驱动程序一起使用。

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

SQL 标准 TIMESTAMP WITH TIME ZONE

如果您的列属于类似于 SQL 标准 TIMESTAMP WITH TIME ZONE 的类型,那么您必须考虑时区来确定日期。

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
ZoneId z = ZoneId.of( "Australia/Sydney" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
LocalDate ld = zdt.toLocalDate() ;

SQL 标准 TIMESTAMP WITHOUT TIME ZONE

如果您的列属于类似于 SQL 标准 TIMESTAMP WITHOUT TIME ZONE 的数据类型,例如 MySQL 类型 DATETIME,请使用 Java 类型 LocalDateTime。这种类型只有一个日期和时间,没有时区的上下文或与 UTC 的偏移量。所以这种类型确实代表片刻。

LocalDateTime ldt = myResultSet.getObject( … , OffsetDateTime.class ) ;
LocalDate ld = ldt.toLocalDate() ;

【讨论】:

强制转换是旧的解决方案尝试,因为 resultSet.getDate() 不返回 LocalDate。使用 myResultSet.getObject( ... , LocalDate.class ) ;作品。 Date 和 LocalDate 的混合是导致这几个日期偏移的原因吗?我也很欣赏有关带和不带时区的信息。这似乎是一个更强大的解决方案。 @RWri - 对于东部标准时间 (EST) 生效的日期,Date 值不正确。 EDT 于 2019 年 3 月 10 日开始,将于 2019 年 11 月 3 日结束。除非指定了其他时区,否则 JDBC 的默认行为是将 java.sql.Date 与 JVM 的默认时区相关联。显然,元旦的日期/时间值被返回为2018-12-31 23:00:00 EST,并且被截断为2018-12-31 @GordThompson 很有趣。你知道为什么它只在 4/10 的日期不正确吗?如果它是由时区引起的,我希望所有日期都会偏移。 @RWri re:“如果它是由时区引起的,我希望所有日期都会偏移。” - 不必要。例如,当您的 JVM 使用America/Toronto 时区(尊重 EST/EDT)而 MySQL 服务器使用固定的区域偏移量时,事情可能会变得混乱,例如,UTC-4(不考虑标准/日光时间)。 Gord Thompson 的 cmets 是正确的,并说明了为什么永远不应该使用麻烦的遗留类,例如 java.sql.Datejava.util.DateCalendar

以上是关于ResultSet getDate() 返回不正确和正确的日期的主要内容,如果未能解决你的问题,请参考以下文章

JDBC ResultSet getDate 失去精度

来自ResultSet java的getDateTime

JDBC ResultSet:我需要一个 getDateTime,但只有 getDate 和 getTimeStamp

ResultSet 不为空,但 resultset.next() 返回 false

关于对ResultSet 中next() 方法的描述及用法是啥啊

Java ResultSet未正确关闭