为什么ISO-8601规范在小数时似乎被普遍忽略?

根据ISO-8601:2004(E)规范:

4.2.2.4带小数部分的表示法

如果特定应用需要,可以包括小时,分钟或秒的小数部分。 如果包含小数部分,则应省略低阶时间元素(如果有),小数部分应从整数部分除以ISO 31-0中指定的小数符号,即逗号[,]或句号[ ]。 其中,逗号是首选标志。

很简单。 因此,根据此规范,优选使用分隔整个和小数部分的逗号来编写分数秒,例如2014-01-01T00:00:00,123 。 然而,似乎几乎无处不在,只接受小数点(又名“完全停止”)!

现在我确定有一些语言或库将这一点考虑在内,我知道在很多情况下你可以自己提供格式的完整细节。 但这似乎是对规范的明显监督,似乎各种程序员都犯了同样的错误。 除了纯粹的人为错误之外,是否存在这种情况的原因?

以下是我测试的地方列表。 如果您找到其他人,请随意编辑问题以扩充我的列表。 谢谢。

.NET / C#

 DateTime dt = DateTime.Parse("2014-01-01T00:00:00,123"); 

抛出FormatException ,并显示消息“String未被识别为有效的DateTime”。 使用句点而不是逗号进行成功解析。

JavaScript日期对象

最新(在撰写本文时)Chrome,Internet Explorer,Firefox和Node.js进行了测试:

 var dt = new Date('2014-01-01T00:00:00,123'); 

返回"Invalid Date" 。 使用句号代替工作正常。

带有moment.js的 JavaScript

 var valid = moment("2014-01-01T00:00:00,123").isValid(); 

返回false 。 使用句点代替返回true

PHP

 echo strtotime('2014-01-01T00:00:00,123'); 

返回一个空字符串。 使用句号代替工作正常。

ruby

 require 'time' puts Time.iso8601("2014-01-01T00:00:00,123") 

给出运行时错误。 虽然Time不保持小数秒,但它不应该是错误 – 事实上如果使用句号,它就可以工作。

纯ISO-8601兼容解析器必须支持逗号和点。 逗号并非严格要求,仅建议使用。 所以关于这个标准,JavaScript,PHP,Ruby等的给定示例清楚地表明了那些解析器实现的错误。

RFC3339确实只支持一个子集(不包括逗号,也不包括十进制小时或小数分钟!) – 因此不完全符合ISO标准。

XML模式类似。 不幸的是,它排除了逗号(参见W3C文档)。

所以你问为什么? 这是我的怀疑:编程世界受到美国的强烈支配。 在美国文化中,点在数字中用作小数分隔符。 因此,大多数开发此类框架,标准和库的人都坐在美国,错误地认为点是准国际标准。

所以问题仍然存在,为什么ISO使用/推荐使用逗号? 我完全不知道,但我们都知道ISO集团的办公室位于巴黎,而不是美国。 在欧洲(英国除外),逗号通常是小数分隔符,也是文化方面。

最后,并非所有解析器都是错误的。 至少Joda-Time也支持逗号,虽然在打印时更喜欢点。 NodaTime的情况如何? 我希望至少与Joda-Time类似。 请继续支持解析逗号。 从欧洲的角度来看,很高兴看到并非所有东西看起来像美国人;-)。

RFC3339 ,由IETF定义,仅指定. 作为分隔符。

这是第5.6节:

 5.6. Internet Date/Time Format The following profile of ISO 8601 [ISO8601] dates SHOULD be used in new protocols on the Internet. This is specified using the syntax description notation defined in [ABNF]. date-fullyear = 4DIGIT date-month = 2DIGIT ; 01-12 date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on ; month/year time-hour = 2DIGIT ; 00-23 time-minute = 2DIGIT ; 00-59 time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second ; rules time-secfrac = "." 1*DIGIT time-numoffset = ("+" / "-") time-hour ":" time-minute time-offset = "Z" / time-numoffset partial-time = time-hour ":" time-minute ":" time-second [time-secfrac] full-date = date-fullyear "-" date-month "-" date-mday full-time = partial-time time-offset date-time = full-date "T" full-time