web-dev-qa-db-ja.com

JavaScript:Date.parseを使用したISO-8601日付文字列の解析をサポートするブラウザー

IE8およびSafari 5でISO-8601の日付「2011-04-26T13:16:50Z」を解析できませんでしたが、Chrome 10、FF4で動作しました。サポートはかなり混ざっているようです。 ?

どのブラウザがこの形式を解析できるかについて、実際のステータスを知っている人はいますか? IE6と7も失敗すると思います。

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

今日はこの問題がありました。 momentjs は、クロスブラウザマナーでISO 8601日付を解析する良い方法であることがわかりました。

momentjsを使用して、異なる形式で日付を出力することもできます。

17
asgeo1

いくつかのテストで必要な場合にのみシムと言います。

ここに私がすでに書いたものがあります:

_(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 Connectを表示するには、ログインが必要です。

IE9は3以外の桁数でミリ秒単位で失敗していました(IE10で修正済み) https://connect.Microsoft.com/IE/feedback/details/723740/date-parse-and-new-date-fail -on-valid-formats

IE10は、タイムゾーンが省略された場合(ECMAによれば、ローカルではなくZまたはUTCにデファルトする必要があります)、まだ(2013年1月17日現在)失敗しています: https://connect.Microsoft.com/ IE/feedback/details/776783/date-parse-and-new-date-fail-on-valid-formats

-標準が現在どこにあるのか、将来どこに行くのか、そしてIEチームがIE10の実装が技術的に正しくありません:

ECMAScript-262 v6.0は、「タイムゾーンインジケータが省略されている場合、現地時間を想定する」のiso8601準拠バージョンに少し移行する予定です。したがって、矛盾、この実装、クロム、モバイルサファリ、operaはすべてECMAScript-262 v5.1に準拠していますが、IE10、firefox、デスクトップサファリはすべてiso8601準拠のECMAScript-262 v6.0仕様に準拠しているようです。これは控えめに言ってもわかりにくいです。 chromeまたはモバイルサファリがトリガーを引いてES6実装に移行するとき、この実装はES5.1を少数のままにしていくべきだと思います。これはバージョン5.1の「正誤表」に記載されていますが、見つかりませんでした。私はまだES6でトリガーを引くのは少し早いという意見の方が多いですが、コードは実用的で理想的ではなく、ブラウザメーカーが移動する場所に移動する必要があるという意見もあります。とはいえ、現時点では50/50の決定であるように思われるため、以下にこのコードの「将来」バージョンを示します。

また、どちらのバージョンのコードも、「非準拠」ブラウザーを正規化して、他のブラウザーの動作に一致させることを言及する必要があります。

ここIS 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);
    };

})();
_

これが役に立つことを願って

32
ckozl

任意のブラウザーで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;
}
18

はい、Date.parseは異なるブラウザに対して一貫性がありません。あなたは出来る:

  • 代わりに Date.UTC を使用します。これは、日付文字列を個別の入力に分割します
  • jQueryのparseDate のようなラッパーライブラリを使用する
6
Vik David

一部の古いブラウザは、ISO日付文字列を解析するとwrong date(NaNではなく)を返します。

すべてのブラウザで独自のメソッドを使用できます。または、正しく実装されている場合は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;
    }
})()
4
kennebec

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.NETなどの他のJSONシリアル化ライブラリとの相互運用性が向上しています。

4
Will Holley

前述のように、ISO 8601スタイルの日付がECMAScriptバージョン5に追加されました。このバージョンでは、実装に一貫性がなく、すべてのブラウザーで利用できるわけではありません。 numberof が利用可能なスクリプトスタブがありますが、独自の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;
});
2
Tracker1

Ckozlの回答は本当に便利で面白いと思いましたが、正規表現は完璧ではなく、私の場合はうまくいきませんでした。

分、秒、ミリ秒のない日付は解析されないという事実とは別に、ISO 8501仕様では、「-」と「:」の区切り文字はオプションであるため、「2013-12-27」と「20131227」は両方とも有効です。私の場合、PHPのJavaScript変数でサーバーの日付と時刻を設定しているため、これは重要です。

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も機能します)。ゾーンタイムに関する頭痛の種また、PHPは常にタイムゾーン指定子を追加するため、ckozlで記述されているECMAScript仕様は重要ではありません。

私が使用している正規表現は、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年1月1日、月曜日の2007-W01-1)、または時間と分での小数部(18:30:00の場合は18.50、18:30:15の場合は18:30.25)が許可されます。しかし、それらは非常に珍しいです。

P.D.この答えは、元のchozlの答えに対するコメントであるはずですが、評判が十分ではありません:(

2
Googol

ISO 8601 日付形式は ECMAScript-262 v5で追加されました。そのため、ブラウザがv5互換でない場合、単にexpectISO 8601形式を処理できません。

V5と互換性のないブラウザは、実装固有の日付形式を使用できます。ただし、それらのほとんどは、少なくとも RFC822 / RFC112 日付形式をサポートしています。例:

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

Microsoft Sharepoint 2013は、「2013-04-30T22:00:00Z」などの異なる表記を使用しています

Sharepoint 2013のRESTサービスを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}))?)?)?)?$/;

これにより、マイクロ秒ビットがオプションになります!

チェリオ、レオ

0
leo