【问题标题】:Why was getMonth deprecated on java.sql.Date and java.util.Date为什么 getMonth 在 java.sql.Date 和 java.util.Date 上被弃用
【发布时间】:2020-10-29 21:24:24
【问题描述】:

我应该先使用 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)

代码的简单性和可读性明显不同,从函数式编程的角度来看,日期作为日历的副作用并不是非常好。有人可以解释为什么他们认为会发生这种变化吗?

【问题讨论】:

    标签: java scala date deprecated design-decisions


    【解决方案1】:

    在 JDK 1.1 之前,Date 类有两个附加功能。它 允许将日期解释为年、月、日、小时、分钟、 和第二个值。它还允许格式化和解析日期 字符串。不幸的是,这些函数的 API 不适合 走向国际化。从 JDK 1.1 开始,Calendar 类应该是 用于在日期和时间字段与 DateFormat 类之间进行转换 应该用于格式化和解析日期字符串。相应的 Date 中的方法已弃用。

    The JavaDoc 解释。国际化。


    如果有人建议我应该使用java.time中的日期@

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

    【讨论】:

    • 感谢您的解释!我经常对 java.time 进行转换,这会使事情变得更容易,但在某些情况下,拥有额外的对象会对性能产生负面影响(作为参考,Apache Spark 是一个大数据处理工具,因此担心如果必须将对象转换为不同的类型没有必要)。
    【解决方案2】:
        val date: java.sql.Date = ???
        val month = date.toLocalDate().getMonthValue()
    

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

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

    虽然Michael has already answered the questionjava.util.Date 相关,但对于java.sql.Date,我有一些补充。这堂课的情况比迈克尔报告的要糟糕得多。

    在弃用之后,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 个月的第二天,月份打印为 9?发生了两件事:

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

    您不必自己更改时区即可。可能发生的情况包括:

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

    顺便说一句,我在顶部展示的第一个 sn-p 在这些情况下通常无助于防止意外结果。如果在您从 java.sql.Date 转换为 LocalDate 之前出现问题,那么转换也会给您错误的日期。如果可以的话,请转换为LocalDate任何人弄乱 JVM 时区设置并确保安全。

    【讨论】:

      猜你喜欢
      • 2015-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-19
      • 2011-08-29
      • 2016-02-14
      相关资源
      最近更新 更多