为什么不能在 java.sql.Date 上调用 toInstant() ?

java.util.Date类有一个名为 toInstant()的方法,它将 Date实例转换为 java.time.Instant

java.sql.Date类扩展了 java.util.Date类,但是当我尝试在 java.sql.Date上调用 toInstant()时,会收到一个 UnsupportedOperationException

为什么 toInstant()java.sql.Date上是不受支持的操作?

什么是“正确”的方法来转换一个 java.sql.Date到一个 java.time.Instant

46410 次浏览

根据 JavaDoc

由于 sql.Date没有时间分量,因此不可能将其转换为 time.Instant

此方法始终引发 Unsupport tedOperationException,并且应该 因为 SQLDate 值没有时间组件。

Java.sql.Date 仅支持 Date 组件(日期、月份、年份)。它不支持时间组件(小时、分钟、秒、毫秒)。转瞬即逝同时需要 Date 和 Time 组件,因此在 java.sql 上使用 toInstant。Date 实例抛出 Unsupport tedOperationException 异常。

到即时 Java 文档

此方法总是引发 不应该使用,因为 SQL 日期 值没有时间成分。

Date OR java.sql.Timestamp 同时具有 Date/Time 组件,因此 toInstant ()可以工作!

你可以这样做:

// Time is 00:00:00.000


new java.util.Date(sqlDate.getTime()).toInstant()

更新:

Instant.ofEpochMilli(sqlDate.getTime());


// and
new java.util.Date(sqlDate.getTime()).toInstant();

将返回相同的结果,因为 toInstant ()方法在内部调用 Instant.ofEpochMilli (getTime ())。

public Instant toInstant() {
return Instant.ofEpochMilli(getTime());
}

到目前为止给出的答案集中在 java.sql.Date没有时间信息这一细节上。这是正确的,但不是真正或充分的原因,为什么这种类型不能提供直接转换到 Instant。不幸的是,Java-8文件也犯了同样的错误,让用户认为问题只是因为缺少时间信息。

从概念上讲,类型 java.sql.Date表示一个本地类型。它建立了一个日历日期,这个日期在我们地球的任何地区都是不同的。但是 Instant在我们的地球上是一样的。因此,用户需要一个时区或时区偏移量来进行转换。

不幸的是,类型 java.sql.Date继承自全局类型(类似即时类型)的 java.util.Date。但是,这种继承实际上表示实现继承,而不是类型继承。考虑打破这些旧 JDBC 类的设计的另一个理由。因此,确实有可能使用黑客通过其方法 getTime()java.util.Date的实例中包装 java.sql.Date,这最终允许直接转换到瞬间。但是: 此转换隐式使用系统的默认时区。

那么,如何正确地转换在一个迂腐的方式?让我们再考虑一下指向正确方向的 Java-8文件:

java.sql.Date sqlDate = ...;
LocalDate calendarDate = sqlDate.toLocalDate();
ZonedDateTime zdt = calendarDate.atStartOfDay(ZoneId.of("Europe/Paris"));
Instant instant = zdt.toInstant();

java.sql.Datejava.time之间的正确映射是 LocalDate:

LocalDate date = sqlDate.toLocalDate();

如果您真的必须 ,那么您可以派生一个 Instant,尽管额外的信息(时间)将是任意的。例如:

Instant i = date.atStartOfDay(ZoneOffset.UTC).toInstant();

如果你没有时间在你的日期-转换为毫米:

Instant.ofEpochMilli(date.getTime())
.atZone(ZoneId.systemDefault())
.toLocalDate();

Date (imho)的实现并不完美。

为了将 java.util.Date 转换为 LocalDate,网页上充满了这样的代码块:

dateToConvert.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate();
  • 上面的代码非常适合 java.util.Date,因为它实现 toInstant ()的方式(正如预期的“ return Instant.ofEpochMilli (getTime ())”)
  • 作为 java.sql。Date 是 java.util 的子类。在 Date 对象上运行的 Date 代码现在可能知道它在 java.sql 上运行。日期。(嘿-这是面向对象的一个方面,对吧? ?).所以如果它得到 java.util。日期代码工作得很好,如果它得到 java.sql。失败的日期。
  • 代码现在可以显式检查 Date 类型,然后(如果它在 java.sql 上操作的话)。Date)它可以对 java.sql 进行向下转换。Date 并使用 toLocalDate ()方法。不用说,这是丑陋的。

作为开发人员,我希望有一个方法可以正常工作—— toLocalDate (在内部使用不推荐的方法)只适用于 java.sql。所以不能在 java.util 上使用的日期。Date 和 toInstant 在 java.sql 上失败。日期。

我将“ Date to LocalDate”转换代码改为:

public static LocalDate asLocalDate(java.util.Date date) {
return date == null ? null : LocalDate.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
}

这与传入的日期类型无关。基本上它的意思是“不要调用 java.util。ToInstant () ,因为您可能会得到一个 java.sql。日期,然后破坏您的代码。

我真的不明白他们为什么要在 JDK 中故意实现这样的陷阱。