首页 > 解决方案 > 使用正确的 DST 将 UTC java.sql.Time 转换为 java.time.localtime

问题描述

我在将从数据库中获取的 java.sql.Time (UTC) 转换为 java.time.LocalTime (GMT+1 DST) 时遇到问题。它总是缺少 DST 时间。因此,就像 03:00 的时间仅转换为 04:00 而不是 05:00 的 LocalTime。

//Saved UTC time in DB: 03:00
LocalTime.ofInstant(Instant.ofEpochMilli(sqlTime.getTime()), ZoneId.of("Europe/Berlin"));
=> 04:00 //expected 05:00

我想问题是 java.sql.Time 以默认日期 1970-01-01 保存时间,而 1970 年德国没有 DST。当然,时间应该显示在今天,而不是 1970 年。

那么我怎样才能得到这个例子的正确时间呢?

标签: javatimelocaltime

解决方案


假设您至少使用 JDBC 4.2,您应该能够LocalTime从结果集中检索 a:

    LocalTime timeInUtc = yourResultSet.getObject(yourTimeColumn, LocalTime.class);

那么就没有必要为过时且设计不佳的java.sql.Time课程而烦恼。当然,你得到的时间仍然是 UTC。以下是转换方法:

    LocalTime timeInUtc = LocalTime.of(3, 0);

    ZoneId zone = ZoneId.of("Europe/Berlin");
    LocalTime timeInGermany = OffsetDateTime.now(ZoneOffset.UTC)
            .with(timeInUtc)
            .atZoneSameInstant(zone)
            .toLocalTime();

    System.out.println("Zeit heute in Deutschland: " + timeInGermany);

当我今天运行代码时,我得到了您期望的输出:

德国时间:05:00

编辑:如果您无法避免获得 a java.sql.Time,请将其转换为LocalTimefirst 。假设Time是 UTC 并且我们不想依赖脆弱的 JVM 时区设置进行转换,那么我们需要该getTime方法是正确的:

    Time sqlTimeInUtc = // Get from database
    LocalTime timeInUtc 
            = LocalTime.MIDNIGHT.plus(sqlTimeInUtc.getTime(), ChronoUnit.MILLIS);

如果您可以依赖 JVM 时区设置也为 UTC,则以下内容会更好:

    LocalTime timeInUtc = sqlTimeInUtc.toLocalTime();

在这两种情况下,其余的都如上。

在所有情况下,当您说“应该显示今天的时间”时,您是否想要“今天在 UTC”或“今天在欧洲/柏林时区”这个问题都有一些极端情况。如果时间在凌晨 2 点到 3 点之间,并且今天是 3 月的最后一个星期日,那么还有一个极端情况,此时时钟从 2 点调快到 3 点,以启动德国的夏令时 (DST)。请仔细考虑这些极端案例并决定您想要什么。

顺便说一句,您的诊断是完全正确的:Time.getTime返回 1970 年 1 月 1 日的时间,因此当您将其输入到中时Instant,您正在转换该日期的时间,即没有夏令时。


推荐阅读