Java:修复日期对象中错误的时区

3

一个外部API返回了一个包含日期的对象。
根据他们的API规范,所有日期都以格林尼治标准时间(GMT)报告。

然而,生成的客户端类(我无法编辑)没有正确设置时区。相反,它使用本地时区而不将日期转换为该时区。

因此,长话短说,我有一个日期对象,我知道它是GMT,但它显示为中欧时间(CET)。如何在不更改计算机本地时区或类似的操作的情况下调整此错误?

LocalDateTime.ofInstant(someObject.getDate().toInstant().plus(1, ChronoUnit.HOURS),
                        ZoneId.of("CET"));

谢谢。

你能提供可解析的String的示例值吗?接收到的日期时间是什么样子的?它是一个String还是Date或者LocalDateTime甚至是ZonedDateTime的实例呢? - deHaar
1
它已经是一个java.util.date对象(我没有解析任何东西,提供和生成的客户端类会错误地执行此操作,如所述)。 - Christoph Strehl
例如,我的日期对象.toString()应该返回“2020年1月24日星期五09:15:00 GMT”,但实际上它返回的是“2020年1月24日星期五09:15:00 CET”或“2020年1月24日星期五10:15:00 CET”。 - Christoph Strehl
3
@ChristophStrehl,java.util.Date没有时区。它会按照JVM的默认时区进行打印。因此,如果您在CET时区,则会以CET时区进行打印。如果他们返回一个java.util.Date,那么“根据他们的API规范,所有日期始终报告为GMT”是不可能的。 - Andy Turner
@AndyTurner 我认为这只是一半的真相。现在已经弃用的 getTimeZoneOffset() 方法表明,最初 java.util.Date 类被设计成也可以包含有关时区的信息。 - Amadán
显示剩余4条评论
2个回答

2

简而言之,使用ZonedDateTime进行转换

public static void main(String[] args) {
    // use your date here, this is just "now"
    Date date = new Date();
    // parse it to an object that is aware of the (currently wrong) time zone
    ZonedDateTime wrongZoneZdt = ZonedDateTime.ofInstant(date.toInstant(), ZoneId.of("CET"));
    // print it to see the result
    System.out.println(wrongZoneZdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));

    // extract the information that should stay (only date and time, NOT zone or offset)
    LocalDateTime ldt = wrongZoneZdt.toLocalDateTime();
    // print it, too
    System.out.println(ldt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));

    // then take the object without zone information and simply add a zone
    ZonedDateTime correctZoneZdt = ldt.atZone(ZoneId.of("GMT"));
    // print the result
    System.out.println(correctZoneZdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
}

输出:

2020-01-24T09:21:37.167+01:00[CET]
2020-01-24T09:21:37.167
2020-01-24T09:21:37.167Z[GMT]

解释:

你之前的方法不仅校正了时区,还调整了时间(如果需要这样做也是好的),这是因为你使用了从Instant创建的LocalDateTimeInstant代表一个时刻,在不同的时区中可以有不同的表示,但它保持相同的时刻。如果你从它创建一个LocalDateTime并放在另一个时区中,则日期和时间将被转换为目标时区的日期和时间。这不仅仅是替换时区,同时保持日期和时间不变。

如果你使用从ZonedDateTime中提取出来的LocalDateTime,则忽略时区,只提取出日期和时间,这使你能够在添加新的时区后保持日期和时间不变。

编辑:如果代码在与错误代码相同的JVM上运行,则可以使用ZoneId.systemDefault()获取与错误代码使用的相同时区。根据你的口味,你也可以使用ZoneOffset.UTC而不是ZoneId.of("GMT")


2
谢谢,那个解决方案对我很有用,我还使用了评论中的调整。 - Christoph Strehl
@OleV.V. 感谢您的编辑,我本来想把它包含在答案中的,但是没有时间... - deHaar

0

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