“正确”的JSON日期格式是什么?

1524

我看到了许多不同的 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
哪个是正确的?或者最好的?这方面有什么标准吗?

哪个是正确的?或者最好的?这方面有什么标准吗?


106
JSON中并没有日期格式,只有字符串类型的数据,由序列化和反序列化程序决定将其映射为日期值。 - user395760
13
strings, numbers, true, false, null, objects and arrays - Russ Cam
17
然而,JavaScript内置的JSON对象和ISO8601包含了所有信息,能够被人类和计算机理解,而且不依赖于计算机时代的开始(1970年1月1日)。 - poussma
1
一个很好的参考和阅读材料。UTC与ISO格式的时间。 - Abhishek Gautam
json 支持数字和字符串作为 date - cwtuan
json 支持 date 的数字和字符串。 - cwtuan
16个回答

2441

JSON本身不会指定日期应如何表示,但JavaScript会。

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

2012-04-23T18:25:43.511Z

以下是原因:

  1. 它既易于人类阅读又简洁明了

  2. 它可以正确排序

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

  4. 它符合ISO 8601

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

  6. ISO 8601得到了W3CRFC3339XKCD的认可。

话虽如此,但是所有已经存在的日期库都可以理解“自1970年以来的毫秒数”。因此,为了方便移植性,ThiefMaster是正确的。


47
这也是根据ECMA的推荐方式来表示: JSON.stringify({'now': new Date()}) 结果为:{"now":"2013-10-21T13:28:06.419Z"} - Steven
20
我会在列表中添加另一个重要原因:它是与地区无关的。如果你有一个日期像02-03-2014,你需要额外的信息才能知道它是指2月3日还是3月2日。这取决于使用美国格式还是其他格式。 - Juanal
137
点赞提到并链接xkcd :D @ajorquera 我通常使用momentjs来处理这个问题。我也看到在IE方面存在一些问题。 - fholzer
68
关于第二点,10000年后无法正确排序。不过我们还有将近8000年的时间来想出一个新的格式,所以这可能不是个问题。 - Erfa
10
实际上,@Erfa,由于ASCII-排在数字之前,因此它可以很好地排序,直到公元十万年。;P - Ky -
显示剩余25条评论

160

JSON对日期并无了解。.NET所做的是非标准的hack/扩展。

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


