Gson 使用时区反序列化 Java.util.Date

Gson deserialize Java.util.Date with timezone

我用日期反序列化一个 json 字符串:

"created_at": "2015-12-24T17:41:54+01:00",

我为 gsonBuilder 设置了日期格式:

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create();

反序列化工作没有崩溃;不幸的是,当我打印结果时,它是不正确的:

SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ssZ");
String str = ft.format(response.createdAt);

结果是:

2015-12-24T11:41:54-0500

而不是:

2015-12-24T17:41:54+01:00

您没有设置时区,只是在 date/time 的末尾添加了一个 Z,因此它看起来像 GMT date/time,但这不会改变值。

将时区设置为 GMT,这将是正确的。

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));

java.time

接受的答案是正确的。但是过时了。 java.text.SimpleDateFormat 和 java.util.Date classes 已被添加到 Java 8 及更高版本的 java.time 框架淘汰。更容易使用和更明智。

ISO 8601

您输入的字符串格式符合ISO 8601标准。当 parsing/generating 字符串表示 date-time 值时,java.time classes 使用 ISO 8601 作为它们的默认格式。

String input = "2015-12-24T17:41:54+01:00";

Offset-From-UTC

该输入字符串包含 +01:00offset-from-UTC,这意味着比 UTC 早一个小时。

ZonedDateTime zdt = ZonedDateTime.parse ( input );
ZoneId z = zdt.getZone ();

偏移量与时区

但是那个偏移量不是时区。时区是一个偏移加上 规则,用于处理异常调整,例如夏令时 (DST)。所以你可能想要分配 a specific time zone you have in mind as being intended by that string. Perhaps you intended Amsterdam time

我们可以申请一个时区以获得另一个ZonedDateTime object. This pattern of creating a new object based on an old object’s values rather than changing the old values directly is known as immutable objects

A ZoneId is a full time zone in java.time. Its subclass ZoneOffset 用于没有调整规则的简单 offset-from-UTC 值。

ZoneId zoneIdAmsterdam = ZoneId.of ( "Europe/Amsterdam" );
ZonedDateTime zdtAmsterdam = zdt.withZoneSameInstant ( zoneIdAmsterdam );

toString

当您在 System.out.println 中调用 toString 时,java.time class 会使用 ISO 8601 格式生成 date-time 值的字符串表示形式.

请注意,除了 offset-from-UTC 编号之外,java.time 通过在方括号中附加指定时区的名称来扩展 ISO 8601。例如,[Europe/Amsterdam].

    System.out.println ( "zdt: " + zdt + " at zoneId z: " + z + " adjusted to zoneIdAmsterdam: " + zoneIdAmsterdam + " is zdtAmsterdam: " + zdtAmsterdam );

zdt: 2015-12-24T17:41:54+01:00 at zoneId z: +01:00 adjusted to zoneIdAmsterdam: Europe/Amsterdam is zdtAmsterdam: 2015-12-24T17:41:54+01:00[Europe/Amsterdam]

Instant

通常在我们的业务逻辑和数据存储中,我们严格按照 UTC 工作,应用时区只是为了向用户展示。为此,传递并存储 Instant class 的实例。此 class 表示 UTC 时间轴上的一个时刻。

Instant instant = zdt.toInstant();