【问题标题】:Initialize JS date object from HTML date picker: incorrect date returned从 HTML 日期选择器初始化 JS 日期对象:返回的日期不正确
【发布时间】:2019-03-10 00:20:56
【问题描述】:

如何从 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>

但至少在我目前处于美国山区时间的计算机上,它产生的日期不正确。我给它今天的日期(2019 年 3 月 9 日),它会以以下格式提醒昨天的日期:Fri Mar 08 2019 17:00:00 GMT-0700 (MST)。我怎样才能让它不那样做?

我真的只是希望它假设所有输入和所有输出都在 GMT 中。

【问题讨论】:

    标签: javascript html date timezone locale


    【解决方案1】:

    &lt;input type="date" /&gt; 元素中,所选日期以区域设置格式显示,但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'}));
    }
    

    【讨论】:

    • 天哪。我并没有完全理解这个答案,所以我做了一些实验,这种行为只发生在这种被解析为字符串的日期的特定格式中。所以let d = new Date("03/09/2019");alert(d) 产生正确的独立于时区的输出,但“2019-03-09”没有。谢谢,还有,GARGH JAVASCRIPT WHY??!!
    • 好吧,我想不是在独立于时区的意义上是正确的,而是从某种意义上说,输入是与输出相同的时区......这似乎是一个非常低的最小值。叹息。
    • 并非如此。不能真正警告或直接记录Date 对象,只有一些字符串表示。当你这样做时,实现不是由规范定义的。有些会隐式调用toString(给出当地时间),但有些实现会隐式调用toISOString(给出UTC)。
    • 另外,我会避免传递像"03/09/2019" 这样的本地特定格式,因为它的解释会因语言环境而异。 3 月 9 日对 9 月 3 日。此外,规范并没有对这种格式提供任何要求,因此实现可能会有所不同。
    • 至于“为什么”——我感觉到你的痛苦。请参阅this 了解它的起点。
    猜你喜欢
    • 2017-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多