【问题标题】:transform java.sql.Date to LocalDateTime将 java.sql.Date 转换为 LocalDateTime
【发布时间】:2021-10-20 15:09:06
【问题描述】:

我有一个java.sql.Date 对象,想将其转换为java.time.LocalDateTime 对象。

为了比较,我可以使用 java.util.Date 进行类似的转换:

java.util.Date utilDate = new java.util.Date(sqlDate.getTime());
System.out.println("date with time: " + utilDate);

This answer 对我不起作用,因为我的java.sql.Date 没有 getTimestamp 方法。

作为参考,this question 解决了相反的转换。

【问题讨论】:

  • 你不能。根据定义,您只有一个日期,没有时间部分。您可以调用toLocalDate(),然后调用LocalDate 的atTime 方法来获取LocalDateTime,但您必须自己决定要应用到日期的时间。
  • U 可以转换成 java.sql.Timestamp(long/Instant time) 然后 localDateTime
  • 编译器允许你这样做并不意味着它是安全或可靠的。让 java.sql.Date 和 java.sql.Time 扩展 java.util.Date 的决定是 Java SE 中一个不幸的设计错误。尽管它们继承了 getTime 方法,但该方法在子类中不可靠,不应调用。事实上,java.sql.Date 根本不应该使用;上级替换是resultSet.getObject(1, LocalDate.class)
  • 那是因为 SQL DATE 没有时间,只有日期。
  • @JWoodchuck java.sql.Date 扩展 java.util.Date 试图假装是没有时间和区域/偏移量的日期是徒劳的。然而它确实有一个时间和一个区域/偏移量。这是一个很好的例子,说明如何 来设计你的类。这些遗留的日期时间类是由不了解如何处理日期时间的人设计的。我敦促您尽快忘记这些遗留类。专注于仅使用 java.time 类。 JSR 310 被一致采用是有充分理由的。

标签: java date


【解决方案1】:

您正在使用糟糕的日期时间类,这些类在几年前被 JSR 310 中定义的现代 java.time 类所取代。

  • 不要使用java.sql.Date
  • 不要使用java.util.Date
  • 不要使用java.sql.Timestamp
  • 不要使用java.util.Calendar

仅使用 java.time 类。

要与数据库交换日期时间值,请使用 JDBC 4.2 或更高版本。

java.sql.Date 类假装代表一个仅限日期的值。

如果您收到java.sql.Date 对象,立即将其转换java.time.LocalDate。使用添加到旧类的新方法toLocalDate

LocalDate localDate  = myJavaSqlDate.toLocalDate() ;

您要求java.time.LocalDateTime 对象。您有必要的日期部分。现在您需要分配时间部分。

LocalTime localTime = LocalTime.of( 15 , 30 );

合并。

LocalDateTime localDateTime = LocalDateTime.of( localDate, localTime ) ;

LocalDateTime 本质上是模棱两可的。日本下午 3:30 ? ?? 与摩洛哥下午 3:30 ? ?? 不同。

要确定时间轴上的特定时刻,请将您的LocalDateTime 放在时区的上下文中。你会得到一个ZonedDateTimeObject

ZoneId zoneId = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zonedDateTime = localDateTime.atZone( zoneId ) ;

要以 UTC 格式查看那个时刻,与 UTC 的偏移量为零时分秒,请提取 Instant

Instant instant = zonedDateTime.toInstant() ;

【讨论】:

    【解决方案2】:

    按要求回答您的问题

    Basil Bourque 的巧妙回答提供了大量有用的信息。尤其是建议完全避免使用 java.sql.Date 类,这样您就不需要转换了。

    对于这个答案,我假设您从旧版 API 获得 java.sql.Date,而您现在无法升级到 java.time。所以你确实需要一些转换,并且你有理由要求LocalDateTime 代表 JVM 的默认时区中的时间(一种脆弱的做法)。还有一个问题需要考虑:您只想要Date 的日期部分,还是它的时间点?询问是因为 java.sql.Date 用于表示没有时间的日期,但 API 不强制执行此操作,java.sql.Date 以毫秒精度保存时间点。我希望我们已经告诉过你,如果可以的话,最好避免这是一个令人困惑的课程。

    开始一天:

        java.sql.Date oldfashionedSqlDate
                = java.sql.Date.valueOf(LocalDate.of(2021, Month.OCTOBER, 26));
        System.out.println("java.sql.Date: " + oldfashionedSqlDate);
        LocalDateTime dateTime = oldfashionedSqlDate.toLocalDate().atStartOfDay();
        System.out.println("LocalDateTime: " + dateTime);
    

    输出(假设JVM的默认时区在此期间没有改变):

    java.sql.Date: 2021-10-26
    LocalDateTime: 2021-10-26T00:00
    

    获取时间点:获取 Date 对象中的完整精度:

        java.sql.Date oldfashionedSqlDate = new java.sql.Date(1_666_000_000_000L);
        System.out.println("java.sql.Date: " + oldfashionedSqlDate);
        long epochMilli = oldfashionedSqlDate.getTime();
        LocalDateTime dateTime = Instant.ofEpochMilli(epochMilli)
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
        System.out.println("LocalDateTime: " + dateTime);
    

    在我的时区输出:

    java.sql.Date: 2022-10-17
    LocalDateTime: 2022-10-17T03:46:40
    

    由于转换取决于时区,因此在大多数情况下,其他时区的输出会有所不同。

    【讨论】:

    • 这很有帮助。非常感谢您提供更多信息!
    猜你喜欢
    • 2011-08-29
    • 2017-07-13
    • 2013-01-27
    • 2016-02-14
    • 1970-01-01
    • 1970-01-01
    • 2021-11-26
    • 2016-04-10
    • 1970-01-01
    相关资源
    最近更新 更多