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

What is the "right" JSON date format?

提问人:Kamyar Nazeri 提问时间:4/24/2012 最后编辑:leonheessKamyar Nazeri 更新时间:8/18/2023 访问量:1848485

问:

我见过很多不同的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

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

JavaScript JSON

评论

106赞 4/24/2012
JSON 中没有日期格式,只有 de-/序列化程序决定映射到日期值的字符串。
13赞 Russ Cam 4/24/2012
stringsnumberstruefalsenullobjectsarrays
17赞 poussma 1/23/2013
但是,JavaScript 内置的 JSON 对象ISO8601包含了人类和计算机需要理解的所有信息,并且不依赖于计算机时代(1970-1-1)的开始。
1赞 Abhishek Gautam 11/26/2021
stackoverflow.com/questions/58847869/utc-vs-iso-format-for-time一个很好的参考,很好读。
0赞 cwtuan 1/10/2023
JSON 支持 的数字和字符串。date

答:

160赞 ThiefMaster 4/24/2012 #1

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

我会使用一种可以很容易地转换为 JavaScript 中对象的格式,即可以传递给新 Date(...) 的格式。最简单、可能最便携的格式是自 1970 年以来包含毫秒的时间戳。Date

评论

25赞 Ben Dolman 5/10/2013
如果你走这条路,请确保你不需要处理早于 1970 年的日期!
16赞 JoeLinux 11/15/2013
正如@BenDolman所说,这个“解决方案”不能适当地处理 1970 年 1 月 1 日(纪元)之前的日期。此外,首先存在ISO8601也是有原因的。在地球上,我们有所谓的“时区”。毫秒在哪里?JSON 可能没有日期标准,但日期存在于 JSON 之外,并且有一个标准。Funroll的答案是正确的(另见:xkcd.com/1179)。
7赞 Brodie Garnet 11/3/2015
也许还值得一提的是,1970 年的(毫)秒对于未来的日期是不可预测的,因为我们有闰秒。因此,我不会将 if 用于进程间通信和数据存储。但是,在程序内部使用是很好的,因为它可以存储在单个整数中,这为您提供了一些性能优势。
10赞 lkraider 11/10/2016
Unix 时间戳始终是 UTC,您在生成时间戳之前从本地时区转换,然后再次转换回显示的本地时区,那里没有歧义。
9赞 Josh from Qaribou 11/20/2016
这些评论中的每一个都说 1970 年代之前的日期或未来的日期不能表示,这是对纪元时间的误解。所有的时间都是相对的,一旦你达到/低于第 1 年,日期字符串就会真正崩溃。无论您的时间源时钟是什么,它几乎肯定是基于纪元时间的表示,因此您不会通过避免纪元时间来使其更准确。
65赞 Russ Cam 4/24/2012 #2

没有正确的格式;JSON规范没有指定交换日期的格式,这就是为什么有这么多不同的方法可以做到这一点。

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

如果您无法控制生成的 json,例如,您是来自多个不同现有系统的 json 的使用者,则处理此问题的最佳方法是使用日期解析实用程序函数来处理预期的不同格式。

评论

