JavaScript: какие браузеры поддерживают разбор строки даты ISO-8601 с помощью Date.parse

Мне не удалось проанализировать дату ISO-8601 "2011-04-26T13: 16: 50Z" на IE8 и Safari 5, но она работала на Chrome 10, FF4. Поддержка кажется довольно смешанной?

Кто-нибудь знает о фактическом статусе того, какие браузеры могут анализировать этот формат? Я предполагаю, что IE6, и 7 тоже не сработает.

var d = Date.parse("2011-04-26T13:16:50Z");

Ответ 1

У меня была эта проблема сегодня. Я нашел momentjs - хороший способ разбора дат ISO 8601 в усадьбе перекрестного браузера.

momentjs также может использоваться для вывода даты в другом формате.

Ответ 2

Я говорю, что он подталкивает его только при необходимости через несколько тестов,

вот то, что я уже написал:

(function() {

var d = window.Date,
    regexIso8601 = /^(\d{4}|\+\d{6})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2}):(\d{2})\.(\d{1,3})(?:Z|([\-+])(\d{2}):(\d{2}))?)?)?)?$/;

if (d.parse('2011-11-29T15:52:30.5') !== 1322581950500 ||
    d.parse('2011-11-29T15:52:30.52') !== 1322581950520 ||
    d.parse('2011-11-29T15:52:18.867') !== 1322581938867 ||
    d.parse('2011-11-29T15:52:18.867Z') !== 1322581938867 ||
    d.parse('2011-11-29T15:52:18.867-03:30') !== 1322594538867 ||
    d.parse('2011-11-29') !== 1322524800000 ||
    d.parse('2011-11') !== 1320105600000 ||
    d.parse('2011') !== 1293840000000) {

    d.__parse = d.parse;

    d.parse = function(v) {

        var m = regexIso8601.exec(v);

        if (m) {
            return Date.UTC(
                m[1],
                (m[2] || 1) - 1,
                m[3] || 1,
                m[4] - (m[8] ? m[8] + m[9] : 0) || 0,
                m[5] - (m[8] ? m[8] + m[10] : 0) || 0,
                m[6] || 0,
                ((m[7] || 0) + '00').substr(0, 3)
            );
        }

        return d.__parse.apply(this, arguments);

    };
}

d.__fromString = d.fromString;

d.fromString = function(v) {

    if (!d.__fromString || regexIso8601.test(v)) {
        return new d(d.parse(v));
    }

    return d.__fromString.apply(this, arguments);
};

})();

и в вашем коде всегда используйте Date.fromString(...) вместо new Date(...)

проверьте браузер, чтобы увидеть, будет ли использоваться прокладка:

http://jsbin.com/efivib/1/edit

работает во всех основных браузерах, использует эти ссылки:

http://dev.w3.org/html5/spec/common-microsyntaxes.html

http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15

http://msdn.microsoft.com/en-us/library/windows/apps/ff743760(v=vs.94).aspx

http://msdn.microsoft.com/en-us/library/windows/apps/wz6stk2z(v=vs.94).aspx

http://msdn.microsoft.com/en-us/library/windows/apps/k4w173wk(v=vs.94).aspx

! - для подключения к Microsoft требуется вход в систему для просмотра:

IE9 терпел неудачу в миллисекундах с цифрами, отличными от 3: (исправлено в IE10) https://connect.microsoft.com/IE/feedback/details/723740/date-parse-and-new-date-fail-on-valid-formats

IE10 по-прежнему (по состоянию на 1/17/2013) не работает, когда часовой пояс опущен (согласно ECMA, это должно деформироваться на Z или UTC, а не локально): https://connect.microsoft.com/IE/feedback/details/776783/date-parse-and-new-date-fail-on-valid-formats

. Прочитайте это, если вам небезразлично, где сейчас находится стандарт, и почему я не могу заставить команду IE признать, что их реализация IE10 технически неверна:

ECMAScript-262 v6.0 собирается перейти к чуть более совместимой с iso8601 версии "если индикатор часового пояса опущен, предположим местное время"... так что теперь есть несоответствие, эта реализация, хром, сафари для мобильных устройств и опера все следуют за ECMAScript-262 v5.1, тогда как IE9, firefox, desktop safari все, похоже, следуют более совместимым с iso8601 спецификациям ECMAScript-262 v6.0... это сбивает с толку как минимум. Когда хром или мобильное сафари вытащит триггер и перейдут на реализацию ES6, я думаю, что эта реализация должна пойти на это, оставив ES5.1 в меньшинстве. Я читал, что это указано в "errata" версии 5.1, хотя я его не нашел. Я больше придерживаюсь мнения, что пока рано вставать триггер на ES6, но я также считаю, что код должен быть практичным, а не идеальным и двигаться туда, куда переходят разработчики браузеров. Тем не менее, сейчас это решение составляет 50/50, поэтому ниже представлена ​​ "будущая" версия этого кода...

