11

この jsfiddle: http://jsfiddle.net/E9gq9/7/を Chrome、FF、および IE で実行すると、次のようになります。

クロム:

クローム http://images.devs-on.net/Image/vBTz86J0f4o8zlL3-Region.png

ファイアフォックス:

Firefox http://images.devs-on.net/Image/aNPxNPUpltyjVpSX-Region.png

いいえ:

IE http://images.devs-on.net/Image/WXLM5Ev1Viq4ecFq-Region.png

サファリ:

サファリ http://images.devs-on.net/Image/AEcyUouX04k2yIPo-Region.png

ISO 8601は、末尾に Z がない文字列をどのように解釈すべきかを述べていないようです。

私たちのサーバー (ASP.NET MVC4) は、データベースから UTC 時刻をDateTimes として取得し、単純に JSON に詰め込んでいます。ご覧のとおり、これが原因でブラウザーで一貫性のない結果が得られます。

サーバー側で Z を追加するだけでよいのでしょうか?

4

5 に答える 5

13

サーバー側でそれらにZを追加する必要がありますか?

TL; DRはい、おそらくそうすべきです。

残念ながら、タイムゾーンなしでの日付と日付/時刻の正しい処理は、仕様とJavaScriptエンジンが仕様に準拠しているという点で、何年にもわたって変化してきました。

この回答が最初に2013年に作成されたとき、ES5仕様(JavaScriptの日付/時刻形式が定義された最初の仕様であり、ISO-8601のサブセットであることが意図されていました)は明確でした。タイムゾーンなし= UTC:

不在のタイムゾーンオフセットの値は「Z」です。

しかし、それはISO-8601とは相容れませんでした。ISO-8601では、タイムゾーンインジケータがないことは「現地時間」を意味します。一部の実装では、ES5の意味を実装せず、代わりにISO-8601に固執していました。

ES2015 (別名「ES6」)では、ISO-8601に一致するように変更されました。

タイムゾーンオフセットがない場合、日時は現地時間として解釈されます。

ただし、これにより、既存のコード、特にのような日付のみのフォームとの非互換性の問題が発生し2018-07-01たため、ES2016ではさらに変更されました。

タイムゾーンオフセットがない場合、日付のみのフォームはUTC時間として解釈され、日時フォームは現地時間として解釈されます。

したがってnew Date("2018-07-01")、UTCとしてnew Date("2018-07-01T00")解析されますが、現地時間として解析されます。

それ以来、ES2017と次のES2018で一貫しています。現在の編集者の下書きへのリンクは次のとおりです。この下書きには、正確なテキストは含まれていませんが、同じ方法で定義されています(ただし、IMHOはあまり明確ではありません)。

ここで現在のブラウザをテストできます。

function test(val, expect) {
  var result = +val === +expect ? "Good" : "ERROR";
  console.log(val.toISOString(), expect.toISOString(), result);
}
test(new Date("2018-07-01"), new Date(Date.UTC(2018, 6, 1)));
test(new Date("2018-07-01T00:00:00"), new Date(2018, 6, 1));

2021年9月現在の状況:

  • Firefox、Chrome、Safariの最新バージョンは、iOSブラウザを含めてこれを正しく実現しています(AppleはJITを実行する場合、独自のJavaScriptエンジンを使用できないため、現在すべてAppleのJavaScriptCore JavaScriptエンジンを使用しています)
  • IE11はそれを正しくします(興味深いことに)

2018年4月現在の状況:

  • IE11はそれを正しくします(興味深いことに)
  • Firefoxはそれを正しく理解します
  • Chrome 65(デスクトップ、Android)で問題ありません
  • Chrome 64(iOS v11.3)が日付/時刻フォームを間違って取得する(UTCとして解析)
  • v11.3のiOSSafariは、日付/時刻の形式が間違っています(UTCとして解析されます)

奇妙なことに、v6.4(Chrome 64のv8)とv6.5(Chrome 65のv8)の間で修正されたv8の問題リストに問題が見つかりません。私はまだ開いているが、修正されたように見えるこの問題を見つけることができるだけです。

于 2013-02-17T17:42:52.903 に答える
6

結局のところ、このアプリで直面している問題は、サーバーが常にすべてのブラウザーが正しく処理する形式でクライアントのDateTimeオブジェクトを送信する場合に修正できます。

これは、最後にその「Z」がなければならないことを意味します。ASP.NET MVC4 JsonシリアライザーはJson.NETに基づいていますが、デフォルトでUtcがオンになっていないことがわかりました。のデフォルトはであるようにDateTimeZoneHandling見えますがRoundtripKind、これは、たとえDateTime.Kind == Utc、が非常に煩わしい場合でも、Zが付いた値を出力しません。

したがって、修正は次のようになります。Json.NETがタイムゾーンを処理する方法を次のように設定しますDateTimeZoneHandling.Utc

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
// Force Utc formatting ('Z' at end). 
json.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;

これで、サーバーからブラウザーに送られるすべてのものがISO-8601としてフォーマットされ、最後に「Z」が付きます。そして、私がテストしたすべてのブラウザは、これで正しいことをします。

于 2013-02-17T23:09:00.957 に答える
2

私はこの問題に遭遇し、少なくとも私のアプリケーションでは、「Z」に変更するよりも日付をローカルタイムゾーンで解釈する方がはるかに理にかなっています。ISO日付に欠落しているローカルタイムゾーン情報を追加するために、この関数を作成しました。これは new Date() の代わりに使用できます。この回答から部分的に派生: How to ISO 8601 format a Date with Timezone Offset in JavaScript?

parseDate = function (/*String*/ d) {
    if (d.search(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/) == 0) {
        var pad = function (num) {
            norm = Math.abs(Math.floor(num));
            return (norm < 10 ? '0' : '') + norm;
        },
        tzo = -(new Date(d)).getTimezoneOffset(),
        sign = tzo >= 0 ? '+' : '-';
        return new Date(d + sign + pad(tzo / 60) + ':' + pad(tzo % 60));
    } else {
        return new Date(d);
    }
}
于 2013-10-03T16:15:23.493 に答える