【问题标题】:Why new Date().toISOString() is loosing timezone?为什么 new Date().toISOString() 正在失去时区?
【发布时间】:2017-11-27 18:10:47
【问题描述】:

我不想使用像 momentjs 这样的任何外部库,我想自己创建一个格式化的日期字符串。我尝试使用new Date().toISOString(),但它正在失去时区。

这个:

new Date()

给予:

Sat Jun 24 2017 09:32:10 GMT+0300 (RTZ 2 (winter))

还有:

new Date().toISOString();

给予:

2017-06-24T06:32:22.990Z

09:32:10 是正确的时间,所以06:32:22 丢失了时区信息。

此外,看起来new Date().toLocaleString() 几乎可以满足我的需要。最后几个小时是正确的。结果:"24.06.2017, 11:37:05"

【问题讨论】:

标签: javascript date-formatting


【解决方案1】:

来自类似question的回答

moment.js 很棒,但有时您不想为简单的事情提取大量依赖项。

以下也可以:

var tzoffset = (new Date()).getTimezoneOffset() * 60000; //以毫秒为单位的偏移量 var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0,-1); // => '2015-01-26T06:40:36.181'

slice(0,-1) 去掉了代表祖鲁时区的尾随 Z,可以用你自己的替换。

【讨论】:

  • 我发现恕我直言更好的解决方案。查看我的问题更新。
【解决方案2】:

在更新后的问题中,您建议使用 toLocaleString(),是的,这会将日期转换为用户当前的语言环境(与始终使用 GMT 的 toISOString 相比),但是您丢失了 ISO 8601 格式。

我使用的解决方案是将语言环境设置为使用 8601 的国家/地区,例如。

const d = new Date();
const dateStr = d.toLocaleString( 'sv' );
// locale 'sv' is Sweden so you get ISO 8601 format

结果将有一个空格而不是“T”,但这在RFC 3339 中是合法的。

[编辑:澄清是 RFC 3339 允许空间,根据 T.J.群众评论。]

【讨论】:

  • “结果将有一个空格而不是 'T',但这在标准中是合法的。” It isn't,实际上(也不是 ISO-8601,虽然这是一个常见的扩展)。如果那里有空格,则无法确定 JavaScript 引擎在解析时会做什么。
【解决方案3】:

JavaScript Date 对象不存储时区信息。他们使用系统时区,仅此而已。所以一旦你有了Date,你就丢失了时区信息(除了当前系统的时区)。

Date,您可以获得当前时区偏移量,并且您可以使用该时区偏移量形成 ISO-8601 格式的字符串:

function pad(x, width = 2, char = "0") {
    return String(x).padStart(width, char);
}
function toLocalISOString(dt) {
    const offset = dt.getTimezoneOffset();
    const absOffset = Math.abs(offset);
    const offHours = Math.floor(absOffset / 60);
    const offStr = pad(offHours) + ":" + pad(absOffset - offHours * 60);
    return [
        String(dt.getFullYear()),
        "-",
        pad(dt.getMonth() + 1),
        "-",
        pad(dt.getDate()),
        "T",
        pad(dt.getHours()),
        ":",
        pad(dt.getMinutes()),
        ":",
        pad(dt.getSeconds()),
        ".",
        dt.getMilliseconds(),
        offset <= 0 ? "+" : "-",
        offStr
    ].join("");
}
console.log(toLocalISOString(new Date()));

...但是偏移量不是时区;偏移量仅告诉您日期/时间与 UTC 的偏移量是多少小时和分钟,而不是 规则 管理它。

在任何现代浏览器(不是 IE11)中,您都可以从 Intl.DateTimeFormat().resolvedOptions().timeZone 获取实际时区,这将为您提供类似 "Europe/London" 的 IANA 字符串。您可以将其包含在您的自定义字符串中,可能有条件地基于能够获取它:

function pad(x, width = 2, char = "0") {
    return String(x).padStart(width, char);
}
function toLocalISOString(dt) {
    const offset = dt.getTimezoneOffset();
    const absOffset = Math.abs(offset);
    const offHours = Math.floor(absOffset / 60);
    const offStr = pad(offHours) + ":" + pad(absOffset - offHours * 60);
    let parts = [
        String(dt.getFullYear()),
        "-",
        pad(dt.getMonth() + 1),
        "-",
        pad(dt.getDate()),
        "T",
        pad(dt.getHours()),
        ":",
        pad(dt.getMinutes()),
        ":",
        pad(dt.getSeconds()),
        ".",
        dt.getMilliseconds(),
        offset <= 0 ? "+" : "-",
        offStr
    ];
    if (typeof Intl === "object" && Intl.DateTimeFormat) {
        try {
            parts.push(
                " (",
                Intl.DateTimeFormat().resolvedOptions().timeZone,
                ")"
            );
        } catch (e) {
        }
    }
    return parts.join("");
}
console.log(toLocalISOString(new Date()));

【讨论】:

    猜你喜欢
    • 2017-06-18
    • 2014-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-03
    • 2019-06-28
    • 1970-01-01
    相关资源
    最近更新 更多