「2016-02-16」が「2016-02-16 00:00」と等しくないのはなぜですか?


96

両方の日付文字列をに渡そうとしていnew Date(t)ます。

結局のところ、両方の文字列が同じ時間を表していると思いますが、結局、時間を省略した場合、その日の真夜中ではないでしょうか。

しかし、

new Date("2016-02-16 00:00")

2016-02-16、午前0時、予想どおり現地時間を返します

new Date("2016-02-16")

2016-02-16のUTCの真夜中を返しますが、これは誤りです。少なくとも、他の文字列が何を解析するかを想定して、私が期待したものとは異なります。

時刻を現地時間として返すのか、UTCとして返すのかに関わらず、両方が同じ振る舞いをするのであれば理解できますが、このように異なるものを返す理由は非常に一貫していないようです。

回避策として、対応するタイムスタンプのない日付に遭遇したときは常に、一貫した動作を得るために「00:00」を追加できますが、これはかなり壊れやすいようです。

「datetime-local」タイプのINPUT要素からこの値を取得しているので、ページ要素から返された値を回避する必要があることは特に矛盾しています。

私は何か間違ったことをしていますか、それとも別のことをしているのですか?


2
2016-02-16 00:00-これは有効な時間のようには見えません。ecma-international.org/ecma-262/6.0/…、ただしTそこに置いた後でも実際には異なる動作をする
zerkms

現在、その値に基づいて、入力要素から日付オブジェクトをどのくらい正確に取得していますか?
BoltClock

4
標準に従って-「HH、mm、またはssフィールドが存在しない場合、値として「00」が使用され、存在しないsssフィールドの値は「000」です。タイムゾーンオフセットが存在しない場合、日時現地時間として解釈されます。」---同じ動作をするはずです。
zerkms 2016

@BoltClockうーん、要素の値フィールドを取得し、(zerkmsが気づいたように)何らかの理由でTを削除しているように見えます( "T"が混乱するコンテキストで値がユーザーに表示されるためと思います)
マイケル

1
@マイケル:素晴らしい。このようなブラウザの癖は私のお気に入りです。(または、それはDOM仕様の奇妙なものでしょうか?わからない、私は実際には見ていません。)
BoltClock

回答:


100

これは、ES5.1仕様で次のように規定されています。

不在の時間帯オフセットの値は「Z」です。

それはまた言います:

この関数は最初に、日付時刻文字列形式(15.9.1.15)で呼び出されたルールに従って文字列の形式を解析しようとします。文字列がその形式に準拠していない場合、関数は実装固有のヒューリスティックまたは実装固有の日付形式にフォールバックする可能性があります。

この形式ではT日付と時刻の間に区切り文字が必要であるため、有効な時刻はUTCになります。

> new Date("2016-02-16T00:00:00")
Tue Feb 16 2016 01:00:00 GMT+0100 (CET)
> new Date("2016-02-16")
Tue Feb 16 2016 01:00:00 GMT+0100 (CET)

... node.jsでは、無効な時間(Tセパレータなし)は実装固有のローカル時間に移動するようです:

> new Date("2016-02-16 00:00:00")
Tue Feb 16 2016 00:00:00 GMT+0100 (CET)

ES6 これを変更したことに注意してください。ドキュメントの同じ部分で次のように変更されています。

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

変化壊す喜び。

編集する

TC39によると、仕様はタイムゾーンのない日付と時刻の文字列(たとえば、「2016-02-16T00:00:00」)はローカル(ISO 8601に準拠)として扱われますが、日付のみの文字列(たとえば"2016-02-16")をUTCとして(これはISO 8601と矛盾します)。


20
確かに、変化を壊す喜び。ES7標準の新しいドラフトでは、UTCから現地時間への変更の一部が元に戻されました。新しい標準では、タイムゾーンが指定されていない場合、日付はUTCとして解釈され、タイムゾーンが指定されていない場合、日時は現地時間として解釈されます。が指定されています。
hichris123 2016

3
日付のみの形式または日付と時刻の形式に関係なく、どちらも実際には現地時間である必要があります。これがISO8601の仕組みです。日付のみの形式がUTCの深夜0時と解釈されるのはおかしいです。ECMA tc39でこれについて白熱した議論がありました。私は現地時間のために戦って、負けました。github.com/tc39/ecma262/issues/87
Matt Johnson-Pint

10

仕様によると:

この関数は最初に、日付時刻文字列形式(15.9.1.15)で呼び出されたルールに従って文字列の形式を解析しようとします。文字列がその形式に準拠していない場合、関数は実装固有のヒューリスティックまたは実装固有の日付形式にフォールバックする可能性があります。

そして、日付時刻文字列の形式は受け入れ2016-02-16、有効な日付として

この形式には、日付のみのフォームが含まれます。

YYYY
YYYY-MM
YYYY-MM-DD

[...] HH、mm、またはssフィールドが存在しない場合、値として「00」が使用され、存在しないsssフィールドの値は「000」です。不在の時間帯オフセットの値は「Z」です。

