ChatGPT解决这个技术问题 Extra ChatGPT

什么是“正确”的 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 中没有日期格式,只有反序列化器决定映射到日期值的字符串。
stringsnumberstruefalsenullobjectsarrays
然而,JavaScript 内置的 JSON 对象和 ISO8601 包含了人类和计算机可以理解的所有信息,并不依赖于计算机时代的开始(1970-1-1)。

C
Community

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

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

2012-04-23T18:25:43.511Z

原因如下:

它易于阅读,但也简洁 正确排序 它包括小数秒,可以帮助重新建立年表 它符合 ISO 8601 ISO 8601 在国际上已经建立了十多年 ISO 8601 得到 W3C、RFC3339 和 XKCD 的认可

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


这也是根据 ECMA 的首选表示:JSON.stringify({'now': new Date()}) "{"now":"2013-10-21T13:28:06.419Z"}"
我会在列表中添加另一个重要原因:它与语言环境无关。如果您的日期类似于 02-03-2014,则需要更多信息才能知道它是指 2 月 3 日还是 3 月 2 日。这取决于使用的是美国格式还是其他格式。
赞成提及和链接 xkcd :D @ajorquera 我通常为此使用momentjs。在这方面我也看到了 IE 的问题
关于第二点,它在 10000 年后不能正确排序。不过,我们确实有将近 8000 年的时间来提出新的格式,所以这可能不是问题。
实际上,@Erfa,因为 - 出现在 ASCII 中的数字之前,它会一直排序到 100,000 年。 ;P
P
Peter Mortensen

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

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


如果你走这条路,请确保你不需要处理早于 1970 年的日期!
正如@BenDolman 所说,这个“解决方案”不能适当地处理 1970 年 1 月 1 日(纪元)之前的日期。此外,ISO8601 的存在也是有原因的。在地球上,我们有称为“时区”的东西。以毫秒为单位在哪里? JSON 可能没有日期标准,但日期存在于 JSON 之外,并且有 标准。 funroll 的答案是正确的(另见:xkcd.com/1179)。
可能还值得一提的是,从 1970 年开始的(毫秒)秒对于未来的日期是不可预测的,因为我们有 leap seconds。所以我不会使用 if 进行进程间通信和数据存储。然而,在程序内部使用它是很好的,因为它可以存储在一个整数中,这会给你一些性能优势。
Unix 时间戳始终是 UTC,您在生成时间戳之前从本地时区转换,然后再返回到显示的本地时区,那里没有歧义。
这些评论中的每一条都说无法表示 1970 年代之前的日期或未来的日期,这都是对纪元时间的误解。所有时间都是相对的,一旦您到达/低于第 1 年,日期字符串就会真正崩溃。无论您的时间的源时钟是什么,它几乎可以肯定是基于纪元时间的表示,所以您没有成功通过避免纪元时间更准确。
B
Basil Bourque

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

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

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


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

RFC 7493 (The I-JSON Message Format )

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

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


这也是由 Date().toISOString()Date().toJSON() 生成的格式,其限制是 Date 不跟踪时区值,因此始终发出 UTC (Z) 时区的时间戳。可以使用 new Date("...")Date.parseDate 解析该值。
b
bb216b3acfd8f72cbc8f899d4d6963

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

new Date().toISOString()

将输出:

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

达达!!


T
Tel

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

Date.UTC(2017,2,22)

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

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

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

这些日期计数器仅在以分解格式(y、m、d 等)表示时才兼容。它们从不兼容 epoch 格式。记在脑子里。


我不会使用那种格式,但是您提供的其余信息非常有用,谢谢!
A
Aryan

“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

J
Justus Romijn

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

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 on JSON.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...

很好,我喜欢!
A
Alireza

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

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

https://i.stack.imgur.com/HhBOj.png

如您所见,Date 有一个本机方法 toJSON,它是这种格式的 return,并且可以很容易地再次转换为 Date...


正确的! JSON 数据交换语法未指定标准:ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf,但在实践中,跨平台(包括 JavaScript 运行时)更需要 ISO 8601 兼容格式。
i
irundaia

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

yourDate.substring(0,10)

这可能对你有帮助


C
Ciabaros

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

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

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

好处

解析性能:如果您将日期存储为 ISO-8601 字符串,如果您希望在该特定字段下有一个日期值,这很好,但如果您有一个必须在没有上下文的情况下确定值类型的系统,您将解析每个字符串日期格式。无需日期验证:您无需担心日期的验证和验证。即使字符串匹配 ISO-8601 格式,它也可能不是真实的日期; EJSON 日期永远不会发生这种情况。明确类型声明:就通用数据系统而言,如果您想在一种情况下将 ISO 字符串存储为字符串,而在另一种情况下存储实际系统日期,则采用 ISO-8601 字符串格式的通用系统机械地不允许这样做(没有逃脱技巧或类似的可怕解决方案)。

