UnsupportedOperationException - 为什么不能在 java.sql.Date 上调用 toInstant()?
UnsupportedOperationException - Why can't you call toInstant() on a java.sql.Date?
java.util.Date
class 有一个名为 toInstant()
的方法,可将 Date
实例转换为 java.time.Instant
.
java.sql.Date
class 扩展了 java.util.Date
class,但是当我尝试在 java.sql.Date
上调用 toInstant()
时,我收到一个 UnsupportedOperationException
.
为什么 toInstant()
是 java.sql.Date
上不受支持的操作?
将 java.sql.Date
转换为 java.time.Instant
的 "correct" 方法是什么?
根据JavaDoc
由于 sql.Date
没有时间成分,因此无法将其转换为 time.Instant
This method always throws an UnsupportedOperationException and should
not be used because SQL Date values do not have a time component.
java.sql.Date supports only Date components (date, month, year). It does NOT support time components (hour, minute, second, millisecond). toInstant 需要日期和时间组件,因此 java.sql.Date 实例上的 toInstant 会抛出 UnsupportedOperationException 异常。
toInstant Java doc
This method always throws an
UnsupportedOperationException and should not be used because SQL Date
values do not have a time component.
java.util.Date 或 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();
将 return 相同的结果,因为 toInstant() 方法在内部调用 Instant.ofEpochMilli(getTime())。
public Instant toInstant() {
return Instant.ofEpochMilli(getTime());
}
到目前为止给出的答案集中在 java.sql.Date
没有时间信息的细节上。这是正确的,但不是此类型不能提供到 Instant
的直接转换的真实或充分理由。不幸的是 documentation of Java-8 确实犯了同样的错误,让用户认为问题只是因为缺少时间信息。
从概念上讲,java.sql.Date
类型表示本地类型。它模拟了一个日历日期,该日期在我们全球的任何地区都可能不同。但是 Instant
在我们的地球上是一样的。 因此用户需要时区或时区偏移量来进行转换。
不幸的是,java.sql.Date
类型继承自 java.util.Date
,它是一个全局类型(类似于即时类型)。但是,这种继承实际上表示实现继承,而不是类型继承。考虑打破这些旧 JDBC-类 设计的另一个原因。因此,确实有可能使用黑客通过其方法 getTime()
将 java.sql.Date
包装在 java.util.Date
的实例中,最终允许直接转换为即时。但是:这种转换隐含地使用了系统的默认时区。
那么迂腐的如何正确转换呢?让我们再次考虑指向正确方向的 documentation of Java-8:
java.sql.Date sqlDate = ...;
LocalDate calendarDate = sqlDate.toLocalDate();
ZonedDateTime zdt = calendarDate.atStartOfDay(ZoneId.of("Europe/Paris"));
Instant instant = zdt.toInstant();
java.sql.Date
和 java.time
之间的正确映射是 LocalDate
:
LocalDate date = sqlDate.toLocalDate();
如果你真的必须,你可以导出一个Instant
,尽管额外的信息(时间)是任意的。例如:
Instant i = date.atStartOfDay(ZoneOffset.UTC).toInstant();
如果您的日期中没有时间 - 将其转换为毫秒:
Instant.ofEpochMilli(date.getTime())
.atZone(ZoneId.systemDefault())
.toLocalDate();
java.sql.Date(恕我直言)的实现确实不完美。
为了将 java.util.Date 转换为 LocalDate,网络上充满了这样的代码块:
dateToConvert.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate();
- 以上代码非常适合 java.util.Date,因为它实现了 toInstant() 的方式。 (如预期的那样“returnInstant.ofEpochMilli(getTime())”)
- 由于 java.sql.Date 是 java.util.Date 的子类,因此在 Date 对象上运行的代码现在可能知道它在 java.sql.Date 上运行。 (嘿 - 这是面向对象的一个方面,对吧??)。因此,如果它获得 java.util.Date 代码运行良好,如果它获得 java.sql.Date 则失败。
- 代码现在可以显式检查 Date 类型,然后(如果它在 java.sql.Date 上运行)它可以向下转换为 java.sql.Date 并使用 toLocalDate() 方法。不用说,这很丑。
作为开发人员,我希望有一种方法可以正常工作 - toLocalDate(在内部使用弃用的方法)仅适用于 java.sql.Date,因此不能用于 java.util.Date,toInstant 在 [=] 上失败32=].
我将“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.Date.toInstant(),因为你可能会得到 java.sql.Date,这会破坏你的代码。
我真的不明白他们为什么要在JDK.
中故意设置这样的陷阱
java.util.Date
class 有一个名为 toInstant()
的方法,可将 Date
实例转换为 java.time.Instant
.
java.sql.Date
class 扩展了 java.util.Date
class,但是当我尝试在 java.sql.Date
上调用 toInstant()
时,我收到一个 UnsupportedOperationException
.
为什么 toInstant()
是 java.sql.Date
上不受支持的操作?
将 java.sql.Date
转换为 java.time.Instant
的 "correct" 方法是什么?
根据JavaDoc
由于 sql.Date
没有时间成分,因此无法将其转换为 time.Instant
This method always throws an UnsupportedOperationException and should not be used because SQL Date values do not have a time component.
java.sql.Date supports only Date components (date, month, year). It does NOT support time components (hour, minute, second, millisecond). toInstant 需要日期和时间组件,因此 java.sql.Date 实例上的 toInstant 会抛出 UnsupportedOperationException 异常。
toInstant Java doc
This method always throws an UnsupportedOperationException and should not be used because SQL Date values do not have a time component.
java.util.Date 或 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();
将 return 相同的结果,因为 toInstant() 方法在内部调用 Instant.ofEpochMilli(getTime())。
public Instant toInstant() {
return Instant.ofEpochMilli(getTime());
}
到目前为止给出的答案集中在 java.sql.Date
没有时间信息的细节上。这是正确的,但不是此类型不能提供到 Instant
的直接转换的真实或充分理由。不幸的是 documentation of Java-8 确实犯了同样的错误,让用户认为问题只是因为缺少时间信息。
从概念上讲,java.sql.Date
类型表示本地类型。它模拟了一个日历日期,该日期在我们全球的任何地区都可能不同。但是 Instant
在我们的地球上是一样的。 因此用户需要时区或时区偏移量来进行转换。
不幸的是,java.sql.Date
类型继承自 java.util.Date
,它是一个全局类型(类似于即时类型)。但是,这种继承实际上表示实现继承,而不是类型继承。考虑打破这些旧 JDBC-类 设计的另一个原因。因此,确实有可能使用黑客通过其方法 getTime()
将 java.sql.Date
包装在 java.util.Date
的实例中,最终允许直接转换为即时。但是:这种转换隐含地使用了系统的默认时区。
那么迂腐的如何正确转换呢?让我们再次考虑指向正确方向的 documentation of Java-8:
java.sql.Date sqlDate = ...;
LocalDate calendarDate = sqlDate.toLocalDate();
ZonedDateTime zdt = calendarDate.atStartOfDay(ZoneId.of("Europe/Paris"));
Instant instant = zdt.toInstant();
java.sql.Date
和 java.time
之间的正确映射是 LocalDate
:
LocalDate date = sqlDate.toLocalDate();
如果你真的必须,你可以导出一个Instant
,尽管额外的信息(时间)是任意的。例如:
Instant i = date.atStartOfDay(ZoneOffset.UTC).toInstant();
如果您的日期中没有时间 - 将其转换为毫秒:
Instant.ofEpochMilli(date.getTime())
.atZone(ZoneId.systemDefault())
.toLocalDate();
java.sql.Date(恕我直言)的实现确实不完美。
为了将 java.util.Date 转换为 LocalDate,网络上充满了这样的代码块:
dateToConvert.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate();
- 以上代码非常适合 java.util.Date,因为它实现了 toInstant() 的方式。 (如预期的那样“returnInstant.ofEpochMilli(getTime())”)
- 由于 java.sql.Date 是 java.util.Date 的子类,因此在 Date 对象上运行的代码现在可能知道它在 java.sql.Date 上运行。 (嘿 - 这是面向对象的一个方面,对吧??)。因此,如果它获得 java.util.Date 代码运行良好,如果它获得 java.sql.Date 则失败。
- 代码现在可以显式检查 Date 类型,然后(如果它在 java.sql.Date 上运行)它可以向下转换为 java.sql.Date 并使用 toLocalDate() 方法。不用说,这很丑。
作为开发人员,我希望有一种方法可以正常工作 - toLocalDate(在内部使用弃用的方法)仅适用于 java.sql.Date,因此不能用于 java.util.Date,toInstant 在 [=] 上失败32=].
我将“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.Date.toInstant(),因为你可能会得到 java.sql.Date,这会破坏你的代码。
我真的不明白他们为什么要在JDK.
中故意设置这样的陷阱