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

问题描述 投票:1回答:1

你如何从html datepicker正确初始化一个与时区无关的日期(或者我猜一个固定在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>

但至少在我的电脑上,目前坐在美国山区,它会产生错误的日​​期。我今天给它(2019年3月9日),并以下列格式提醒昨天的日期:Fri Mar 08 2019 17:00:00 GMT-0700 (MST)。我该怎么做呢?

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

javascript html date timezone locale
1个回答
1
投票

<input type="date" />元素中,所选日期以区域设置格式显示,但value属性始终以yyyy-mm-dd格式返回,如the MDN docs中所述。

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

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

这是描述in the MDN docs

注意:由于浏览器差异和不一致性,强烈建议不要使用Date构造函数(和Date.parse,它们是等效的)解析日期字符串。对RFC 2822格式字符串的支持仅限于惯例。对ISO 8601格式的支持不同之处在于仅日期字符串(例如“1970-01-01”)被视为UTC,而不是本地字符串。

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

...如果不存在时区偏移,则仅日期表单将被解释为UTC时间,而日期时间表单将被解释为本地时间。

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在午夜(巴西,古巴等)过渡的当地时区中午夜不存在时出错的情况。

那是你最后的评论:

我真的只是想让它假设所有输入和所有输出都是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'}));
}
© www.soinside.com 2019 - 2024. All rights reserved.