时区 CEST 到 GMT

Posted

技术标签:

【中文标题】时区 CEST 到 GMT【英文标题】:Timezone CEST to GMT 【发布时间】:2018-12-25 00:16:21 【问题描述】:

我必须以这种格式输入日期时间:

"2018-07-17T12:16:50.52Z"

因此我正在使用:

private static final SimpleDateFormat LIVETRACK_DATE_TIME_FORMATTER =
  new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");

DATE_TIME_FORMATTER.parse(timeFrameFrom);

但是当我运行测试用例时出现以下错误:

Tue Jul 17 1[2:20:50 CES]T 2018> but was:<Tue Jul 17 1[0:20:50 GM]T 2018>

这是否意味着我应该将日期转换为 GMT 格式? 如何转换?

【问题讨论】:

我建议你避免使用SimpleDateFormat 类。它不仅过时了,而且出了名的麻烦。今天我们在java.time, the modern Java date and time API 中做得更好。也不要将Z 硬编码为格式模式字符串中的文字。这是一个 UTC 偏移量,需要这样解析,否则会得到不正确的结果。 您的代码不会生成单元测试报告为观察结果的Tue Jul 17 10:20:50 GMT 2018 Uhr,至少不会产生“Uhr”。请问create a Minimal, Complete, and Verifiable example可以吗?然后我们可以更好地帮助您。 你的例子中的方括号是什么?错字? @BasilBourque 在比较预期字符串和实际字符串时,JUnit(可能还有其他测试框架?)在不同的部分周围插入方括号。所以显然测试比较了字符串,但DATE_TIME_FORMATTER.parse 没有产生字符串,所以我们还没有被告知。 【参考方案1】:
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
            "EEE MMM dd HH:mm:ss zzz yyyy 'Uhr'", Locale.ROOT);

    String input = "2018-07-17T12:16:50.52Z";
    ZonedDateTime dateTime = Instant.parse(input)
            .atZone(ZoneId.of("Europe/Berlin"));
    String output = dateTime.format(formatter);
    System.out.println(output);

输出:

2018 年 7 月 17 日星期二 14:16:50 CEST Uhr

您的测试用例期望得到错误的结果。输入字符串中的 Z 表示 UTC(从 UTC 或所谓的祖鲁时区偏移零)。 UTC 时间 12:16:50.52 与中欧夏令时间 (CEST) 的 14:16:50.52 相同。所以要求Tue Jul 17 12:20:50 CEST 2018 Uhr 是错误的。

在您的代码中,您将Z 硬编码为文字,而不是将其解析为应有的偏移量。有趣的是,这产生了单元测试预期的错误时间点,只是不在预期的时区。这可能Date.toString 使用您的JVM 的时区设置和期望这是CEST 的测试有关,而实际上它是GMT。但是,您的 SimpleDateFormat 没有使用 GMT 来解析字符串(可能是 CEST),因此您没有向我们提供足够的信息来解释测试中发生的所有事情。 SimpleDateFormat 将使用相同的 JVM 设置,除非您已明确设置其时区,这在您发布的代码中不会发生。

链接:Oracle tutorial: Date Time解释如何使用java.time

【讨论】:

【参考方案2】:

如果您使用的是 Java8,您可以使用 java.time API,您可以使用默认日期时间格式 Instant 解析您的字符串:

ZonedDateTime zdt = Instant.parse("2018-07-17T12:16:50.52Z")
        .atZone(ZoneId.of("Europe/Berlin"));

输出

2018-07-17T14:16:50.520+02:00[Europe/Berlin]

【讨论】:

但是 Z 表示 GMT 时区对吗?我想要 2018 年 7 月 17 日星期二 [0:20:50 GM]T 的时间 @pgman 你的意思是ZonedDateTime zdt = Instant.parse("2018-07-17T12:16:50.52Z").atZone(ZoneId.of("GMT")); 或者只是Instant ins = Instant.parse("2018-07-17T12:16:50.52Z"); 我不明白你在说什么!【参考方案3】:

这是否意味着我应该将日期转换为 GMT 格式??

不,这意味着不应将“Z”视为像“T”那样的常量分隔符,而应将其视为指示日期时区的完整字段。其中 Z 表示 GMT 时区。

你的格式真的应该是

"yyyy-MM-dd'T'HH:mm:ss.SSX"

这将使 SimpleDateFormat 识别 Z 表示 GMT 时区,因此它生成的 Date 将与 GMT 时区对齐。将其转换为字符串并因此转换为德国时区时,它将添加差异并产生预期的结果。

话虽如此,更好的解决方案是从过时的 java.util.Date 和 SimpleDateFormat 类继续前进,并改用 Java 8 的 java.time.* API。请参阅其他答案以获取灵感。

【讨论】:

使用这种格式只会将小时数增加 2 小时,不会转换为 GMT 你的意思是使用 Z 表示 GMT?在这里,我的格式实际上并没有转换为格林威治标准时间?但是通过将这种格式与 SSX 一起使用,它只会将小时数增加 2 小时,而不会转换为 GMT @pgman 与 java.util.Date 没有“转换为 GMT”之类的东西。此类不包含有关时区的信息。它代表了一个瞬间,不管这个瞬间在纽约、柏林或格林威治如何发音。那里没有时区。这意味着当将 java.util.Date 转换为 String 或从 String 转换时,需要指定一个时区来告诉世界上的哪个瞬间是这样写的(因为它在不同的时区会以不同的方式写成)。在这里,您的测试表明他们期望日期写为 CEST。所以,让他们拥有它。【参考方案4】:

以下是将日历中的日期转换为不同时区的示例。

TimeZone tzLA = TimeZone.getTimeZone("America/Los_Angeles");
    TimeZone tzIN = TimeZone.getTimeZone("Asia/Calcutta");

    Calendar calendar = new GregorianCalendar();

    calendar.setTimeZone(tzLA);

    long timeLA = calendar.getTimeInMillis();

    System.out.println("Time at America in milliseconds = " +timeLA);
    System.out.println("Hour at America = " +calendar.get(Calendar.HOUR_OF_DAY));

    calendar.setTimeZone(tzIN);

    long timeIN = calendar.getTimeInMillis();
    System.out.println("Time at Asia in millis = " + timeIN);
    System.out.println("Hour at Asia = " + calendar.get(Calendar.HOUR_OF_DAY));

这是输出。

Time at America in milliseconds = 1515136660357
Hour at America = 23
Time at Asia in millis = 1515136660357
Hour at Asia = 12

【讨论】:

以上是关于时区 CEST 到 GMT的主要内容,如果未能解决你的问题,请参考以下文章

时区缩写 UTC, CST, GMT, CEST 以及转换

使用本地时区在 Python 中获取正确的时区偏移量

iOS 手机时区获取问题

R 中的时区问题,我想使用 UTC+0100,即使在夏天,尽管 CET 会自动切换到 CEST

服务器时区值“CEST”无法识别

从 GMT 到本地的时区转换