Инициализация объекта даты JS из средства выбора даты HTML: неверная дата возврата - PullRequest
1 голос
/ 10 марта 2019

Как правильно инициализировать независимую от часового пояса дату (или, я полагаю, дату, которая привязана к одному часовому поясу на стороне html и на стороне JS) из средства выбора даты html?

У меня есть следующеепростой код, который выдает неправильные даты:

function printDate(){
	let d = new Date(document.getElementById("date").value)
	alert(d)
}

document.getElementById("printDate").addEventListener("click", e => printDate())
<html>
<body>
Print Date: <br><input type="date" id="date"> <button id="printDate">Add</button>
</body>
</html>

Но, по крайней мере, на моем компьютере, который сейчас находится в горах США, он выдает неверные даты.Я даю ему сегодняшнюю дату (9 марта 2019 года), и он оповещает о вчерашней дате в следующем формате: Fri Mar 08 2019 17:00:00 GMT-0700 (MST).Как я могу заставить это не делать это?

Я просто хочу предположить, что все входные и выходные данные представлены в GMT.

1 Ответ

1 голос
/ 11 марта 2019

В элементе <input type="date" /> выбранная дата отображается в формате локали, но свойство value всегда возвращается в формате yyyy-mm-dd, как описано в документах MDN .

Другими словами, если вы выберете 9 марта 2019 года, вы можете увидеть 03/09/2019 из США или 09/03/2019 в других частях света, но value означает 2019-03-09 независимо от часового пояса илиНастройки локализации.Это хорошо, поскольку позволяет работать с выбранной датой в стандартном формате ISO 8601, не пытаясь применить время.

Однако, когда вы анализируете строку даты в этом формате с помощью Date конструктор объекта (или с Date.parse), вы столкнулись с известной проблемой: дата не обрабатывается как местное время, а как UTC.Это напротив ISO 8601.

Это описано в документах MDN :

Примечание: анализ строк даты с помощью конструктора Date (и Date.parse, они эквивалентны) настоятельно не рекомендуется из-за различий и несоответствий в браузере.Поддержка строк формата RFC 2822 предоставляется только по соглашению.Поддержка форматов ISO 8601 отличается тем, что строки только с датой (например, «1970-01-01») обрабатываются как UTC, а не как локальные.

Это также в спецификации ECMAScript (выделено мной):

... Когда смещение часового пояса отсутствует, формы только для даты интерпретируются как время UTC , а формы даты и времени интерпретируются какпо местному времени.

В 2015 году велись споры об этом , но в конечном итоге было решено, что поддержание совместимости с существующим поведением важнее, чем совместимость с ISO 8601.

Возвращаясь к вашему вопросу, лучше всего было бы , а не разобрать его в Date объект, если он вам не нужен.Другими словами:

function printDate(){
    const d = document.getElementById("date").value;
    alert(d);
}

Если вам действительно нужен объект Date, то самый простой вариант - проанализировать значение самостоятельно:

function printDate(){
    const parts = document.getElementById("date").value.split('-');
    const d = new Date(+parts[0], parts[1]-1, +parts[2], 12);
    alert(d);
}

Обратите внимание на ,12 вend устанавливает время до полудня вместо полуночи.Это необязательно, но позволяет избежать ситуаций неправильного дня, когда полночь не существует в местном часовом поясе, где DST переходит в полночь (Бразилия, Куба и т. Д.).

Тогда есть ваш последний комментарий:

Я просто хочу предположить, что все входные и выходные данные находятся в GMT.

Это немного отличается от того, что вы показали.Если это действительно то, что вам нужно, тогда вы можете сконструировать объект Date, как вы это делали ранее, и использовать .toISOString(), .toGMTString() или .toLocaleString(undefined, {timeZone: 'UTC'})

function printDate(){
    const d = new Date(document.getElementById("date").value); // will treat input as UTC

    // will output as UTC in ISO 8601 format
    alert(d.toISOString());

    // will output as UTC in an implementation dependent format
    alert(d.toGMTString());

    // will output as UTC in a locale specific format
    alert(d.toLocaleString(undefined, {timeZone: 'UTC'}));
}
...