我将将从数据库中获取的java.sql.Time(UTC)转换为java.time.LocalTime(GMT + 1 DST)时遇到问题。它总是缺少夏令时。因此,将03:00的时间仅转换为04:00的LocalTime而不是05:00。
//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年的时间。
那么我如何获得本示例的正确时间?
答案 0 :(得分:3)
假设您至少使用JDBC 4.2,则应该能够从结果集中检索LocalTime
:
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);
今天运行代码时,我得到了您期望的输出:
德国的Zeit heute:05:00
编辑:如果无法避免,请先获取java.sql.Time
,然后将其转换为LocalTime
。假设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点之间,而今天是三月的最后一个星期日,则还有一个极端的情况,在那儿,时钟从2点变为3点,以启动德国的夏令时(DST)。请仔细考虑这些极端情况,然后决定您想要什么。
通过这种方式,您的诊断是完全正确的:Time.getTime
返回一天中的时间,即1970年1月1日,因此,当您将其输入Instant
时,您将在此日期中转换时间日期,即没有夏季时间。
答案 1 :(得分:1)
据我了解,您的问题是:给定UTC时间,请根据当前时间偏移将其转换为本地时间。此时间偏移取决于DST是否有效。
一种可能的方法是使用TimeZone
确定当前偏移量:
TimeZone tz = TimeZone.getTimeZone("Europe/Berlin");
int timeZoneOffsetMillis = tz.getOffset(new Date().getTime());
现在timeZoneOffsetMillis
包含您必须添加到UTC时间以获取本地时间的毫秒数。
您可以这样获得LocalTime
:
LocalTime localTime = LocalTime.ofNanoOfDay((sqlTime.getTime() + timeZoneOffsetMillis) * 1000000L);
如果您的时间仅精确到秒而不是十亿分之一秒,则可能要使用LocalTime.ofSecondOfDay
。