为什么 getMonth 在 java.sql.Date 和 java.util.Date 上被弃用

Why was getMonth deprecated on java.sql.Date and java.util.Date

我应该以我使用 Apache Spark 作为开头,它使用 java.sql.Date,以防有人建议我应该使用 java.time 中的日期。下面的例子是在 Scala 中。

我使用(已弃用)获取日期月份的 API 如下:

val date: java.sql.Date = ???
val month = date.getMonth()

但是,如果我看一下它的显示方式,我应该根据弃用来执行此操作,上面的代码将重写如下:

val date: java.sql.Date = ???
val cal = Calendar.getInstance()
cal.setTime(date)
cal.get(Calendar.MONTH)

代码的简单性和可读性明显不同,从函数式编程的角度来看,日期作为日历的副作用并不是很好。有人可以解释为什么他们认为进行了此更改吗?

Prior to JDK 1.1, the class Date had two additional functions. It allowed the interpretation of dates as year, month, day, hour, minute, and second values. It also allowed the formatting and parsing of date strings. Unfortunately, the API for these functions was not amenable to internationalization. As of JDK 1.1, the Calendar class should be used to convert between dates and time fields and the DateFormat class should be used to format and parse date strings. The corresponding methods in Date are deprecated.

The JavaDoc 说明。国际化。


"万一有人建议我应该使用 java.time"

中的日期

没有什么可以阻止您尽快转换为 java.time 类,执行您需要的任何 calculations/modifications,如果您需要重新插入,则转换回来再次 java.sql.Date

    val date: java.sql.Date = ???
    val month = date.toLocalDate().getMonthValue()

你自己说的,我仍然认为:你应该使用 java.time,现代 Java 日期和时间 API。当您从尚未升级到 java.time 的遗留 API 获得老式 java.sql.Date 时,将其转换为现代 LocalDate 并享受使用 [=72 编写自然代码的乐趣=].

为什么不推荐使用 getMonth() 和其他 getXxx 方法?

虽然 关于 java.util.Date,但在谈到 java.sql.Date 时我有一些要补充的。对于这个class,情况比迈克尔报告的要糟糕得多。

java.util.Date 在弃用之后还没有弃用(赞成?)的是 Date 是一个时间点。另一方面,java.sql.Date 从来就不是一个时间点。说明这一事实的一种方法是它的 toInstant 方法——应该将它转换为一个 Instant,一个时间点——无条件地抛出一个 UnsupportedOperationExceptionjava.sql.Date 是一个日历日期,用于 SQL 数据库及其 date 数据类型,在大多数情况下,它也是一个日期,由年月日定义月。由于 Date 不再是年月日,他们实际上已经弃用了 java.sql.Date 应该是 的所有内容。在 JDBC 4.2 我们可以用 SQL 数据库交换 LocalDate 对象之前,他们没有给我们替换。

导致弃用的观察结果产生了非常实际的后果。让我们试试这个(在 Java 因为这是我可以写的):

void foo(java.sql.Date sqlDate) {
    System.out.println(sqlDate);
    TimeZone.setDefault(TimeZone.getTimeZone(ZoneId.of("Pacific/Samoa")));
    System.out.println(sqlDate.getMonth());
}

在一次调用中打印的方法:

2020-11-02
9

所以我们有第 11 个月的第 2 天,月份打印为 9?有两件事正在发生:

  1. 令人困惑的月份数字 getMonth() returns 是从 0 开始的,所以 9 表示十月。
  2. Date 在内部表示为从纪元到 JVM 默认时区一天开始的毫秒数。我原来时区的 2020-11-02 00:00:00(此演示设置为 Pacific/Kiritimati)与萨摩亚的 2020-10-31 23:00:00 是同一时间点。因此我们得到了十月。

您不必为此自行更改时区。可能发生的情况包括:

  • JVM 的默认时区可以从程序的任何部分和同一 JVM 中的任何其他程序 运行 更改。
  • 日期可以在一个 JVM 中的程序 运行 中序列化,并在具有不同时区设置的不同 JVM 中反序列化。

顺便说一句,在这些情况下,我在顶部展示的第一个片段通常无助于防止意外结果。如果在从 java.sql.Date 转换为 LocalDate 之前事情偏离轨道,转换也会给您错误的日期。如果可以的话,转换为 LocalDate 之前 任何人都会弄乱 JVM 时区设置并确保安全。