从 HTML 日期选择器初始化 JS 日期对象:返回不正确的日期

Initialize JS date object from HTML date picker: incorrect date returned

如何从 html 日期选择器正确初始化与时区无关的日期(或者我猜是固定在 html 端和 JS 端的单个时区的日期)?

我有以下简单代码,它生成了不正确的日期:

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>

但至少在我的电脑上,目前位于 U.S。山地时间,它会产生不正确的日期。我给它今天的日期(2019 年 3 月 9 日),它以以下格式提醒昨天的日期:Fri Mar 08 2019 17:00:00 GMT-0700 (MST)。我如何让它不那样做?

我真的只是想让它假设所有输入和所有输出都是 GMT。

<input type="date" /> 元素中,所选日期以语言环境格式显示,但 value 属性 始终以 yyyy-mm-dd 格式返回,如the MDN docs.

换句话说,当您选择2019年3月9日时,您可能会看到来自美国的03/09/2019或世界其他地区的09/03/2019,但value2019-03-09 无论任何时区或本地化设置如何。这是一件好事,因为它允许您以标准 ISO 8601 格式处理所选日期,而无需尝试应用时间。

但是,当您使用 Date 对象的构造函数(或 Date.parse)解析该格式的日期字符串时,您 运行 遇到了一个已知问题:日期是不被视为本地时间,而是作为 UTC。这是 ISO 8601 的相反

这是描述in the MDN docs:

Note: parsing of date strings with the Date constructor (and Date.parse, they are equivalent) is strongly discouraged due to browser differences and inconsistencies. Support for RFC 2822 format strings is by convention only. Support for ISO 8601 formats differs in that date-only strings (e.g. "1970-01-01") are treated as UTC, not local.

也是in the ECMAScript specification(强调我的):

... When the time zone offset is absent, date-only forms are interpreted as a UTC time and date-time forms are interpreted as a local time.

a debate about this in 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 将时间设置为中午而不是午夜。这是可选的,但它避免了在 DST 在午夜转换的本地时区(巴西、古巴等)不存在午夜时得到错误日期的情况。

然后是您最后的评论:

I really just want it to assume that all input and all output are in 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'}));
}