“正确的” JSON日期格式


1137

我已经看到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

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


75
JSON中没有日期格式,只有解串器/序列化器决定要映射到日期值的字符串。

11
stringsnumberstruefalsenullobjectsarrays
拉斯凸轮

12
但是,JavaScript内置的JSON对象ISO8601包含了人类和计算机可以理解的所有信息,并且不依赖于计算机时代的开始(1970-1-1)。
poussma 2013年

Answers:


1847

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

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

2012-04-23T18:25:43.511Z

原因如下:

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

  2. 排序正确

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

  4. 符合ISO 8601

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

  6. W3CRFC3339XKCD认可了ISO 8601

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


32
根据ECMA,这也是首选的表示方式:JSON.stringify({'now': new Date()}) "{"now":"2013-10-21T13:28:06.419Z"}"
史蒂文

11
我将在列表中添加另一个重要原因:它与语言环境无关。如果您有2014年2月3日这样的日期,则需要其他信息才能知道它是指2月3日还是3月2日。这取决于是否使用美国格式或其他格式。
Juanal 2014年

107
提到和链接xkcd的upvote:D @ajorquera我通常为此使用momentjs。在这方面,我也看到了IE的问题
fholzer

54
关于第二点,它不能在10000年之后正确排序。但是,我们确实有将近8000年的时间来提出一种新格式,因此这可能不是问题。
Erfa 2015年

7
实际上,@ Erfa既然排-在数字之前ASCII,它将一直排序到100,000年。; P
Ben Leggiero

128

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

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


3
stackoverflow.com/questions/10286385/…-让我们看看是否有人知道FF为何会这样。
ThiefMaster 2012年

11
如果您选择这条路线,请确保您不需要处理早于1970年的日期!
Ben Dolman

8
正如@BenDolman所说,此“解决方案”不适用于1970年1月1日之前的日期(Epoch)。此外,还有一个原因就是ISO8601首先存在。在地球上,我们有所谓的“时区”。毫秒在哪里?JSON可能没有日期的标准,但日期外存在JSON的,有一个标准这一点。funroll的答案是正确的答案(另请参见:xkcd.com/1179)。
JoeLinux

5
也许还值得一提的是,由于我们有leap秒,所以对于未来的日期来说,1970年的(毫秒)是不可预测的。因此,我不会将if用于进程间的通信和数据存储。但是,最好在程序内部使用它,因为它可以存储在单个整数中,从而为您带来一些性能优势。
布罗迪·加内(Brodie Garnet)2015年

5
Unix时间戳始终是UTC,在生成时间戳之前先从本地时区转换,然后再次返回显示的本地时区,那里没有歧义。
lkraider

46

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

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

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


2
@mlissner,但这是最好的一种看法。ISO-8601是一个标准,但是它不是JSON的标准(即使我倾向于使用它);例如,Microsoft决定不使用它(msdn.microsoft.com/en-us/library/…)。最佳做法是坚持一项(明智的)约定,无论如何。正如我在回答中所述,处理此问题的最佳方法是定义一个可以处理预期格式的日期解析实用程序功能。如果您与使用不同格式的系统集成,则该功能应处理各种情况。
Russ Cam

1
@RussCam,我们可以来回切换,但是如果有人问使用JSON编码日期的最佳方法,他们会问制作JSON时如何格式化日期(答案通常是ISO-8601)。您正在回答相反的问题:一旦完成,如何使用JSON日期(尽管您的建议是合理的)。
mlissner

1
JSON模式规范实际上说,由模式验证的日期必须为8601格式。
gnasher729

3
@ gnasher729您有链接吗?
Russ Cam

@vallismortis-这是用于为双方之间交换的给定json结构定义架构的规范草案,而不是json规范中日期的格式。我将根据评论修改我的答案,似乎我没有说得足够清楚
Russ Cam

27

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

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

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


2
这也是所生产的格式Date().toISOString()Date().toJSON(),与该限制Date不跟踪时区值,并且因此总是发射时间戳在UTC( Z)时区。可以使用new Date("...")和解析值Date.parseDate
索伦Løvborg

15

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

Date.UTC(2017,2,22)

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

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

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

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


4
我不会使用这种格式,但是您提供的其余信息非常有用,谢谢!
罗伯特·麦克斯

9

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

new Date().toISOString()

将输出:

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

-


3

我相信实现通用互操作性的最佳格式不是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字符串理解,但是对于一种普遍接受的传输格式,该格式应保证某些值可以肯定是日期,我们如何允许歧义和需要进行大量验证?


请参阅线程中较早的答案,以了解为什么自历元以来的毫秒数有警告,例如incorrect秒的不正确计算等:stackoverflow.com/a/42480073/190476
Sudhanshu Mishra,

