将日期从 GMT 时区转换为本地时区——使用 ISO_OFFSET_DATE_TIME

Posted

技术标签:

【中文标题】将日期从 GMT 时区转换为本地时区——使用 ISO_OFFSET_DATE_TIME【英文标题】:Convert date from GMT timezone to local time zone -- using ISO_OFFSET_DATE_TIME 【发布时间】:2019-03-20 08:53:15 【问题描述】:

我有一个日期,假定为 GMT,我想使用 ISO_OFFSET_DATE_TIME 格式将其转换为本地时区。

基本上,我想从:

2018-03-13 03:00:00.0

到:

2018-03-13T00:00:00-09:00

这显然会改变,具体取决于您当地的时区。

关于如何做到这一点的任何想法?

【问题讨论】:

【参考方案1】:

您可以为此利用ZonedDateTime。您只需将日期读取为 UTC 并根据需要进行转换。你可能会得到这样的东西:

String readPattern = "yyyy-MM-dd HH:mm:ss.S";
DateTimeFormatter readDateTimeFormatter = DateTimeFormatter.ofPattern(readPattern).withZone(ZoneOffset.UTC);
LocalDateTime utcLocalDateTime = LocalDateTime.parse("2018-03-13 03:00:00.0", readDateTimeFormatter);
ZonedDateTime localZonedDateTime = utcLocalDateTime.atOffset(ZoneOffset.UTC).atZoneSameInstant(ZoneId.systemDefault());
String writePattern = "yyyy-MM-dd HH:mm:ssXXX";
DateTimeFormatter writeDateTimeFormatter = DateTimeFormatter.ofPattern(writePattern);
System.out.println(writeDateTimeFormatter.format(localZonedDateTime));

有关详细信息,请参阅:

https://docs.oracle.com/javase/8/docs/api/java/time/ZonedDateTime.html https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html

【讨论】:

这个答案还不错,但有一些问题。它可以使用更多的讨论/解释。而且,我建议将其分为两个阶段,解析输入,然后应用 ZoneOffset 由于您解析为LocalDateTime(无区域或偏移),因此无需在您的DateTimeFormatter 上调用withZone。没有为这个例子增加价值。 ZonedDateTime 在这里不合适。当仅使用与 UTC 的偏移量而不是时区时,请使用 OffsetDateTime 类,顾名思义。 你的最后两行令人困惑和纠结。那时您应该使用时区,而不是偏移量。致电ZoneId.systemDefault。您的所有代码都可以替换为一行:LocalDateTime.parse( "2018-01-23 01:23:45".replace( " " , "T" ) ).atOffset( ZoneOffset.UTC ).atZoneSameInstant( ZoneId.systemDefault() ) 感谢您的回答。您的基本想法是正确的,@BasilBourque 已经提供了一些很好的改进建议。请允许我补充一点,SSS 要求第二个小数点后三位,而问题中的示例字符串只有一位。所以只使用一个S【参考方案2】:

将日期时间字符串解析为LocalDateTime:

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("u-M-d H:m:s.S", Locale.ENGLISH);
LocalDateTime ldt = LocalDateTime.parse("2018-03-13 03:00:00.0", dtf);

将此与 UTC 偏移量结合起来创建一个OffsetDateTime

OffsetDateTime odtUtc = ldt.atOffset(ZoneOffset.UTC);

创建它的副本,将偏移量设置为 -09:00,同时保持瞬间不变:

OffsetDateTime odtUtcMinus9 = odtUtc.withOffsetSameInstant(ZoneOffset.of("+09:00"));

演示:

import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main 
    public static void main(String[] args) 
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("u-M-d H:m:s.S", Locale.ENGLISH);
        LocalDateTime ldt = LocalDateTime.parse("2018-03-13 03:00:00.0", dtf);
        System.out.println(ldt); // 2018-03-13T03:00

        OffsetDateTime odtUtc = ldt.atOffset(ZoneOffset.UTC);
        System.out.println(odtUtc); // 2018-03-13T03:00Z

        OffsetDateTime odtUtcMinus9 = odtUtc.withOffsetSameInstant(ZoneOffset.of("+09:00"));
        System.out.println(odtUtcMinus9); // 2018-03-13T12:00+09:00
    

请注意,时区偏移是固定的,即它独立于DST。如果您正在寻找根据 DST 自动调整时区偏移量,请使用 ZonedDateTime。这些方法与我们在上一个演示中使用的方法非常相似。

演示:

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

public class Main 
    public static void main(String[] args) 
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("u-M-d H:m:s.S", Locale.ENGLISH);
        LocalDateTime ldt = LocalDateTime.parse("2018-03-13 03:00:00.0", dtf);
        System.out.println(ldt); // 2018-03-13T03:00

        ZonedDateTime zdtUtc = ldt.atZone(ZoneId.of("Etc/UTC"));
        System.out.println(zdtUtc); // 2018-03-13T03:00Z[Etc/UTC]

        ZonedDateTime zdtAmericaAdak = zdtUtc.withZoneSameInstant(ZoneId.of("America/Adak"));
        System.out.println(zdtAmericaAdak); // 2018-03-12T18:00-09:00[America/Adak]

        // A custom format
        DateTimeFormatter dtfOutput = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSXXX", Locale.ENGLISH);
        String formatted = dtfOutput.format(zdtAmericaAdak);
        System.out.println(formatted); // 2018-03-12 18:00:00.000-09:00
    
   

Trail: Date Time了解更多关于java.timemodern date-time API*的信息。


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 和 7 . 如果您正在为一个 android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaring 和 How to use ThreeTenABP in Android Project。

【讨论】:

以上是关于将日期从 GMT 时区转换为本地时区——使用 ISO_OFFSET_DATE_TIME的主要内容,如果未能解决你的问题,请参考以下文章

将 GMT 日期时间转换为本地时区日期时间

使用时区偏移量而不是时区标识符将 GMT 时间转换为本地时间

将本地时间转换为用户首选时区,将用户首选时区转换为 GMT

如何使用 MQ 的 esql 将日期的特定时区转换为 GMT 时区?

使用 joda time 将一个时区转换为另一个时区

如何使用 Java 处理日历时区?