“正确的” JSON 日期格式

我已经看到 JSON 日期格式的许多不同标准:

"\"\\/Date(1335205592410)\\/\""         .NET JavaScriptSerializer
"\"\\/Date(1335205592410-0500)\\/\""    .NET DataContractJsonSerializer
"2012-04-23T18:25:43.511Z"              JavaScript built-in JSON object
"2012-04-21T18:25:43-05:00"             ISO 8601

哪一个是正确的?还是最好的?有什么标准吗?

答案

JSON本身并未指定日期应如何表示,但 JavaScript 却指定了。

应该使用DatetoJSON方法发出的格式:

2012-04-23T18:25:43.511Z

原因如下:

  1. 它是人类可读的但也很简洁

  2. 排序正确

  3. 它包括小数秒,可以帮助重新建立时间顺序

  4. 符合ISO 8601

  5. ISO 8601 已经在国际上建立了十多年的历史

  6. W3CRFC3339XKCD认可了 ISO 8601

话虽这么说 ,每个日期库都可以理解 “自 1970 年以来的毫秒数”。因此,为了方便携带, ThiefMaster是正确的。

JSON 对日期一无所知。 .NET 所做的是非标准的 hack / 扩展。

我将使用一种可以轻松转换为 JavaScript 中的Date对象的格式,即可以传递给new Date(...)的格式。最简单且可能最可移植的格式是自 1970 年以来包含毫秒的时间戳。

没有正确的格式 ; JSON 规范没有指定交换日期的格式,这就是为什么有这么多种不同的方式来实现的原因。

最好的格式可以说是以ISO 8601 格式表示的日期请参阅 Wikipedia )。它是一种众所周知的且被广泛使用的格式,并且可以跨多种不同的语言进行处理,因此非常适合互操作性。例如,如果您可以控制生成的 json,则可以 json 格式将数据提供给其他系统,那么选择 8601 作为日期交换格式是一个不错的选择。

例如,如果您无法控制生成的 json,则您是几个现有系统中 json 的使用者,那么处理此问题的最佳方法是使用日期解析实用程序功能来处理所需的不同格式。

RFC 7493(I-JSON 消息格式)开始

I-JSON 代表 Internet JSON 或可互操作 JSON,具体取决于您问谁。

协议通常包含旨在包含时间戳或持续时间的数据项。建议所有此类数据项均按照RFC 3339 中的规定以 ISO 8601 格式的字符串值表示,并具有其他限制,即使用大写而不是小写字母,时区不默认设置,并且可选的尾随秒数即使它们的值为 “00” 也要包括在内。还建议所有包含持续时间的数据项均符合 RFC 3339 附录 A 中的 “持续时间”,并具有相同的附加限制。

仅供参考,我已经看到使用此格式:

Date.UTC(2017,2,22)

它与$.getJSON()函数支持的JSONP一起使用。不确定我是否会推荐这种方法... 只是把它扔掉是有可能的,因为人们是这样做的。

FWIW:切勿在通信协议中使用自纪元以来的秒数,也不要自纪元以来的毫秒数,因为由于 leap 秒的随机实现而使它们充满了危险(您不知道发送方和接收方是否都正确实现了 UTC leap 秒)。

有点讨厌,但许多人认为 UTC 只是 GMT 的新名称 - 错误!如果您的系统未实现 leap 秒,则说明您使用的是 GMT(尽管不正确,但通常称为 UTC)。如果您完全实现了 leap 秒,则说明您确实在使用 UTC。无法知道未来的 leap 秒;它们会在必要时由 IERS 发布,并且需要不断更新。如果您正在运行一个试图实施 leap 秒但包含和过时的参考表(比您想象的更常见)的系统,那么您既没有 GMT 也没有 UTC,那么您的系统就很虚假,是 UTC。

这些日期计数器仅在以细分格式(y,m,d 等)表示时才兼容。它们从不以纪元格式兼容。记住这一点。

如有疑问,只需按 F12 键(在 Firefox 中为 Ctrl + K),然后转到现代浏览器的 javascript Web 控制台,然后编写以下代码:

new Date().toISOString()

将输出:

“2019-07-04T13:33:03.969Z”

-

JSON 本身没有日期格式,它不在乎任何人如何存储日期。但是,由于此问题是用 javascript 标记的,因此我假设您想知道如何在 JSON 中存储 JavaScript 日期。您可以只将日期传递给JSON.stringify方法,默认情况下它将使用Date.prototype.toJSON ,而后者又使用Date.prototype.toISOStringDate.prototype.toISOString MDN ):

const json = JSON.stringify(new Date());
const parsed = JSON.parse(json); //2015-10-26T07:46:36.611Z
const date = new Date(parsed); // Back to date object

我还发现使用JSON.parsereviver参数( 在 JSON.parse 上MDN )可以在每次读取 JSON 字符串时自动将 ISO 字符串转换回 javascript 日期,这很有用。

const isoDatePattern = new RegExp(/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/);

const obj = {
 a: 'foo',
 b: new Date(1500000000000) // Fri Jul 14 2017, etc...
}
const json = JSON.stringify(obj);

// Convert back, use reviver function:
const parsed = JSON.parse(json, (key, value) => {
    if (typeof value === 'string' &&  value.match(isoDatePattern)){
        return new Date(value); // isostring, so cast to js date
    }
    return value; // leave any other value as-is
});
console.log(parsed.b); // // Fri Jul 14 2017, etc...

我相信实现通用互操作性的最佳格式不是 ISO-8601 字符串,而是 EJSON 使用的格式:

{ "myDateField": { "$date" : <ms-since-epoch> } }

如此处所述: https : //docs.meteor.com/api/ejson.html

好处

  1. 解析性能:如果您将日期存储为 ISO-8601 字符串,那么在期望该特定字段下的日期值的情况下,这是很好的选择,但是如果您有一个必须在没有上下文的情况下确定值类型的系统,则需要解析一个字符串。日期格式。
  2. 不需要日期验证:您不必担心日期的验证和验证。即使字符串与 ISO-8601 格式匹配,也可能不是真实日期; EJSON 日期永远不会发生。
  3. 明确的类型声明:就通用数据系统而言,如果要在一种情况下将 ISO 字符串存储为字符串 ,而在另一种情况下以真实系统日期存储 ,则采用 ISO-8601 字符串格式的通用系统将不允许这样做。 (没有越狱技巧或类似的糟糕解决方案)。

结论

我了解人类可读的格式(ISO-8601 字符串)在 80%的用例中都是有用的,并且更加方便 ,并且确实没有人被告知不要将其日期存储为 ISO-8601 字符串,如果这就是他们的应用理解, 但是对于一种普遍接受的传输格式,该格式应保证某些值可以肯定是日期,我们如何允许歧义和需要进行大量验证?

在 Sharepoint 2013 中,获取 JSON 数据时没有将日期转换为仅日期格式的格式,因为该日期应为 ISO 格式

yourDate.substring(0,10)

这可能对您有帮助

首选方式是使用2018-04-23T18:25:43.511Z ...

下图显示了为什么这是首选方式:

JSON日期

因此,如您所见,Date 具有本机方法toJSON ,该方法以这种格式return ,并且可以轻松地再次转换为Date