@SudhanshuMishra您参考的注意事项是有关unix时间戳的学术性极为关注的一般陷阱,主要与时间戳的生成有关。对于毫秒分辨率,这一点就更少了。正如另一条评论中所述,大多数计算机日期在内部均以unix时间戳表示,即使以其他方式公开和格式化也是如此。尽管如此,任何给定日期和时间的毫秒表示都没有问题,特别是与其他方法相比时,该方法很容易受到引擎盖下相同的纳米撞击警告的影响。
Ciabaros

只是要添加有关UNIX时间戳“超出范围”日期的担忧:这些是系统存储问题,需要在比传输格式更广泛的范围内解决。例如,此格式不必限于可容纳32位的整数,也不必是严格的正数,但是没人会通过在系统/体系结构级别上添加时间戳来解决“ 2038年问题”。 ; 它们仅需要扩展(例如扩展到64位或更高),并且不会影响此提议的传输格式。
Ciabaros

3

JSON本身没有日期格式,它不在乎任何人如何存储日期。但是,由于此问题是用javascript标记的,因此我假设您想知道如何在JSON中存储javascript日期。您可以只将日期传递给该JSON.stringify方法,Date.prototype.toJSON默认情况下它将使用该方法,而该方法又会使用Date.prototype.toISOStringDate.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.parse上的MDNreviver参数可以在每次读取JSON字符串时自动将ISO字符串转换回javascript日期。JSON.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...


1

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

yourDate.substring(0,10)

这可能对您有帮助


0

“ 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); // 2014年1月1日星期三13:28:56 GMT- 1000(夏威夷标准时间)

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

如果您使用的是Kotlin,则可以解决您的问题。(MS Json格式)

val dataString = "/Date(1586583441106)/"
val date = Date(Long.parseLong(dataString.substring(6, dataString.length - 2)))

-3

它对我来说解析服务器工作

{
    "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"
            }
}

-6

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

去除多余的位,仅将日期视为直到UI的数字。您可以使用简单的算术运算符进行查询和逻辑。



5
现在,您有两个问题:应该选择哪个时期,应该计数哪个毫秒?也许最常见的选择是Unix时间(1970年1月1日T00:00:00 UTC和SI毫秒,除了那些在a秒内的时间),但是当然,这使未来的时间不确定。
2016年

2
那么,您如何表示微秒呢?RFC3339可以在任何精度下正常工作,您将拥有一个读取器来解析时区并为您提供正确的时间戳,以及其他信息。日历应用程序通常关心时区。
gnasher729

11
时区与UI无关,除非您不介意错过下一个航班。航班会以当地时间发布,并遵循DST更改的特定规则。失去补偿意味着失去重要的商业信息
Panagiotis Kanavos

1
一些进一步的反论点包括能够表示1970年之前的时间(假设那个特定纪元),并且JSON趋于让人易读。
2013年

-8

以下代码对我有用。此代码将以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);

-19

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

{
"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解析器将为您完成所有操作
  • 使用任何日期时间框架或任何语言的实现轻松创建
  • 可以轻松扩展以支持其他日历比例(希伯来语,中文,伊斯兰...)和时代(AD,BC,...)
  • 这是10000年安全;-)(不是RFC 3339)
  • 支持全天日期和浮动时间(JavaScript Date.toJSON()不支持)

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


7
我怀疑有人会在10000年使用json,或者甚至到那时10000年仍将是10000年。但是如果到那时这两种情况仍然成立,那么格式可以简单地扩展为包含3位数字世纪组成部分。因此,我想说人们可以放心使用RFC 3339,至少要保留到9900
梦想成真

8
@downvoters:根据为什么投票很重要?如果有,您应该投反对票post contains wrong information, is poorly researched, or fails to communicate information。请说明您否决了此答案的原因之一。
Marten

5
@马丁两件事。1.虽然我知道您会得到帮助,但您永远不会欠他们解释票的理由。2.我没有否决您的答案,但我想人们不喜欢您的答案,因为他们认为这样做是错误的方式。这将其视为“错误的信息”,因为问题正在寻找做某事的最佳方法
Kevin Wells

7
我没有拒绝您的投票,但是我当然可以理解,如何“发明另一种指定不正确的格式”(基本上就是您所说的)会被视为错误或研究不足。
aij 2016年

2
@ Phil,UTC并不是真正的时区(地球上没有任何地方使用“ UTC”作为其官方时区),这是一个时间标准。同样,时区偏移量也是不可预测的。没有办法说,如果2025年的“ 12:00莫斯科时间”仍然像今天一样是“ 9:00 UTC”,那么在过去30年中它已经改变了两次。如果要表示将来的当地时间,则需要真实的时区。
Marten
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.