Почему спецификация ISO-8601 выглядит повсеместно игнорируемой, когда речь идет о десятичных знаках?
Из ISO-8601: 2004 (E) Спецификация:
4.2.2.4 Представления с десятичной дроби
При необходимости для конкретного приложения десятичная доля часа, минуты или секунды могут быть включены. Если включена десятичная дробь, время младшего порядка элементы (если таковые имеются) должны быть опущены, а десятичная дробь должна быть разделенный на целую часть на десятичный знак, указанный в ISO 31-0, т.е. Запятая [,] или полная остановка [.]. Из них запятая предпочтительный знак.
Прост достаточно. Таким образом, согласно этой спецификации, доли секунды предпочтительнее записывать с использованием запятой, разделяющей целую и десятичную части, такие как 2014-01-01T00:00:00,123
. Однако кажется, что почти везде принимается только десятичная точка (ака "полная остановка" )
Теперь я уверен, что есть некоторые языки или библиотеки, которые учитывали это, и я знаю, что во многих случаях вы можете предоставить полную информацию о формате самостоятельно. Но это похоже на такой вопиющий контроль над спецификацией, и кажется, что большое количество программистов совершили ту же ошибку. Есть ли причина, почему это так, кроме чистой человеческой ошибки?
Ниже приведен список тех, где я тестировал. Не стесняйтесь редактировать вопрос, чтобы увеличить мой список, если найдете другие. Спасибо.
.NET/С#
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"
. Использование периода вместо этого отлично работает.
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
не сохраняет дробные секунды, это не должно быть ошибкой - и действительно, если используется период, он работает.
Ответы
Ответ 1
Чистый синтаксический анализатор, совместимый с ISO-8601, ДОЛЖЕН поддерживать как запятую, так и точку. Запятая не требуется строго, рекомендуется только. Поэтому в отношении этого стандарта приведенные примеры JavaScript, PHP, Ruby и т.д. Четко указывают на ошибку этих реализаций парсера.
RFC3339 действительно поддерживает только подмножество (исключая запятую AND также исключая десятичные часы или десятичные минуты!) - поэтому не полностью соответствует ISO.
XML-схема похожа. К сожалению, это исключает запятую (см. Документ W3C).
Итак, вы спрашиваете, почему? Это мое подозрение: в мире программирования сильно доминируют США. В американской культуре точка используется как десятичный разделитель в числах. Поэтому большинство людей, разрабатывающих такие рамки, стандарты и библиотеки, сидят в США и ошибочно считают, что точки являются квази-международным стандартом.
Итак, остается вопрос, почему ISO использует/рекомендует запятую? Я точно не знаю, но мы все знаем, что офис группы ИСО находится в Париже, а не в США. А в Европе (исключая Великобританию) запятая обычно предпочтительнее как десятичный разделитель, а также культурный аспект.
Наконец, не все парсеры ошибаются. По крайней мере Joda-Time поддерживает запятую, хотя предпочитает точку в печати. Какова ситуация в NodaTime? Надеюсь, по крайней мере, похоже на Joda-Time. Продолжайте поддерживать разбор запятой. С европейской точки зрения приятно видеть, что не все вещи выглядят как американские; -).
Ответ 2
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