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

And*_*ose 46 java java-8 java-time

java.util.Date班有一个名为方法toInstant()的转换Date实例到java.time.Instant.

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

为什么toInstant()不支持操作java.sql.Date

什么是"正确"的方式到转换java.sql.Datejava.time.Instant

ass*_*ias 37

java.sql.Date和之间的正确映射java.timeLocalDate:

LocalDate date = sqlDate.toLocalDate();
Run Code Online (Sandbox Code Playgroud)

如果你真的必须,你可以得到一个Instant,虽然额外的信息(时间)将是任意的.例如:

Instant i = date.atStartOfDay(ZoneOffset.UTC).toInstant();
Run Code Online (Sandbox Code Playgroud)


Yas*_*jaj 27

检查JavaDoc

由于sql.Date没有时间组件,因此无法将其转换为time.Instant

此方法始终抛出UnsupportedOperationException,因为SQL Date值没有时间组件,所以不应使用此方法.

  • 现在,问题是_why_它是这样设计的.可以想象它的默认设置为时间信息设置为0.无法在邮件列表中找到任何内容. (3认同)
  • @Tunaki这个逻辑让我觉得这是因为父类`util.Date`有一个公共`toInstant`方法,子类不应该使用它.因此,他们不是将其作为"final"(保留继承逻辑),而是选择覆盖它并使其无法使用. (2认同)
  • 但是,使用与 java.util.Date 相同的逻辑的“Instant”将产生正确且合乎逻辑的结果,同时避免违反多态性契约。甲骨文做出了一个非常令人头疼的选择。 (2认同)

Loc*_*Loc 25

java.sql.Date只有Date组件(日期,月份和年份).它没有日期和时间组件.toInstant需要Date/Time组件,所以toSstant在java.sql.Date实例上抛出UnsupportedOperationException异常.

java.util.Date或java.sql.Timestamp都有日期/时间组件,所以toInstant()工作!

你可以这样做:

// Time is 00:00:00.000

new java.util.Date(sqlDate.getTime()).toInstant() 
Run Code Online (Sandbox Code Playgroud)

更新:

Instant.ofEpochMilli(sqlDate.getTime());

// OR
new java.util.Date(sqlDate.getTime()).toInstant();
Run Code Online (Sandbox Code Playgroud)

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

public Instant toInstant() {
    return Instant.ofEpochMilli(getTime());
}
Run Code Online (Sandbox Code Playgroud)


Men*_*ild 14

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

从概念上讲,类型java.sql.Date表示本地类型.它模拟了一个日历日期,它可以在我们全球任何地区都不同.但是Instant我们的地球周围是一样的.因此,用户需要时区或时区偏移才能进行转换.

可悲的是,类型java.sql.Date继承java.util.Date了全局类型(类似即时).但是,此继承实际上表示实现继承,而不是类型继承.考虑破坏这些旧JDBC类的设计的另一个原因.因此,确实可以使用hack将java.sql.Date其方法包装在其最终允许直接转换为瞬间getTime()的实例中java.util.Date.但是:此转换隐式使用系统的默认时区.

那么如何以迂腐的方式正确转换呢?让我们再次考虑Java-8文档,这里指出了正确的方向:

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


Zon*_*Zon 6

如果您的日期中没有时间 - 将其转换为毫秒:

Instant.ofEpochMilli(date.getTime())
   .atZone(ZoneId.systemDefault())
   .toLocalDate();
Run Code Online (Sandbox Code Playgroud)