val date: java.sql.Date = ???
val month = date.toLocalDate().getMonthValue()
您自己说过,我仍然认为:您应该使用 java.time,现代 Java 日期和时间 API。当您java.sql.Date
从尚未升级到 java.time 的遗留 API 中获得老式 API 时,将其转换为现代 API,LocalDate
并享受使用 java.time 编写的自然代码。
为什么不推荐使用 getMonth() 和其他 getXxx 方法?
虽然迈克尔已经回答了这个问题,java.util.Date
但我有一些要补充的java.sql.Date
。对于这堂课,情况比迈克尔报告的要糟糕得多。
java.util.Date
在弃用之后没有弃用(被认可?)的是 aDate
是一个时间点。java.sql.Date
另一方面,从来都不是一个时间点。说明这一事实的一种方法是它的toInstant
方法——应该将它转换为一个Instant
时间点——无条件地抛出一个UnsupportedOperationException
。Ajava.sql.Date
本来是要与 SQL 数据库及其date
数据类型一起使用的日历日期,在大多数情况下,它也是一个日期,由年、月和月中的某天定义。由于 aDate
不再是年、月和日,他们实际上已经弃用了 ajava.sql.Date
应该是的所有内容。LocalDate
直到使用 JDBC 4.2 我们可以与 SQL 数据库交换对象,他们才给我们一个替代品。
导致弃用的观察结果产生了非常实际的后果。让我们试试这个(在 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?有两件事发生:
- 令人困惑的是,返回的月份数
getMonth()
是从 0 开始的,所以 9 表示 10 月。
- 在 JVM的
Date
默认时区中,它在内部表示为从纪元到一天开始的毫秒数。2020-11-02 00:00:00 在我的原始时区(在此演示中设置为 Pacific/Kiritimati)与萨摩亚的 2020-10-31 23:00:00 是同一时间点。因此我们得到十月。
您不必自己更改时区即可。可能发生的情况包括:
- JVM 的默认时区可以从程序的任何部分以及在同一 JVM 中运行的任何其他程序进行更改。
- 日期可以在一个 JVM 中运行的程序中序列化,并在具有不同时区设置的不同 JVM 中反序列化。
顺便说一句,我在顶部展示的第一个片段通常无助于在这些情况下出现意外结果。如果在您从 转换为 之前事情偏离了轨道,那么java.sql.Date
转换LocalDate
也会给您错误的日期。如果可以,请在任何人弄乱 JVM 时区设置LocalDate
之前转换为安全起见。