25
如果你选择这条路,确保你不需要处理1970年之前的日期! - Ben Dolman
16
正如@BenDolman所说,这个“解决方案”没有妥善处理1970年1月1日(纪元)之前的日期。此外,ISO8601存在的原因也是有道理的。在地球上我们有所谓的“时区”,毫秒数在哪里?JSON可能没有关于日期的标准,但日期存在于JSON之外,而且确实有一个标准。funroll的答案是正确的(参见:http://xkcd.com/1179/)。 - JoeLinux
7
值得一提的是,自从1970年以来经过的(毫)秒对于未来日期并不可预测,因为我们有闰秒。因此,在进程间通信和数据存储中不应使用它。不过,在程序内部使用它很方便,因为它可以存储在一个整数中,这样可以带来一些性能上的好处。 - Brodie Garnet
10
Unix时间戳始终是UTC时间,您需要在生成时间戳之前将本地时区转换为UTC时间,然后在显示时再将其转回本地时区,这里没有任何歧义。 - lkraider
9
所有认为无法表示1970年之前或未来日期的评论都误解了时间戳(epoch time)。因为时间是相对的,一旦你到达或低于公元1年,日期字符串就会真正崩溃。无论你使用哪个时钟源,它几乎肯定都是基于时间戳的表示方式,因此避免使用时间戳并不能使其更准确。 - Josh from Qaribou
显示剩余10条评论

65

没有正确的日期格式JSON规范没有指定交换日期的格式,这就是为什么有这么多不同的方式来处理它。

最好的格式可能是以ISO 8601格式( 参见维基百科)表示的日期;它是一种众所周知和广泛使用的格式,可以在许多不同的语言中处理,非常适合互操作性。如果您可以控制生成的json数据,例如,您以json格式向其他系统提供数据,则选择8601作为日期交换格式是一个很好的选择。

如果您无法控制生成的json数据,例如,您是来自几个不同现有系统的json的消费者,则处理这种情况的最佳方法是使用日期解析实用程序函数来处理预期的不同格式。


3
@mlissner 但这只是对哪种方式最佳的观点。ISO-8601是一种标准,但它并不是JSON的标准(尽管我倾向于使用它);例如,微软决定不使用它(http://msdn.microsoft.com/en-us/library/bb299886.aspx#intro_to_json_sidebarb)。最佳实践是坚持使用一个(合理的)约定,无论它是什么。正如我在答案中所述,处理这个问题的最佳方法是定义一个日期解析工具函数,可以处理预期的格式。如果您与使用不同格式的系统集成,该函数应该处理每种情况。 - Russ Cam
2
@RussCam,我们可以来回讨论,但如果有人询问在JSON中编码日期的最佳方法,他们是在询问如何在制作JSON时格式化日期(通常的答案是ISO-8601)。你正在回答相反的问题:如何在JSON日期已经制作好后消费它们(尽管你的建议是正确的)。 - mlissner
1
JSON模式规范实际上指出,由模式验证的日期必须采用8601格式。 - gnasher729
3
@gnasher729,您有链接吗? - Russ Cam
1
@vallismortis - 这是一个草案规范,用于定义在各方之间交换的给定JSON结构的模式,而不是JSON规范中日期的格式。根据评论,我将修改我的答案,因为似乎我没有表述清楚。 - Russ Cam
小问题,但我不确定我会说“Microsoft决定不使用它”,更准确地说是*.Net*决定不使用它。我正在使用完整的Microsoft工具链,包括Typescript、C++和JSON,并且愉快地消耗ISO-8601格式。你的情况可能有所不同。 - J. Gwinner

38

当您有疑问时,只需按下F12(在Firefox中为Ctrl+Shift+K),进入现代浏览器的JavaScript Web控制台,并输入以下内容:

new Date().toISOString()

将输出:

"2019-07-04T13:33:03.969Z"

哒哒声!!


1
尽管这是一种合理的格式,但这个答案并没有解释为什么它对于JSON是明智或有用的。为什么JS相关?为什么toISOString相关? - IMSoP
@IMSoP 或许是因为 ISO 标准比日期转字符串转换更好。 - Lepy
@Lepy 那句话并没有真正意义上的意义 - 它仍然只是被转换为字符串,只是选择了一个特定的格式。就像我已经说过的那样,这是一个合理的格式,但答案并没有说明为什么应该使用它;而问题不是关于 JS 的,而是关于 JSON 的。我在评论答案的质量,而不是我是否同意它。 - IMSoP
@IMSoP,我鼓励你学习有关在JSON中传输日期时如何使用ISO 8601日期格式,这是一个很好的用法。理解我提供的答案的关键在于toISOString()部分,当使用它时会产生ISO 8601格式。 - Shayan Ahmad
9
再次强调,我的评论并不是关于这个格式是否好,而是关于这个回答中缺失了什么。如果有人对这个格式一无所知,读完你的回答后,他们仍然会一无所知;甚至连它的名称都不知道。我的问题是为了提示应该编辑到答案中的信息。 - IMSoP
我明白你的观点,@IMSoP。我将添加一些信息,以说明JSON结果的有效性所在。 - Shayan Ahmad

33

来自RFC 7493(I-JSON消息格式)

I-JSON是Internet JSON或Interoperable JSON的缩写,具体取决于您问谁。

协议通常包含旨在包含时间戳或时间持续时间的数据项。建议将所有此类数据项表示为符合ISO 8601格式的字符串值,如RFC 3339中所指定的那样,其中使用大写而非小写字母,时区被包括而不是默认值,并且即使其值为“00”,也应包括可选的尾随秒数。还建议所有包含时间持续时间的数据项符合RFC 3339附录A中的“duration”定义,并具有相同的附加限制。


3
这也是Date().toISOString()Date().toJSON()生成的格式,但由于Date不跟踪时区值,因此始终以世界协调时间(UTC)发出时间戳。该值可以使用new Date("...")Date.parseDate进行解析。 - Søren Løvborg

22

仅供参考,我见过使用这种格式:

Date.UTC(2017,2,22)

它与$.getJSON()函数支持的JSONP一起使用。虽然我不确定是否会推荐这种方法...但是因为人们正在以这种方式进行操作,所以我只是提出了这种可能性。

FWIW:永远不要在通信协议中使用自纪元以来的秒数或毫秒数,因为由于闰秒的随机实现,这些术语充满了危险(您不知道发送者和接收者是否都正确地实现了UTC闰秒)。

有点小心眼,但许多人认为UTC只是GMT的新名称——错误!如果您的系统不实现闰秒,则使用GMT(通常称为UTC,尽管不正确)。如果您确实实现了闰秒,则确实使用的是UTC。未来的闰秒不能预知;它们会根据需要由IERS发布并需要不断更新。如果您运行的系统尝试实现闰秒但包含已过时的参考表格(比您想象的更为常见),则既不是GMT也不是UTC,而是一个假装是UTC的奇怪系统。

只有在拆解格式(年、月、日等)中表示时,这些日期计数器才是兼容的。它们在自纪元格式中绝对不兼容。请记住这一点。


5
我不会使用那种格式,但是你提供的其他信息非常有用,谢谢! - Robert Mikes

20
"2014-01-01T23:28:56.782Z" 日期采用ISO 8601标准和可排序格式来表示UTC时间(由Z表示)。ISO 8601还通过将Z替换为时区偏移的+或-值来支持时区: "2014-02-01T09:28:56.321-10:00" ISO 8601规范中还有其他时区编码变体,但是当前的JSON解析器仅支持“ -10:00”格式。通常最好使用基于UTC的格式(Z),除非您需要确定生成日期的时区(可能仅在服务器端生成时才需要)。
注意:
    var date = new Date();
    console.log(date); // Wed Jan 01 2014 13:28:56 GMT- 
    1000 (Hawaiian Standard Time) 
        
    var json = JSON.stringify(date);
    console.log(json);  // "2014-01-01T23:28:56.782Z"
告诉你,即使JavaScript没有标准格式,这仍是首选方式。
// JSON encoded date
var json = "\"2014-01-01T23:28:56.782Z\"";

var dateStr = JSON.parse(json);  
console.log(dateStr); // 2014-01-01T23:28:56.782Z

11

JSON本身没有日期格式,它并不关心任何人如何存储日期。然而,由于这个问题标记了javascript,我假设你想知道如何将javascript日期存储在JSON中。你可以直接将一个日期传递给JSON.stringify方法,它会默认使用Date.prototype.toJSON,这个方法又会使用Date.prototype.toISOString(有关Date.toJSON的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参数也很有用(MDN on JSON.parse),可以在读取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...

6
首选的方法是使用2018-04-23T18:25:43.511Z格式...
下面的图片展示了为什么这是首选的方式: JSON Date 因此,您可以看到日期有一个本地方法toJSON,它以这种格式return并且可以轻松转换回Date...

2
正确!JSON数据交换语法没有指定标准:http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf,但实际上,包括JavaScript运行时在内的平台更倾向于ISO 8601兼容格式。 - Kamyar Nazeri
这张图片只是展示了JS选择如何实现它,而且问题已经说得很清楚了。这并不影响其他语言可能会做什么或者什么是最佳实践 - JS选择实现的许多事情在其他语言中被认为是糟糕的实践。 - IMSoP

3
在Sharepoint 2013中,获取JSON数据时没有将日期转换为仅包含日期格式的格式,因为在该日期应该是ISO格式。
yourDate.substring(0,10)

这可能对您有所帮助


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