Я должен также упомянуть, что любая версия кода будет нормализовать "несоответствующие" браузеры, чтобы соответствовать поведению другого, поскольку это то, что делают прокладки;)

ЗДЕСЬ АДАПТИРОВАННАЯ ВЕРСИЯ, СОВМЕСТИМАЯ С ECMAScript-262 v6.0 (JavaScript Future)

см. соответствующие разделы здесь: (это единственная онлайн-версия html спецификации, которую я мог найти) http://people.mozilla.org/~jorendorff/es6-draft.html#sec-15.9.1.15

(function() {

    var d = window.Date,
        regexIso8601 = /^(\d{4}|\+\d{6})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2}):(\d{2})\.(\d{1,})(Z|([\-+])(\d{2}):(\d{2}))?)?)?)?$/,
        lOff, lHrs, lMin;

    if (d.parse('2011-11-29T15:52:30.5') !== 1322599950500 ||
        d.parse('2011-11-29T15:52:30.52') !== 1322599950520 ||
        d.parse('2011-11-29T15:52:18.867') !== 1322599938867 ||
        d.parse('2011-11-29T15:52:18.867Z') !== 1322581938867 ||
        d.parse('2011-11-29T15:52:18.867-03:30') !== 1322594538867 ||
        d.parse('2011-11-29') !== 1322524800000 ||
        d.parse('2011-11') !== 1320105600000 ||
        d.parse('2011') !== 1293840000000) {

        d.__parse = d.parse;

        lOff = -(new Date().getTimezoneOffset());
        lHrs = Math.floor(lOff / 60);
        lMin = lOff % 60;

        d.parse = function(v) {

            var m = regexIso8601.exec(v);

            if (m) {
                return Date.UTC(
                    m[1],
                    (m[2] || 1) - 1,
                    m[3] || 1,
                    m[4] - (m[8] ? m[9] ? m[9] + m[10] : 0 : lHrs) || 0,
                    m[5] - (m[8] ? m[9] ? m[9] + m[11] : 0 : lMin) || 0,
                    m[6] || 0,
                    ((m[7] || 0) + '00').substr(0, 3)
                );
            }

            return d.__parse.apply(this, arguments);

        };
    }

    d.__fromString = d.fromString;

    d.fromString = function(v) {

        if (!d.__fromString || regexIso8601.test(v)) {
            return new d(d.parse(v));
        }

        return d.__fromString.apply(this, arguments);
    };

})();

надеюсь, что это поможет -ck

Ответ 3

Простая функция для анализа формата даты ISO8601 в любом браузере:

function dateFromISO8601(isoDateString) {
  var parts = isoDateString.match(/\d+/g);
  var isoTime = Date.UTC(parts[0], parts[1] - 1, parts[2], parts[3], parts[4], parts[5]);
  var isoDate = new Date(isoTime);

  return isoDate;
}

Ответ 4

Да, Date.parse несовместим для разных браузеров. Вы могли:

  • Используйте Date.UTC вместо этого, который разбивает строку даты на отдельные входы
  • Используйте библиотеку обертки, например jQuery parseDate

Ответ 5

Некоторые старые браузеры возвращают неправильную дату (а не NaN), если вы разбираете строку даты ISO.

Вы можете использовать свой собственный метод во всех браузерах или использовать Date.parse, если он выполнен правильно, проверьте известную временную метку.

Date.fromISO= (function(){
    var diso= Date.parse('2011-04-26T13:16:50Z');
    if(diso=== 1303823810000) return function(s){
        return new Date(Date.parse(s));
    }
    else return function(s){
        var day, tz, 
        rx= /^(\d{4}\-\d\d\-\d\d([tT][\d:\.]*)?)([zZ]|([+\-])(\d\d):(\d\d))?$/, 
        p= rx.exec(s) || [];
        if(p[1]){
            day= p[1].split(/\D/).map(function(itm){
                return parseInt(itm, 10) || 0;
            });
            day[1]-= 1;
            day= new Date(Date.UTC.apply(Date, day));
            if(!day.getDate()) return NaN;
            if(p[5]){
                tz= parseInt(p[5], 10)*60;
                if(p[6]) tz += parseInt(p[6], 10);
                if(p[4]== "+") tz*= -1;
                if(tz) day.setUTCMinutes(day.getUTCMinutes()+ tz);
            }
            return day;
        }
        return NaN;
    }
})()

Ответ 6

Спецификация ES5 отличается от спецификации ISO8601, особенно когда дело касается обработки дат без индикатора/смещения часового пояса. Существует ошибка в https://bugs.ecmascript.org/show_bug.cgi?id=112, описывающая проблему, и похоже, что она будет исправлена ​​в ES6.

