Javascript和Java Date JSON序列化

Javascript and Java Date JSON serialization

我有一个带有Date属性的javascript对象,它使用JSON.stringify转换为JSON

我在GMT + 4时区(俄罗斯/莫斯科)

例如,
5 Jan 2012转换为2012-01-04T20:00:00.000Z

5 Jan 1975转换为1975-01-04T20:00:00.000Z

但是在1975年它是GMT + 3时区,因为2011年在俄罗斯取消了夏令时。所以当它来到服务器(java)时,它反序列化为:

2012-01-04T20:00:00.000Z因为5 Jan 2012 00:00 - 好的

1975-01-04T20:00:00.000Z becames 4 Jan 1975 23:00 - 错!

在Javascript中将Date对象转换为JSON的推荐方法是什么?


我更喜欢坚持使用javascripts ISO 8601日期格式,
在正确解析它时,它将自动处理时区差异。

在java中,您可以解析javascript Stringified JSON日期,如下所示:

1
2
3
String iso8601Date ="2013-08-13T14:15:00.000Z";
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
Date parsedDate = formatter.parse(iso8601Date);

当把它变回字符串时,你会有类似的东西

1
2
//"2013-08-13T16:15:00.000+02:00"
String formattedDate = formatter.format(parsedDate);

为了解析JSON我使用FlexJson,您可以像这样配置。

1
2
3
4
5
//Serializing to JSON
DateTransformer dateTransformer = new DateTransformer("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
new JSONSerializer().transform(dateTransformer, Date.class).serialize(object);
//deserialize From JSON (replace object by java class)
JSONDeserializer<..Object..>().use(Date.class, dateTransformer).deserialize(json);


我建议使用自纪元符号以来的秒数来传递日期/时间,更具体地说是自Unix纪元(1970年1月1日00:00 GMT)以来的秒数。如果你不熟悉这个,那里有一个示例转换器:http://www.epochconverter.com/

这有一些优点:

  • 它指的是与时区无关的同一时刻。这有助于独立于时区错误存储时间(当然,首先必须正确输入它们)。
  • 它是java.util.Date中唯一不推荐使用的构造函数(除了没有参数的构造函数),请参阅(getTime())。 (请注意,这使用毫秒。)
  • JavaScript可以很容易地从中构建日期(例如new Date(1000 * 1326894706))。 (请注意,这使用毫秒。)
  • 如果重要的话,它总是会比"yyyy-MM-dd HH:mm:ss"中的任何一个小(在JSON序列化中的数据大小方面)。
  • 如果您希望渲染时区并将其与此数字相关联,则可以始终向表示添加额外字段。 {"datetime": 1326894706,"tz":"GMT" }仍然短于{"datetime":"18 Jan 2012 13:51:46 GMT" }

考虑到在Java和JavaScript中很容易从中获取Date实例,然后可以使用DateFormatter将其转换为Java中的文本。对于JavaScript,使用诸如日期格式之类的库将帮助您在页面上适当地呈现它(例如,使用类似new Date(val * 1000).format("yyyy-mm-dd HH:MM")的内容)。


如果使用Spring Framework,则可以使用@JsonSerialize(using = CustomLocalDateSerializer.class)@JsonDeserialize(using = ISO8601LocalDateDeserializer.class)注释。它会正确解析你的javascript Date

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class product {

    @NotNull
    private Long id;

    @NotNull
    private String name;

    @JsonSerialize(using = CustomLocalDateSerializer.class)
    @JsonDeserialize(using = ISO8601LocalDateDeserializer.class)
    private LocalDate date;

    // getter and setter...
}

这个帖子相当陈旧。现在,使用java 8,您应该在表单dto中使用ZonedDateTime。使用spring-mvc,Jackson将正确地将ISO格式(例如:"2019-03-27T22:05:42.763Z")映射到ZonedDateTime。

但是,Date.toISOString方法始终将时区设置为utc,因此反序列化的ZonedDateTime区域将始终设置为UTC。如果您需要服务器端的区域,则可能会出现问题。比方说,您需要向客户发送一封电子邮件,其中包含他/她刚刚通过表单提交的日期:您希望使用相同的区域。

如果你想传递时区并遵守ISO格式,你应该使用像moment.js这样的lib来格式化javascript中的日期。然后在序列化时:

1
moment().format('YYYY:MM:DDTHH:mm:ssZ') //"2019:03:27T23:06:11+01:00"

JSON没有Date支持,所有解析器/序列化器都使用toString或类似的东西。您可以自行序列化/反序列化日期。
由于Javascript没有包含合适的日期格式化程序,因此最简单的解决方案是将日期转换为long。但是如果你想能够阅读正在发生的事情,我建议http://www.datejs.com/和格式化日期为yyyy-MM-dd HH:mm:ss


我个人会使用以下内容将它们转换为java中的String:

1
String theDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);

然后String被序列化。在javascript方面,你只需解析它。