时区CEST转GMT

3

我需要按照以下格式输入日期时间:

"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,现代Java日期和时间API 。此外,在格式模式字符串中不要硬编码Z作为文本。它是一个UTC偏移量,需要解析为此,否则会得到不正确的结果。 - Ole V.V.
你的代码没有生成单元测试报告中所述的 Tue Jul 17 10:20:50 GMT 2018 Uhr,至少没有生成 "Uhr"。能否请你创建一个“最小、完整和可验证的示例”(Minimal, Complete, and Verifiable example)?这样我们就可以更好地帮助你了。 - Ole V.V.
你的例子中方括号是什么意思?是打错了吗? - Basil Bourque
@BasilBourque 当比较预期和实际字符串时,JUnit(以及可能的其他测试框架?)会在不同的部分周围插入方括号。因此,显然测试比较字符串,但是DATE_TIME_FORMATTER.parse不会产生字符串,因此还有一些我们尚未被告知的内容。 - Ole V.V.
4个回答

3
    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中欧夏令时

您的测试用例期望的结果是错误的。您输入的字符串中的Z表示UTC(与UTC偏移量为零或所谓的Zulu时区)。在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教程:日期时间,介绍如何使用java.time


1
如果您正在使用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表示格林威治标准时间,对吧?我想要的是2018年7月17日10:20:50 GMT时间。 - pgman
@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");?我不明白你在说什么! - Youcef LAIDANI

0
这是一个将日期从日历转换为不同时区的示例。
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

0
这是否意味着我应该将日期转换为GMT格式?不是的,它意味着“Z”不应像“T”一样被视为常量分隔符,而应作为一个完整的字段,表示日期的时区。其中Z表示GMT时区。你的格式应该真正如下:
"yyyy-MM-dd'T'HH:mm:ss.SSX"

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

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


使用这种格式只会增加2小时,而不会转换为GMT。 - pgman
你的意思是使用Z表示格林威治标准时间?但是使用我的格式并没有真正转换为GMT?但是使用SSX格式会将小时数增加2个小时而不是转换为GMT。 - pgman
1
@pgman 在使用 java.util.Date 时,不存在所谓的“转换为 GMT”。该类不包含有关时区的信息。它表示时间的瞬间,无论这个瞬间在纽约、柏林或格林威治如何发音。那里没有时区。这意味着,在将 java.util.Date 转换为字符串或从字符串转换时,需要指定一个时区来告诉世界上哪个地方写下了这个瞬间(因为在不同的时区中,它会被写成不同的形式)。在这里,您的测试表明它们期望以 CEST 的形式编写日期。所以,让它们拥有它。 - kumesana

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接