В настоящее время я рекомендую посмотреть https://github.com/csnover/js-iso8601 для кросс-браузерной реализации. Я использую https://github.com/csnover/js-iso8601/tree/lax, который не соответствует спецификации ES5, но имеет лучшую совместимость с другими библиотеками сериализации JSON, такими как JSON.NET.

Ответ 7

Как упоминалось ранее, даты стиля стиля ISO 8601 были добавлены в ECMAScript версии 5, где реализация несовместима и недоступна во всех браузерах. Есть номер из script доступных заглушек, но вы можете просто добавить свой собственный метод Date.parse *.

(function() {
  //ISO-8601 Date Matching
  var reIsoDate = /^(\d{4})-(\d{2})-(\d{2})((T)(\d{2}):(\d{2})(:(\d{2})(\.\d*)?)?)?(Z|[+-]00(\:00)?)?$/;
  Date.parseISO = function(val) {
    var m;

    m = typeof val === 'string' && val.match(reIsoDate);
    if (m) return new Date(Date.UTC(+m[1], +m[2] - 1, +m[3], +m[6] || 0, +m[7] || 0, +m[9] || 0, parseInt((+m[10]) * 1000) || 0));

    return null;
  }

  //MS-Ajax Date Matching
  var reMsAjaxDate = /^\\?\/Date\((\-?\d+)\)\\?\/$/;
  Date.parseAjax = function(val) {
    var m;

    m = typeof val === 'string' && val.match(reMsAjaxDate);
    if (m) return new Date(+m[1]);

    return null;
  }
}();

Я использую вышеуказанный метод для JSON.parse гидратации дат...

JSON.parse(text, function(key, val) {
  return Date.parseISO(val) || Date.parseAjax(val) || val;
});

Ответ 8

Я нашел ответ ckozl действительно полезным и интересным, но регулярное выражение не является совершенным, и в моем случае это не сработало.

Помимо того, что даты без минут, сек или milisecs не анализируются, спецификация ISO 8501 говорит, что разделители '-' и ':' не являются обязательными, поэтому "2013-12-27" и "20131227" оба действительный. В моем случае это важно, потому что я устанавливаю дату и время сервера в переменной JavaScript из PHP:

var serverDate = new Date(Date.parse("<?php date(DateTime::ISO8601); ?>"));

Этот код генерирует что-то вроде этого:

<script>
var serverDate = new Date(Date.parse("2013-12-27T15:27:34+0100"));
</script>

Важной частью является указатель часового пояса "+0100", где отсутствует символ ":". Хотя Firefox правильно разбирает эту строку, IE (11) терпит неудачу (если добавлен ":", то IE также работает). Головная боль о времени zonetime и спецификациях ECMAScript, описанных ckozl, в моем случае не имеет значения, поскольку PHP всегда добавляет указатель часового пояса.

RegExp, который я использую, вместо этого из ckozl:

var regexIso8601 = /^(\d{4}|\+\d{6})(?:-?(\d{2})(?:-?(\d{2})(?:T(\d{2})(?::?(\d{2})(?::?(\d{2})(?:(?:\.|,)(\d{1,}))?)?)?(Z|([\-+])(\d{2})(?::?(\d{2}))?)?)?)?)?$/;

Имейте в виду, что это регулярное выражение также не является совершенным. ISO 8501 позволяет спецификацию недели (2007-W01-1 по понедельникам, 1 января 2007 г.) или десятичные дроби в часах и минутах (18,50 за 18:30:00 или 18:30 - 18:30). Но они довольно необычны.

P.D. Этот ответ должен быть, я думаю, комментарием к исходному голосовому ответу, но у меня недостаточно репутации: (

Ответ 9

ISO 8601 форматы даты были добавлены с ECMAScript-262 v5. Поэтому, если браузер не совместим с v5, вы просто не можете ожидать, что сможете обрабатывать форматы ISO 8601.

Браузеры, не совместимые с v5, могут использовать любые форматы дат конкретной реализации, которые они хотят. Большинство из них, по крайней мере, поддерживают RFC822/RFC1123 формат даты. Пример:

var d = Date.parse("Wed, 26 Apr 2011 13:16:50 GMT+0200");

Ответ 10

Microsoft Sharepoint 2013 ТАКЖЕ использует другую нотацию, например "2013-04-30T22: 00: 00Z"

Если вы хотите использовать службы REST из sharepoint 2013 в сочетании с Internet Explorer 8 (IE8), тогда решение ckozl НЕ работает. Вы получите NaN

измените строку регулярных выражений TO:

regexIso8601 = /^(\d{4}|\+\d{6})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2}):(\d{2})(\.(\d{1,3}))?(?:Z|([\-+])(\d{2}):(\d{2}))?)?)?)?$/;

это сделает бит микросекунд дополнительным!

cheerio, Лео