Java.util.Calendar未正确更新时区

1cosmwyk  于 2022-10-01  发布在  Java
关注(0)|答案(1)|浏览(134)

此方法的目标是获取UTC日期,将其转换为指定的时区并返回DateTimeValue对象。然而,我们最近在某些时区使用此方法时发现了一个错误。

private static DateTimeValue toDateTimeValue(Date endDate, TimeZone timeZone) {     
    Calendar cal = Calendar.getInstance();
    cal.setTime(endDate);
    cal.setTimeZone(timeZone);
    cal.set(Calendar.HOUR_OF_DAY, 23); // move to the end of the day
    cal.set(Calendar.MINUTE, 59);
    cal.set(Calendar.SECOND, 59);
    int year = cal.get(Calendar.YEAR);
    int month = cal.get(Calendar.MONTH) + 1;
    int day = cal.get(Calendar.DAY_OF_MONTH);  //ends up being 3 but should be 4
    int hour = cal.get(Calendar.HOUR_OF_DAY);
    int minute = cal.get(Calendar.MINUTE);
    int second = cal.get(Calendar.SECOND);

    return new DateTimeValueImpl(year, month, day, hour, minute, second);
}

说明错误的主要案例:

  • 结束日期值:星期一OCT 03 21:00:00 UTC 2022
  • 时区值:欧洲/赫尔辛基+3

在上面的方法中,日期值最终是第3天,但它应该是第4天,因为UTC中的03月21:00:00实际上是赫尔辛基时区的10月4日

我用这个代码代替那个方法做了一些进一步的测试。

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
    String utcDate = sdf.format(endDate); 
    System.out.println(utcDate);   //2022-10-03 09:00:00

    sdf.setTimeZone(timeZone);
    String timeZoneDate = sdf.format(endDate);
    System.out.println(timeZoneDate);   //2022-10-04 12:00:00

这显示了正确/预期的结果,但这是一个字符串,我需要将其作为DateTimeValue

为什么当我们将时区设置为赫尔辛基时,java.util.calar不更新日期(日期)?

y1aodyip

y1aodyip1#

The java.util date-time API is outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.

The following demo shows how easily and cleanly you could do/test it by using the modern date-time API.

Demo:

public class Main {
    public static void main(String[] args) {
        ZonedDateTime endDate = ZonedDateTime.of(LocalDate.of(2022, 10, 3), LocalTime.of(21, 0), ZoneOffset.UTC);
        ZonedDateTime zdtDesired = endDate.withZoneSameInstant(ZoneId.of("Europe/Helsinki"));
        System.out.println(zdtDesired);
        System.out.println(zdtDesired.getDayOfMonth());
    }
}

Output:

2022-10-04T00:00+03:00[Europe/Helsinki]
4

How to convert java.util.Date into ZonedDateTime?

You can convert java.util.Date into Instant which can be converted into ZonedDateTime. It means you do not even need to use ZonedDateTime#withZoneSameInstant as shown in the above demo.

public class Main {
    public static void main(String[] args) {
        // In your case, it will be endDate.toInstant()
        Instant instant = new Date().toInstant();
        ZonedDateTime zdtDesired = instant.atZone(ZoneId.of("Europe/Helsinki"));
        System.out.println(zdtDesired);
    }
}

Output:

2022-09-30T21:57:50.487+03:00[Europe/Helsinki]

Learn more about the the modern date-time API from**Trail: Date Time**.

相关问题