结论

我了解人类可读的格式(ISO-8601 字符串)对于 80% 的用例来说是有帮助且更方便的,而且确实不应该告诉任何人不要将他们的日期存储为 ISO-8601 字符串,如果这是他们的应用程序的话理解,但是对于应该保证某些值肯定是日期的普遍接受的传输格式,我们怎么能允许模棱两可并需要如此多的验证?


请参阅线程前面的此答案,了解为什么自纪元以来的毫秒数有警告,例如闰秒计算不正确等:stackoverflow.com/a/42480073/190476
@SudhanshuMishra 您引用的警告是针对unix时间戳的极端学术问题的一般陷阱,主要与时间戳生成有关。这与毫秒分辨率无关。正如在另一条评论中所指出的,大多数计算机日期在内部都表示为 unix 时间戳,即使它们被公开并以其他方式格式化。尽管如此,任何给定日期+时间的毫秒表示都没有错,特别是与其他方法相比,这很容易受到引擎盖下相同的纳米影响警告的影响。
只是为了增加对 unix 时间戳的“超出范围”日期的担忧:这些是系统存储问题,需要在比传输格式更广泛的范围内解决。例如,这种格式不需要限制为适合 32 位的整数,也不需要是严格的正数,但是没有人会通过在系统/架构级别上删除时间戳来解决“2038 年问题” ;它们只需要扩展(例如到 64 位或更高),这不会影响这个建议的传输格式。
为时已晚。这可能是用于 JSON 的一种很好的格式,但现在大多数系统都使用 ISO8601 或自 epoch 以来的直接时间,其他任何东西都是互操作性的难题。 EJSON 让我想起了这一点:xkcd.com/927 它提供了在 JS 中使用 JSON 的解决方案,但是有很多 JSON 不是使用 JS 处理的。
R
Rosdi Kasim

解析服务器对我有用

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

C
Chad Wilson

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

去掉无关的位,将日期视为 UI 上的数字。您可以使用简单的算术运算符来执行查询和逻辑。


现在你有两个问题:你应该选择哪个时期,你应该计算哪些毫秒?可能最常见的选择是 Unix 时间(1970-01-01T00:00:00 UTC 和 SI 毫秒,闰秒内的除外),但这当然会使未来时间不确定。
那么如何表示微秒呢? RFC3339 在任何精度下都可以正常工作,您将拥有一个解析时区并为您提供正确时间戳的阅读器,它是附加信息。日历应用程序通常关心时区。
时区不是 UI 问题,除非您不介意错过下一个航班。航班以当地时间发布,并遵循 DST 更改的特定规则。失去偏移意味着失去重要的商业信息
一些进一步的反驳包括表示 1970 年之前的时间的能力(假设那个特定的时代),以及 JSON 倾向于在某种程度上是人类可读的。
关于时区注释干草叉:虽然我同意说它是哪个层的关注点(UI,业务逻辑作为数据)是危险的,因为这是特定于应用程序的——存储日期时间的通用方法不应该包括时区,因为你总是可以通过标准的易于理解的方法,得出日期时间的任何时区特定变化。我觉得任何将时区普遍存储到日期中的论点在尝试将 LOCATION 包含到日期时间中时都会被误导,而应该将其存储为单独的独立数据。
P
Phil3992

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

M
Mukus

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

{
"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 时真正需要的功能。这也仅适用于具有相同时区偏移的日期时间。


我怀疑有人会在 10000 年使用 json,甚至到那时 10000 年仍然是 10000 年。但是如果到那时这两件事仍然正确,则可以简单地将格式扩展为包含 3 位数世纪成分。所以我想说人们可以安全地坚持使用 RFC 3339,至少到 9900 年
@downvoters:根据Why is voting important?,如果post contains wrong information, is poorly researched, or fails to communicate information,您应该投反对票。请解释您对这个答案投反对票的原因之一。
@Marten 两件事。 1. 您永远不会因投票而被拒绝解释,尽管我知道这可能会有所帮助。 2. 我没有否决你的答案,但我猜人们不喜欢你的答案,因为他们认为这样做是错误的。这会将其定性为“错误信息”,因为问题是在寻找做某事的最佳方法
我没有对您投反对票,但我当然可以理解“发明另一种指定不明确的格式”(基本上就是您所说的)如何被视为错误或研究不足。
@Phil,UTC 并不是一个真正的时区(地球上没有任何地方使用“UTC”作为其官方时区),它是一个 time standard。时区偏移也非常不可预测。没有办法说 2025 年“莫斯科时间 12:00”是否仍然像今天一样“9:00 UTC”,它一直是 changed a couple of times during the last 30 years。如果你想表达未来的当地时间,你需要真正的时区。