如何将java.sql.timestamp转换为LocalDate (java8) java.time?

188
在Java 8中,我该如何将一个java.sql.Timestamp转换为java.time.LocalDate?

1
我在这里遇到了一个类似的问题:https://dev59.com/SmEh5IYBdhLWcg3wHARD#23197731。简短的回答是,不完全相同。但这并不一定是坏事。 - jacobhyphenated
3个回答

291

您可以执行以下操作:

timeStamp.toLocalDateTime().toLocalDate();
请注意,timestamp.toLocalDateTime()将使用Clock.systemDefaultZone()时区进行转换。这可能是您想要的,也可能不是。

1
它已经被添加到Java 8中。 - assylias
72
请注意,timestamp.toLocalDateTime() 方法将使用系统默认时区进行转换。这可能是您想要的,也可能不是。 - jacobhyphenated
1
@jacobhyphenated 请使用明确的时区发布答案。谢谢! - user482745
1
@jacobhyphenated的评论在这里非常重要,因此它得到了很多赞。请查看我的答案以获取详细信息https://dev59.com/cWAg5IYBdhLWcg3wu87o#57101544 - Ruslan
@jacobhyphenated,“LocalDateTime”始终使用系统默认时区。这就是其名称中“Local”所表示的意思。 - M. Prokhorov
显示剩余2条评论

55

接受的答案并不理想,因此我决定补充我的意见。

timeStamp.toLocalDateTime().toLocalDate();

一般情况下,这是一个不好的解决方案,我甚至不确定为什么他们要将这个方法添加到JDK中,因为它会使用系统时区进行隐式转换,使事情变得非常混乱。通常,当仅使用java8日期类时,程序员被迫指定时区,这是一件好事。

好的解决方案是

timestamp.toInstant().atZone(zoneId).toLocalDate()

其中zoneId是你想要使用的时区,通常为ZoneId.systemDefault()(如果你想使用系统时区)或一些硬编码的时区,比如ZoneOffset.UTC

一般的做法应该是:

  1. 使用与之直接相关的类来自由地使用新的Java 8日期类,例如在我们的例子中,java.time.Instant与java.sql.Timestamp直接相关,即它们之间不需要进行时区转换。
  2. 使用这个Java 8类中设计良好的方法来实现正确的事情。在我们的例子中,atZone(zoneId)明确表示我们正在进行转换并使用特定的时区。

2
我不同意。时间戳(以及日期)没有任何区域信息。LocalDate也没有任何区域信息,因此两者是等效的。它们之间的转换可以独立于任何特定区域进行。在转换为LocalDate之前转换为ZonedDateTime会添加时区,然后再次删除 - 这种方式更容易出现难以发现的错误。 - AutomatedMike
8
@AutomatedMike 时间戳(以及日期)代表UTC中的一个时间点。LocalDate并不代表一个时间点,而是墙上时钟上显示的时间。请阅读它们的javadoc。“它们之间的转换可以独立于任何特定区域进行”-这是不正确的,对于我的莫斯科时区,新的Timestamp(0L).toLocalDateTime()返回“1970-01-01T03:00”。你的时区可能会有不同的结果。 - Ruslan
1
即使您通过执行toLocalDate()来剥离时间,也很容易证明如果Timestamp在午夜左右有一个时间,那么日期可能是错误的,例如对于我的莫斯科时区,new Timestamp(1000 * 60 * 60 * 23).toLocalDateTime().toLocalDate()返回"1970-01-02",而在UTC中则为"1970-01-01"。 - Ruslan
1
@AutomatedMike "添加时区,然后再移除" - 关键不在于添加和移除时区,而是通过使用显式时区在不同概念之间进行转换。这与我之前两条评论的示例形成对比,其中时区被隐式应用。 - Ruslan
1
当您从数据库获取一个没有时区的时间戳(TIMESTAMP (WITHOUT TIME ZONE))时,它实际上是一个LocalDateTime。然后,如果您将其映射到java.sql.Timestamp,则JDBC驱动程序会使用系统默认时区将本地日期/时间数据转换为毫秒数。.toLocalDateTime()再次使用默认时区将毫秒数转换为LocalDateTime。这对我来说似乎相对安全。 - Yay295
显示剩余2条评论

8

我会稍微扩展@assylias的回答,考虑到时区的因素。有至少两种方法可以获取特定时区的LocalDateTime。

您可以为整个应用程序设置默认时区。它应该在任何时间戳 -> java.time转换之前调用:

public static void main(String... args) {
    TimeZone utcTimeZone = TimeZone.getTimeZone("UTC");
    TimeZone.setDefault(utcTimeZone);
    ...
    timestamp.toLocalDateTime().toLocalDate();
}

或者您可以使用 toInstant.atZone 链:

timestamp.toInstant()
        .atZone(ZoneId.of("UTC"))
        .toLocalDate();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接