3赞 Russ Cam 4/30/2013
@mlissner但这是关于哪一个最好的意见。ISO-8601 是一个标准,但它不是 JSON 的标准(尽管我倾向于使用它);例如,Microsoft决定不使用它(msdn.microsoft.com/en-us/library/...最好的做法是坚持一个(明智的)约定,不管那是什么。正如我在回答中所说,处理此问题的最佳方法是定义一个可以处理预期格式的日期解析实用程序函数。如果与使用不同格式的系统集成,则该函数应处理每种情况。
2赞 mlissner 5/1/2013
@RussCam,我们可以来回走动,但如果有人问用JSON编码日期的最佳方法,他们就会问在制作JSON时如何格式化日期(答案通常是ISO-8601)。你回答的是相反的问题:一旦 JSON 日期已经制作完成,如何使用它们(尽管你的建议是合理的)。
1赞 gnasher729 1/17/2015
JSON 架构规范实际上规定,由架构验证的日期必须采用 8601 格式。
3赞 Russ Cam 1/17/2015
@gnasher729你有链接吗?
1赞 Russ Cam 6/27/2015
@vallismortis - 这是用于为各方之间交换的给定 json 结构定义架构的规范草案,而不是 json 规范中的日期格式。我将根据评论修改我的答案,看来我做得不够清楚
2443赞 funroll 4/11/2013 #3

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赞 Steven 10/21/2013
这也是根据 ECMA 的首选表示:JSON.stringify({'now': new Date()}) "{"now":"2013-10-21T13:28:06.419Z"}"
20赞 Juanal 7/2/2014
我会在列表中添加另一个重要原因:它与语言环境无关。如果您的日期是 2014 年 3 月 2 日,您需要其他信息才能知道它指的是 2 月 3 日还是 3 月 2 日。这取决于使用的是美国格式还是其他格式。
137赞 fholzer 4/30/2015
为提及和链接 xkcd 投赞成票:D @ajorquera我通常为此使用 momentjs。在这方面,我也看到了IE的问题
68赞 Erfa 8/19/2015
关于第二点,它在 10000 年之后没有正确排序。不过,我们确实有将近 8000 年的时间来提出一种新格式,所以这可能不是问题。
10赞 Ky - 5/3/2016
实际上,@Erfa,由于在数字之前,它会很好地排序,直到 100,000 年。;P-ASCII
33赞 Bryan Larsen 3/28/2015 #4

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

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

协议通常包含旨在包含的数据项 时间戳或持续时间。建议所有此类数据 项目以 ISO 8601 格式表示为字符串值,如指定 在 RFC 3339 中,具有大写的附加限制 比使用小写字母,则不包括时区 默认值,并且即使 它们的值为“00”。还建议所有数据项 包含的持续时间符合 RFC 3339 的附录 A,具有相同的附加限制。

评论

3赞 Søren Løvborg 9/21/2015
这也是 和 生成的格式,但限制是不跟踪时区值,因此始终以 UTC () 时区发出时间戳。可以使用 和 来解析该值。Date().toISOString()Date().toJSON()DateZnew Date("...")Date.parseDate
-8赞 Chad Wilson 12/17/2015 #5

这个问题只有一个正确答案,大多数系统都错了。自纪元以来的毫秒数,又名 64 位整数。时区是一个 UI 问题,在应用程序层或数据库层中没有业务。为什么你的数据库关心某物是什么时区,当你知道它会将其存储为 64 位整数时,然后进行转换计算。

去掉多余的部分,只将日期视为数字,直到 UI。您可以使用简单的算术运算符来执行查询和逻辑。

评论

7赞 aij 9/22/2016
现在你有 2 个问题:你应该选择哪个纪元,你应该计算哪毫秒?可能最常见的选择是 Unix 时间(1970-01-01T00:00:00 UTC 和 SI 毫秒,除了那些落在闰秒以内的时间),但当然,这使得未来的时间不确定。
4赞 gnasher729 11/5/2016
那么如何表示微秒呢?RFC3339在任何精度下都能正常工作,您将拥有一个解析时区并为您提供正确时间戳的阅读器,以及附加信息。日历应用通常关心时区。
14赞 Panagiotis Kanavos 12/5/2016
时区不是 UI 问题,除非您不介意错过下一趟航班。航班以当地时间发布,并遵循 DST 更改的特定规则。丢失偏移量意味着丢失重要的业务信息
3赞 Timo 12/14/2016
一些进一步的反驳包括表示 1970 年之前的时间的能力(假设那个特定的时代),以及 JSON 在某种程度上是人类可读的。
2赞 Ciabaros 11/2/2019
关于时区注释干草叉:虽然我同意说它是哪一层的关注点(UI,业务逻辑即数据)是危险的,因为这是特定于应用程序的 - 存储日期时间的通用方法不应包括时区,因为您始终可以通过标准易于理解的方式推导出日期时间的任何时区特定变体。我觉得任何将时区普遍存储到日期中的论点在试图将 LOCATION 包含在日期时间中都是错误的,而日期时间应该存储为单独的独立数据。
-21赞 Marten 1/1/2016 #6

我认为这实际上取决于用例。在许多情况下,使用适当的对象模型(而不是将日期呈现为字符串)可能更有益,如下所示:

{
"person" :
      {
 "name" : {
   "first": "Tom",
   "middle": "M",
  ...
}
 "dob" :  {
         "year": 2012,
         "month": 4,
         "day": 23,
         "hour": 18,
         "minute": 25,
         "second": 43,
         "timeZone": "America/New_York"
    }   
   }
}

诚然,这比 RFC 3339 更冗长,但是:

  • 它也是人类可读的
  • 它实现了一个适当的对象模型(就像在 OOP 中一样,只要 JSON 允许它)
  • 它支持时区(而不仅仅是给定日期和时间的 UTC 偏移量)
  • 它可以支持更小的单位,如毫秒、纳秒等。或者只是小数秒
  • 它不需要单独的解析步骤(解析日期时间字符串),JSON 解析器将为您完成所有操作
  • 使用任何日期时间框架或任何语言的实现轻松创建
  • 可以很容易地扩展以支持其他日历刻度(希伯来语、汉语、伊斯兰教等)和时代(公元、公元前等)
  • 这是 10000 年安全 ;-)(RFC 3339 不是)
  • 支持全天日期和浮动时间(Javascript 不支持)Date.toJSON()

