你如何从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。
在<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'}));
}