したがって、に2016-02-16変換され2016-02-16T00:00:00.000Zます。

他の日付2016-02-16 00:00はフォーマットに準拠していないため、その解析は実装固有です。明らかに、そのような日付はローカルタイムゾーンを持つものとして扱われ、サンプルの日付はタイムゾーンに応じて異なる値を返します。

/* tz = +05:00 */ new Date("2016-02-16 00:00").toISOString() // 2016-02-15T19:00:00.000Z
/* tz = -08:00 */ new Date("2016-02-16 00:00").toISOString() // 2016-02-16T08:00:00.000Z

概要:

  • 準拠する日付時刻形式の場合、動作は明確に定義されています。タイムゾーンオフセットがない場合、日付文字列はUTC(ES5)またはローカル(ES6)として扱われます。
  • 非準拠の日付時刻形式の場合、動作は実装固有です。タイムゾーンオフセットがない場合、通常の動作は日付をローカルとして処理することです。
  • 実際のところ、実装は返すように選択することができますNaNの代わりにしようと、非適合日付を解析します。Internet Explorer 11でコードをテストするだけです;)

7

ES5、ES6の実装と期待される結果の違いに直面している可能性があります。MDNでのDate.parseごとに、「特に、「2015-10-12 12:00:00」のような文字列がNaN、UTC、またはローカルタイムゾーンとして解析される可能性があるさまざまなECMAScript実装全体で」重要です。

Firefox 44とIE 11での追加のテストにより、両方がの日付オブジェクトをnew Date("2016-02-16 00:00")返すことがわかりました。このオブジェクトは、日付コンポーネント値を取得しようとするとNaNを返し、そのtoString値は「無効な日付」です(「NaN」ではありません)。したがって、「一貫性のある動作を得るために00:00」を追加すると、異なるブラウザーで簡単に壊れてしまう可能性があります。

他の回答で述べたようにnew Date("2016-02-16")、デフォルトではゼロのタイムゾーンオフセットを使用し、ローカルではなく深夜UTCを生成します。


OPは同じ実装で異なる結果を得るようです。
Salman A

6

DateParser::Parse()ChromeのV8ソースコードごと。

ES5 ISO 8601の日付:

[('-'|'+')yy]yyyy[-MM[-DD]][THH:mm[:ss[.sss]][Z|(+|-)hh:mm]]

「:」が後に続く符号なしの数値は時間値であり、TimeComposerに追加されます。

タイムゾーンがない場合、デフォルトでZになります

> new Date("2016-02-16 00:00")
  Tue Feb 16 2016 00:00:00 GMT+0800 (China Standard Time)

両方の形式(例1970-01-01:)に一致する文字列は、ES5日時文字列として解析されますUTC time-zon。つまり、デフォルトでe になります。ES5仕様に従っている場合、それは避けられません。

> new Date("2016-02-16")
Tue Feb 16 2016 08:00:00 GMT+0800 (China Standard Time)

3

2016-02-16のUTCの真夜中を返しますが、これは誤りです。少なくとも、他の文字列が何を解析するかを想定して、私が期待したものとは異なります。

タイムゾーンのオフセットを 00:00

new Date("2016-02-16") 出力 Tue Feb 16 2016 05:30:00 GMT+0530 (India Standard Time)

私のタイムゾーンはオフセット値(分単位)のIST +330なので、00:00に330分を追加しました。

あたりとしてECMA-262、セクション20.3.3.2 Date.parse(文字列)

ToStringが突然完了した場合、完了レコードがすぐに返されます。それ以外の場合、parseは結果の文字列を日付と時刻として解釈します。日付と時刻に対応するUTC時間値である数値を返します。文字列は、文字列の内容に応じて、現地時間、UTC時間、または他のタイムゾーンの時間として解釈される場合があります。

時間単位を明示的に設定する場合は、new Date("2016-02-16 00:00")set that hoursおよびandを使用しますminutes

それ以外の場合、ここで2 0.3.1.16に記載されています。

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


はい、しかしなぜそれが一方のケースでこれを行うが、他方のケースではしないのですか?
マイケル

@Michaelはい、ecma-international.org section 20.3.3.2
publications

では、なぜこれらが異なる結果になるのでしょうか。基準は同じである必要があると主張しています
zerkms

@zerkms Standardは、時間単位を渡したときに何が行われるかを示し、そうでない場合に何が行われるかを示していません。それはThe String may be interpreted as a local time, a UTC time, or a time in some other time zone, depending on the contents of the String.どこにそれが同じでなければならないと主張しているのか明確に述べていますか?
gurvinder372 2016

@ gurvinder372質問のコメントで引用を提供しました:「HH、mm、またはssフィールドが存在しない場合、値として「00」が使用され、存在しないsssフィールドの値は「000」です。タイムゾーンオフセットの場合がない場合、日時は現地時間として解釈されます。」
zerkms 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.