我不认为正确的排序(如 RFC 3339 的 funroll 所指出的那样)是将日期序列化为 JSON 时真正需要的功能。此外,这仅适用于具有相同时区偏移量的日期时间。

评论

8赞 memory of a dream 3/9/2016
我怀疑有人会在 10000 年使用 json,甚至到那时 10000 年仍然是 10000 年。但是,如果到那时这两件事仍然成立,则可以简单地扩展该格式以包含 3 位数的世纪分量。所以我想说人们可以安全地坚持使用 RFC 3339,至少在 9900 年之前
7赞 Kevin 6/30/2016
@Marten 两件事。1. 你从来没有被欠过反对票的解释,尽管我知道这可能会有所帮助。2. 我没有对你的答案投反对票,但我猜人们不喜欢你的答案,因为他们认为这是错误的做法。这将将其定性为“错误信息”,因为问题是寻找做某事的最佳方式
10赞 aij 9/22/2016
我没有对你投反对票,但我当然可以理解“发明另一种指定不佳的格式”(这基本上就是你所说的)会被视为错误或研究不足。
3赞 Marten 8/8/2017
@Phil,UTC并不是一个真正的时区(地球上没有一个地方使用“UTC”作为其官方时区),它是一个时间标准。此外,时区偏移量也是非常不可预测的。没有办法说在 2025 年“莫斯科时间 12:00”是否仍然像今天一样是“UTC 9:00”,在过去的 30 年里已经更改了几次。如果要表示未来的本地时间,则需要真实的时区。
2赞 random_user_name 2/9/2018
我只想说:你很顽强!保持(当前)得分为 -15 的答案,已收集了 23 张反对票!(顺便说一句,我没有投反对票)
3赞 raghava arr 9/16/2016 #7

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

yourDate.substring(0,10)

这可能对您有所帮助

22赞 Tel 2/27/2017 #8

仅供参考,我已经看到使用了这种格式:

Date.UTC(2017,2,22)

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

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

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

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

评论

5赞 Robert Mikes 12/25/2017
我不会使用这种格式,但您提供的其余信息非常有用,谢谢!
-3赞 Kemal Karadag 8/24/2017 #9

它对我有用 parse Server

{
    "ContractID": "203-17-DC0101-00003-10011",
    "Supplier":"Sample Co., Ltd",
    "Value":12345.80,
    "Curency":"USD",
    "StartDate": {
                "__type": "Date",
                "iso": "2017-08-22T06:11:00.000Z"
            }
}
-12赞 Aniket Kumar 4/10/2018 #10

以下代码对我有用。此代码将以 DD-MM-YYYY 格式打印日期。

DateValue=DateValue.substring(6,8)+"-"+DateValue.substring(4,6)+"-"+DateValue.substring(0,4);

否则,您还可以使用:

DateValue=DateValue.substring(0,4)+"-"+DateValue.substring(4,6)+"-"+DateValue.substring(6,8);
6赞 Alireza 1/31/2019 #11

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

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

JSON Date

所以正如你所看到的 Date 有一个 原生方法 ,它以这种格式,可以很容易地再次转换为......toJSONreturnDate

评论

2赞 Kamyar Nazeri 1/31/2019
正确!JSON 数据交换语法没有指定标准:ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf 但在实践中,ISO 8601 兼容格式在包括 JavaScript 运行时在内的平台上更受欢迎。
0赞 IMSoP 7/26/2022
图片只是表明JS选择实现它的方式,问题已经说了很多。这与其他语言可能做什么,或者什么是好的做法没有任何关系——JS 选择实现很多东西,而其他语言会认为这是糟糕的做法。
3赞 Ciabaros 2/8/2019 #12

我认为通用互操作性的最佳格式不是 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 字符串,但对于普遍接受的传输格式,它应该保证某些值肯定是日期, 我们怎么能允许模棱两可,需要如此多的验证?

评论

