JavaScript: Какие браузеры поддерживают анализ строки даты ISO-8601 с Date.parse - PullRequest
48 голосов
/ 27 апреля 2011

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

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

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

Ответы [ 10 ]

31 голосов
/ 20 февраля 2012

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

вот тот, который я уже написал:

(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 / # втор-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 по-прежнему (по состоянию на 17.01.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 версию «если индикатор часового пояса опущен, предположить местное время» ... так что теперь есть расхождение, эта реализация, chrome, мобильное сафари и Opera все следуют ECMAScript-262 v5.1, в то время как IE10, firefox, десктопное сафари все, похоже, следуют более совместимой со стандартом ISO601 ECMAScript-262 v6.0 спецификации ... это, по меньшей мере, запутанно Когда chrome или мобильное сафари нажимают на триггер и переходят к реализации ES6, я думаю, что эта реализация должна идти с ним, оставляя ES5.1 в меньшинстве. Я читал, что это перечислено в "опечатках" версии 5.1, хотя я не нашел это. Я придерживаюсь мнения, что пока еще рано нажимать на ES6, но я также придерживаюсь мнения, что код должен быть практичным, а не идеальным и двигаться туда, куда переходят создатели браузера. Тем не менее, сейчас кажется, что решение 50/50, поэтому ниже приведена «будущая» версия этого кода ...

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

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

см. Соответствующие разделы здесь: (это единственная онлайн-версия спецификации, которую я смог найти) 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

18 голосов
/ 26 ноября 2013

Простая функция для разбора формата даты 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;
}
17 голосов
/ 17 октября 2012

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

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

6 голосов
/ 27 апреля 2011

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

  • Вместо этого используйте Date.UTC , что разбивает строку даты на отдельные входные данные
  • Используйте библиотеку-оболочку, например jQuery's parseDate
4 голосов
/ 25 мая 2012

Спецификация 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.

4 голосов
/ 27 апреля 2011

Некоторые старые браузеры возвращают неправильную дату (а не 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;
    }
})()
2 голосов
/ 27 декабря 2013

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

Помимо того, что даты без минут, секунд или миллисекунд не анализируются, спецификация 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 также работает). Головная боль, связанная с поясным временем и спецификациями 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.25 для 18:30:15). Но они довольно необычные.

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

2 голосов
/ 14 февраля 2012

Как упоминалось ранее, даты стиля ISO 8601 были добавлены в ECMAScript версии 5, где реализация не согласована и доступна не во всех браузерах.Доступно число из скриптовых заглушек, но вы можете просто добавить свой собственный метод 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;
});
1 голос
/ 27 апреля 2011

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

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

var d = Date.parse("Wed, 26 Apr 2011 13:16:50 GMT+0200");
0 голосов
/ 03 июня 2013

Microsoft Sharepoint 2013 также используется с другой нотацией, например, «2013-04-30T22: 00: 00Z»

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

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

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

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

привет, Лев

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...