如何将java.util.Date转换为java.sql.Date?
如何将java.util.Date转换为java.sql.Date?
我正在尝试使用java.util.Date
作为输入,然后创建一个查询-因此我需要一个java.sql.Date
。
我很惊讶地发现它不能隐式或显式地进行转换-但我甚至不知道我应该怎么做,因为Java API对我来说仍然是相当新的。
tl;dr
如何将java.util.Date转换为java.sql.Date?
不要这样做。
这两个Date
类已经过时了。 Sun,Oracle和JCP社区多年前放弃了这些传统的日期时间类,统一采用JSR 310定义的java.time类
- 使用java.time类而不是JDBC 4.2或更高版本的旧的
java.util.Date
和java.sql.Date
类。 - 如果需要与尚未更新到java.time的代码进行交互,则需进行转换。
传统的 | 现代的 | 转换 |
---|---|---|
java.util.Date |
java.time.Instant |
java.util.Date.toInstant() java.util.Date.from( Instant ) |
java.sql.Date |
java.time.LocalDate |
java.sql.Date.toLocalDate() java.sql.Date.valueOf( LocalDate ) |
带有PreparedStatement
的示例查询。
myPreparedStatement.setObject( … , // Specify the ordinal number of which argument in SQL statement. myJavaUtilDate.toInstant() // Convert from legacy class `java.util.Date` (a moment in UTC) to a modern `java.time.Instant` (a moment in UTC). .atZone( ZoneId.of( "Africa/Tunis" ) ) // Adjust from UTC to a particular time zone, to determine a date. Instantiating a `ZonedDateTime`. .toLocalDate() // Extract a date-only `java.time.LocalDate` object from the date-time `ZonedDateTime` object. )
替代方式:
- 使用
Instant
而不是java.util.Date
,两者都表示UTC中的一个时刻,但现在精确到纳秒而不是毫秒。 - 使用
LocalDate
而不是java.sql.Date
,两者都表示没有日期的时间和时区。
细节
如果您正在尝试使用仅具有日期(不含时间,不含时区)的值,则应使用LocalDate
类而不是java.util.Date
。
java.time
在Java 8及更高版本中,早期版本的Java中捆绑的令人困扰的旧日期时间类已被新的java.time包取代。请参见Oracle教程。大部分功能已经被导回到Java 6&7中的ThreeTen-Backport中,并在ThreeTenABP中进一步适应了Android。
SQL数据类型 DATE
表示只有日期而没有时间和时区。Java 8 中引入了 java.time.LocalDate
类型,正好满足这样的要求。我们可以使用指定时区的今天的日期来创建这样的值(时区在确定日期时很重要,例如新的一天在巴黎比蒙特利尔早)。
LocalDate todayLocalDate = LocalDate.now( ZoneId.of( "America/Montreal" ) ); // Use proper "continent/region" time zone names; never use 3-4 letter codes like "EST" or "IST".
在这个阶段,我们已经完成了。如果你使用的JDBC驱动符合JDBC 4.2规范,你应该可以在 PreparedStatement
上使用 setObject
通过传递一个 LocalDate
存储到 SQL DATE 字段中。
myPreparedStatement.setObject( 1 , localDate );
同样地,使用 ResultSet::getObject
从 SQL DATE 列获取到 Java 的 LocalDate
对象,通过指定第二个参数中的类,使你的代码具备类型安全性。
LocalDate localDate = ResultSet.getObject( 1 , LocalDate.class );
换句话说,在 JDBC 4.2 或更高版本下,这个问题是不相关的。
如果你的 JDBC 驱动程序不是以这种方式运行的,那么你需要回退并将其转换为 java.sql 类型。
转换为 java.sql.Date
要进行转换,请使用旧的日期时间类中添加的新方法。我们可以调用 java.sql.Date.valueOf(…)
来将 LocalDate
转换为 java.sql.Date
。
java.sql.Date sqlDate = java.sql.Date.valueOf( todayLocalDate );
反过来也可以这么做。
LocalDate localDate = sqlDate.toLocalDate();
从 java.util.Date
进行转换
虽然你应该避免使用旧的日期时间类,但在使用现有代码时可能会被迫这样做。如果需要这样做,那么可以进行 java.time 和 java.util.Date 类型之间的转换。
使用代表 UTC 时间轴上的瞬间的 Instant
类,类似于 java.util.Date
。但要注意,Instant
具有高达纳秒的分辨率,而 java.util.Date
只有 毫秒 级别的分辨率。
为了进行转换,可以使用添加到旧类中的新方法。例如,java.util.Date.from( Instant )
和 java.util.Date::toInstant
。
Instant instant = myUtilDate.toInstant();
要确定日期,我们需要一个时区的上下文。对于特定的时刻,由于时区不同,日期会在全球范围内变化。应用 ZoneId
来获取 ZonedDateTime
。
ZoneId zoneId = ZoneId.of ( "America/Montreal" ); ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , zoneId ); LocalDate localDate = zdt.toLocalDate();
† java.sql.Date 类假装是没有时间的日期,但实际上会调整为凌晨时间的时间。混乱吗?是的,旧的日期时间类是一团糟。
关于 java.time
Java 8 及其后续版本内建 java.time 框架。这些类代替了麻烦的旧遗留日期时间类,如 java.util.Date
、Calendar
和 SimpleDateFormat
。
要了解更多信息,请参阅 Oracle 教程。在 Stack Overflow 上搜索许多示例和解释。规范是 JSR 310。
项目 Joda-Time,现在处于维护模式,建议迁移到 java.time 类。
可以直接使用 java.time 对象与数据库交换。使用符合 JDBC 4.2 或更高版本标准的 JDBC 驱动程序。不需要字符串,也不需要 java.sql.*
类。Hibernate 5 和 JPA 2.2 支持 java.time。
如何获取 java.time 类?
- Java SE 8、Java SE 9、Java SE 10、Java SE 11 和以后版本 - 与附带实现的标准 Java API 的一部分。
- Java 9 带来了一些次要的功能和修复。
- Java SE 6 和 Java SE 7
- 大多数 java.time 功能都被移植到了 ThreeTen-Backport 中的 Java 6 和 7。
- Android
- Android 的后续版本(26+)捆绑了 java.time 类的实现。
- 对于早期的 Android (<26),一个被称为“API 反混淆”的过程将最初没有构建到 Android 中的 java.time 的一个子集 功能带入。
- 如果反混淆没有提供您需要的内容,则项目 ThreeTenABP 将适配 ThreeTen-Backport(前面提到过) 到 Android。请参见 如何使用 ThreeTenABP...。
ThreeTen-Extra项目扩展了java.time的附加类。该项目是java.time可能未来增加的类的实验场。您可能会在这里找到一些有用的类,例如Interval
、YearWeek
、YearQuarter
和更多。
算了吧....
public class MainClass { public static void main(String[] args) { java.util.Date utilDate = new java.util.Date(); java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime()); System.out.println("utilDate:" + utilDate); System.out.println("sqlDate:" + sqlDate); } }