LocaleDateTime atZone 格式忽略不同的时区

问题描述

我的代码似乎有问题。我希望输出中的时间不同 - 一个从 UTC 转换为德国时间,另一个转换为巴西东部时间,但我总是得到相同的 UTC 时间输出

我的代码

        LocalDateTime localDateTime = resource.getDateOfManufacture();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy_HH-mm-ss",Locale.getDefault());      
        ZoneId zoneDE = ZoneId.of("Europe/Berlin");
        ZoneId zoneBR = ZoneId.of("Brazil/East");
        
        System.out.println("TIME --------------------------------------------------------------------");
        
        System.out.println(localDateTime);
        
        System.out.println(localDateTime.atZone(zoneDE));
        System.out.println(localDateTime.atZone(zoneBR));

        System.out.println(localDateTime.atZone(zoneDE).format(dateTimeFormatter));
        System.out.println(localDateTime.atZone(zoneBR).format(dateTimeFormatter));

我的实际输出

13:06:43,890 INFO  [stdout] (EJB default - 2) TIME --------------------------------------------------------------------
13:06:43,904 INFO  [stdout] (EJB default - 2) 2016-05-31T22:00
13:06:43,907 INFO  [stdout] (EJB default - 2) 2016-05-31T22:00+02:00[Europe/Berlin]
13:06:43,908 INFO  [stdout] (EJB default - 2) 2016-05-31T22:00-03:00[Brazil/East]
13:06:43,913 INFO  [stdout] (EJB default - 2) 31-05-2016_22-00-00
13:06:43,917 INFO  [stdout] (EJB default - 2) 31-05-2016_22-00-00

我的期望(关于最后两行):

13:06:43,913 INFO  [stdout] (EJB default - 2) 01-06-2016_00-00-00
13:06:43,917 INFO  [stdout] (EJB default - 2) 31-05-2016_19-00-00

解决方法

您的代码只是向本地日期时间添加一个区域,没有区域。前 2 行准确显示了这些结果。您的日期时间格式化程序也不会做任何特别的事情,它们只是格式化所有内容但忽略区域。

您可能存在的误解是您可能认为本地日期时间代表 UTC 中的日期时间。 他们没有。它们只是年、月、日、时、分、秒和毫微的组合。

如果 localDateTime 在 UTC 中,您期望的输出表明您想要获得另一个时区中的相应日期时间。您本质上是在问,鉴于我将在 UTC 的这个日期举办一个派对,我需要制作哪些字符串,以便我可以告诉我在柏林和巴西的朋友来参加派对?

执行此操作的一种方法是在区域 ZonedDateTime 处获取 UTC,然后设置日期时间格式化程序的区域:

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy_HH-mm-ss",Locale.getDefault()); 
ZoneId zoneDE = ZoneId.of("Europe/Berlin");
ZoneId zoneBR = ZoneId.of("Brazil/East");
DateTimeFormatter formatterDE = dateTimeFormatter.withZone(zoneDE);
DateTimeFormatter formatterBR = dateTimeFormatter.withZone(zoneBR);

System.out.println(localDateTime.atZone(ZoneOffset.UTC).format(formatterDE));
System.out.println(localDateTime.atZone(ZoneOffset.UTC).format(formatterBR));
,

ZonedDateTime#withZoneSameInstant

使用它来获取具有不同时区的日期时间的副本,保留瞬间。您需要在 LocalDateTime 处将 ZonedDateTime 转换为 UTC,然后应用 .withZoneSameInstant(zoneId),如下所示:

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy_HH-mm-ss",Locale.ENGLISH);
        ZoneId zoneDE = ZoneId.of("Europe/Berlin");
        ZoneId zoneBR = ZoneId.of("Brazil/East");
        LocalDateTime ldt = LocalDateTime.parse("2016-05-31T22:00");
        System.out.println(ldt);

        // Date-time in Europe/Berlin
        ZonedDateTime zdtDE = ldt.atZone(ZoneOffset.UTC).withZoneSameInstant(zoneDE);
        System.out.println(zdtDE.format(dateTimeFormatter));

        // Date-time in Brazil/East
        ZonedDateTime zdtBR = ldt.atZone(ZoneOffset.UTC).withZoneSameInstant(zoneBR);
        System.out.println(zdtBR.format(dateTimeFormatter));
    }
}

输出:

2016-05-31T22:00
01-06-2016_00-00-00
31-05-2016_19-00-00