1赞 Sudhanshu Mishra 11/1/2019
请参阅线程前面的这个答案,了解为什么自纪元以来的毫秒有警告,例如闰秒的计算不正确等:stackoverflow.com/a/42480073/190476
0赞 Ciabaros 11/2/2019
@SudhanshuMishra 您引用的警告是针对 unix 时间戳的极端学术问题的一般问题,主要与时间戳生成有关。对于毫秒级分辨率来说,这更不重要。正如在另一条评论中指出的那样,大多数计算机日期在内部表示为 unix 时间戳,即使它们以其他方式公开和格式化。尽管如此,任何给定日期+时间的毫秒表示都没有错,特别是与其他方法相比,这些方法很容易受到引擎盖下相同的纳米影响警告的影响。
0赞 Ciabaros 11/2/2019
补充一下对 unix 时间戳的“超出范围”日期的担忧:这些是系统存储问题,需要在比传输格式更广泛的上下文中解决。例如,这种格式不需要局限于适合 32 位的整数,也不需要是严格的正数,但没有人会通过在系统/架构级别上删除时间戳来解决“2038 年问题”;它们只需要扩展(例如,扩展到 64 位或更高),这不会影响这种建议的传输格式。
0赞 Yaytay 4/7/2022
太迟了。这可能是用于 JSON 的一个很好的格式,但现在大多数系统都使用自 epoch 以来的ISO8601或直接时间,其他任何事情都是令人头疼的互操作性问题。EJSON让我想起了这一点: xkcd.com/927 它提供了在 JS 中使用 JSON 的解决方案,但有很多 JSON 没有使用 JS 进行处理。
0赞 Ciabaros 1/3/2023
@Yaytay EJSON 中的数字是“自纪元以来的直线时间”,以毫秒为单位。这就是时间戳通常的样子。
11赞 Justus Romijn 5/8/2019 #13

JSON本身没有日期格式,它不关心任何人如何存储日期。但是,由于这个问题被标记为 javascript,我假设您想知道如何在 JSON 中存储 javascript 日期。你可以只将一个日期传递给该方法,它将默认使用,而该方法又使用(Date.toJSON 上的 MDN):JSON.stringifyDate.prototype.toJSONDate.prototype.toISOString

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 字符串时,使用 (JSON.parse 上的 MDN) 参数自动将 ISO 字符串转换回 javascript 日期很有用。reviverJSON.parse

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...
38赞 Shayan Ahmad 7/4/2019 #14

如有疑问,只需按 (Firefox 中的 ++) 进入现代浏览器的 javascript Web 控制台,然后编写以下内容:F12CtrlShiftK

new Date().toISOString()

将输出:

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

哒哒!!

评论

1赞 IMSoP 7/26/2022
虽然这是一个合理的格式,但这个答案并没有说明为什么它对 JSON 来说是一个明智或有用的格式。为什么 JS 是相关的?为什么是相关的?toISOString
0赞 Lepy 8/16/2022
@IMSoP可能是因为 ISO 标准比日期到字符串的转换要好得多
0赞 IMSoP 8/16/2022
@Lepy 这句话真的没有意义——它仍然只是被转换为字符串,只是选择一种特定的格式。正如我已经说过的,这是一种合理的格式,但答案并没有说明为什么要使用它;问题不在于 JS,而在于 JSON。我是在评论答案的质量,而不是我是否同意它。
0赞 Shayan Ahmad 8/19/2022
@IMSoP,我鼓励您了解 ISO 8601 日期格式在以 JSON 格式传输日期时如何成为一种极好的用法。理解我提供的答案的关键归结为 toISOString() 部分,该部分在使用时会产生 ISO 8601 格式。
9赞 IMSoP 8/19/2022
所以,再一次,我的评论不是关于这是否是一个好的格式,而是关于这个答案的文本中缺少什么。如果有人对这种格式一无所知,并阅读了您的答案,他们仍然不会对这种格式一无所知;他们甚至不知道它的名字。我的问题是提示应该编辑到答案中的信息。
20赞 Chukwuemeka Maduekwe 2/16/2020 #15

“2014-01-01T23:28:56.782Z”

日期以标准且可排序的格式表示,该格式表示 UTC 时间(由 Z 表示)。ISO 8601 还支持时区,将 Z 替换为时区偏移量的 + 或 – 值:

“2014-02-01T09:28:56.321-10:00”

ISO 8601 规范中还有其他时区编码变体,但 –10:00 格式是当前 JSON 解析器支持的唯一 TZ 格式。通常,最好使用基于 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
0赞 Jos de Jong 8/17/2023 #16

JSON 中没有正式的日期格式。但最好的解决方案是使用 ISO 8601 格式,将日期描述为字符串,例如 ."2023-08-17T08:20:28.438Z"