什么是“正确的”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

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

1643329 次浏览

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

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

JSON规范没有指定交换日期的格式,这就是为什么有这么多不同的方法。

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

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

JSON本身不要指定如何表示日期,但JavaScript可以。

应该使用#0#1方法发出的格式:

2012-04-23T18:25:43.511Z

原因如下:

  1. 它既可读又简洁

  2. 正确排序

  3. 它包括小数秒,可以帮助重新建立年表

  4. 符合ISO8601

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

  6. ISO 8601被W3CRFC3339XKCD认可

话虽如此,曾经编写的每个日期库都可以理解“自1970年以来的毫秒”。所以为了便于移植,ThiefMaster是对的。

RFC 7493(I-JSON消息格式)

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

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

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

去掉多余的位,只将日期视为用户界面上的数字。您可以使用简单的算术运算符来执行查询和逻辑。

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

{"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()不支持)

我不认为正确的排序(正如funroll在RFC 3339中所指出的)是将日期序列化为JSON时真正需要的功能。

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

yourDate.substring(0,10)

这可能对你有帮助

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

Date.UTC(2017,2,22)

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

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

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

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

这是我的工作与解析服务器

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

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

最好的方法是使用2018-04-23T18:25:43.511Z

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

JSON Date

因此,正如您所看到的,Date有一个本机方法toJSON,其中return为这种格式,并且可以轻松地再次转换为Date

我相信通用互操作性的最佳格式不是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字符串,对于普遍接受的传输格式,它应该保证某些值肯定是日期,我们怎么能允许歧义和需要这么多验证?

JSON本身没有日期格式,它不在乎任何人如何存储日期。然而,由于这个问题用javascript标记,我假设你想知道如何在JSON中存储javascript日期。你可以将日期传入JSON.stringify方法,它将默认使用Date.prototype.toJSON,反过来使用Date.prototype.toISOStringDate.toJSON):

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

我还发现,每当我读取JSON字符串时,使用JSON.parseMDNJSON.parse)的reviver参数自动将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...

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

new Date().toISOString()

将输出:

"2019-07-04 T 13:33:03.969 Z"

Ta-da!!

"2014-01-01 T 23:28:56.782 Z"

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

"2014-02-01 T 09:28:56.321-10:00"

ISO 8601规范中的时区编码还有其他变体,但是-10:00格式是当前JSON解析器支持的唯一TZ格式。通常,最好使用基于UTC的格式(Z),除非您有特定的需求来确定生成日期的时区(仅在服务器端生成中可能)。

NB:

    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 datevar json = "\"2014-01-01T23:28:56.782Z\"";
var dateStr = JSON.parse(json);console.log(dateStr); // 2014-01-01T23:28:56.782Z