Почему спецификация 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" . Использование периода работает отлично.

JavaScript с помощью функции moment.js

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

Возвращает false . Использование периода вместо этого возвращает true .

PHP

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

Возвращает пустую строку. Использование периода работает отлично.

Рубин

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

Дает ошибку времени выполнения. Хотя Time не сохраняет дробные секунды, это не должно быть ошибкой – и действительно, если период используется вместо этого, он работает.

Чистый ISO-8601-совместимый анализатор ДОЛЖЕН поддерживать как запятую, так и точку. Запятая не требуется строго, рекомендуется только. Поэтому в отношении этого стандарта приведенные примеры JavaScript, PHP, Ruby и т. Д. Четко указывают на ошибку этих реализаций парсера.

RFC3339 действительно поддерживает только подмножество (исключая запятую И также исключая десятичные часы или десятичные минуты!) – поэтому не полностью соответствует ISO.

XML-схема похожа. К сожалению, он не содержит запятую (см. Документ W3C).

Итак, вы спрашиваете, почему? Это мое подозрение: в мире программирования сильно доминируют США. В американской культуре точка используется как десятичный разделитель в числах. Поэтому большинство людей, разрабатывающих такие рамки, стандарты и библиотеки, сидят в США и ошибочно считают, что точки являются квази-международным стандартом.

Поэтому остается вопрос, почему 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