Convert UTC java.sql.Time to java.time.localtime with correct DST

那年仲夏 提交于 2021-02-10 06:14:39

问题


I have a problem to convert a java.sql.Time (UTC) which is fetched from a database to a java.time.LocalTime (GMT+1 DST). It is always missing the DST hour. So like a Time of 03:00 is only converted to a LocalTime of 04:00 instead of 05:00.

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

I guess the problem is that java.sql.Time saves the time with a default date of 1970-01-01 and in 1970 there was no DST in Germany. But of course the time should be shown for today and not for 1970.

So how can I get the correct time for this example?


回答1:


Assuming that you are using at least JDBC 4.2, you should be able to retrieve a LocalTime from your result set:

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

Then there’s no need bother with the outdated and poorly designed java.sql.Time class. The time you get will still be in UTC, of course. Here’s how to convert:

    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);

When I ran the code today I got the output you expected:

Zeit heute in Deutschland: 05:00

Edit: If there’s no way you can avoid getting a java.sql.Time, convert it to LocalTime first. Assuming that the Time is in UTC and we don’t want to rely on a fragile JVM time zone setting for conversion, you are correct that we need the getTime method:

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

If you could rely on the JVM time zone setting also being UTC, the following would be nicer:

    LocalTime timeInUtc = sqlTimeInUtc.toLocalTime();

In both cases the rest is as above.

In all cases there are some corner cases around the question whether you want “today in UTC” or “today in Europe/Berlin time zone” when you say “the time should be shown for today”. There’s also a corner case if the time is between 2 and 3 AM and today is the last Sunday in March, where the clocks are turned forward from 2 to 3 to initiate summer time (DST) in Germany. Please think these corner cases through and decide what you want.

By the way your diagnosis is completely correct: Time.getTime returns the time of day on Jan 1, 1970, so when you feed this into an Instant, you are converting the time of day on this date, that is, without summer time.




回答2:


As far as I understand it your question is: Given a time in UTC convert it to local time according to the current time offset. This time offset is different depending of whether DST is in effect or not.

A possible approach is to determine the current offset using TimeZone:

    TimeZone tz = TimeZone.getTimeZone("Europe/Berlin");
    int timeZoneOffsetMillis = tz.getOffset(new Date().getTime());

Now timeZoneOffsetMillis contains the number of milliseconds you have to add to your UTC time to get local time.

You can get a LocalTime like this:

    LocalTime localTime = LocalTime.ofNanoOfDay((sqlTime.getTime() + timeZoneOffsetMillis) * 1000000L);

If your time is only accurate to seconds instead of nanoseconds anyway you might want to use LocalTime.ofSecondOfDay.



来源:https://stackoverflow.com/questions/52966281/convert-utc-java-sql-time-to-java-time-localtime-with-correct-dst

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!