【问题标题】:Javascript: parse a string to Date as LOCAL time zoneJavascript:将字符串解析为日期作为本地时区
【发布时间】:2016-02-27 18:12:13
【问题描述】:

我有一个代表当前时间的字符串:2015-11-24T19:40:00。如何在 Javascript 中解析该字符串以获取由该字符串表示为 LOCAL TIME 的日期? 由于某些限制,我不能使用库moment,但允许使用jquery。我知道以前有人问过这个问题,但答案用moment

例如,如果我在加利福尼亚运行脚本,那么这个字符串代表太平洋时间晚上 7 点,但如果我在纽约运行脚本,那么这个字符串代表东部时间?

我尝试了以下方法,但 Chrome 和 Firefox 给出了不同的结果:

var str = "2015-11-24T19:40:00";
var date = new Date(str);

Chrome 将其作为 UTC 时间 (Tue Nov 24 2015 11:40:00 GMT-0800 (Pacific Standard Time)) 使用,

但 Firefox 将它作为我的本地 PACIFIC 时间使用 (Tue Nov 24 2015 19:40:00 GMT-0800 (Pacific Standard Time))

我尝试将“Z”添加到str,就像var date = new Date(str+"Z");,然后两个浏览器都给我UTC时间。是否有任何与"Z" 类似的字母告诉所有浏览器(至少 chrome、Firefox 和 Safari)将字符串解析为本地时区?

【问题讨论】:

    标签: javascript date timestamp


    【解决方案1】:

    强烈建议不要使用 Date 构造函数或 Date.parse(本质上是相同的东西)解析日期字符串。

    如果 Date 作为函数被调用并传递了一个没有时区的 ISO 8601 格式的日期字符串(例如 2015-11-24T19:40:00),您可能会得到以下结果之一:

    1. ES5 之前的实现可以将其视为任何东西,甚至是 NaN(例如 IE 8)
    2. 符合 ES5 的实现会将其视为 UTC 时区
    3. 符合 ECMAScript 2015 的实现会将其视为本地(与 ISO 8601 一致)

    Date 对象有一个 UTC 时间值和一个基于系统设置的偏移量。当您将 Date 发送到输出时,您看到的通常是 Date.prototype.toString 的结果,它是一个依赖于实现的、人类可读的字符串,表示日期和时间,通常位于基于系统设置。

    解析日期字符串的最佳方法是手动进行。如果您确信格式一致且有效,那么将 ISO 格式字符串解析为本地日期就很简单:

    /*  @param {string} s - an ISO 8001 format date and time string
    **                      with all components, e.g. 2015-11-24T19:40:00
    **  @returns {Date} - Date instance from parsing the string. May be NaN.
    */
    function parseISOLocal(s) {
      var b = s.split(/\D/);
      return new Date(b[0], b[1]-1, b[2], b[3], b[4], b[5]);
    }
    
    document.write(parseISOLocal('2015-11-24T19:40:00'));

    请注意,使用 Date.parse 解析 ISO 字符串仅接受 UTC,它不接受任何其他时区指定(如果缺少上述行为,请注意上述行为)。

    【讨论】:

    • 作为一个附带问题,new Date() 是否总是返回本地当前时间?如果没有,我怎样才能得到当前的当地时间?至少对我来说,它适用于 Chrome 和 Firefox。基本上,我需要获取当前时间和字符串表示的给定时间之间的差异(以秒为单位),例如"2015-11-24T19:40:00"
    • 如上,new Date() 返回一个 Date 对象,其时间值设置为当前 UTC 时间和基于系统设置的偏移量。如何呈现由称为的方法确定:toStringtoISOStringtoUTCStringtoLocaleTimeString 等。
    • 我正在使用两种类型的 Date 对象。 new Date("2000-01-01") new Date(2000, 0, 1) 在第一种类型中,timeZoneOffset 被添加到日期中,但在第二种类型中没有。如何识别 timezoneOffset 是否添加到日期对象?
    • @KesavanSubramaniam — 第一个被解析为 UTC,第二个被视为本地。两者都解析为 UTC。 Date 对象没有偏移量,它们是 UTC 并使用系统偏移量来获取本地值。
    【解决方案2】:

    RobG 出色答案的变体。

    注意,这将要求您运行最前沿的 JavaScript 它依赖于箭头符号和扩展运算符。

    function parseDateISOString(s) {
      let ds = s.split(/\D/).map(s => parseInt(s));
      ds[1] = ds[1] - 1; // adjust month
      return new Date(...ds);
    }
    

    请注意,如果给定的日期/时间在任何时区,这不会考虑在内。它将假定为当地时间。您可以将new Date 更改为Date.UTC 以采用UTC。

    为什么要编写这样的代码有技术原因。例如,在这里我们应用正确数量的参数及其对应的预期类型。确实,Date 构造函数会将字符串转换为数字,但可能发生的情况是,在优化后的代码需要一个数字但看到一个字符串并采用较慢的路径时,会发生去优化。没什么大不了的,但我尝试编写我的 JavaScript 来避免这样的事情。如果在字符串中可以找到少于 6 个组件,我们也不会在数组边界之外进行索引,这也是您可以在 JavaScript 中执行的操作之一,但它有一些细微的去优化警告。

    【讨论】:

    • @IAfanasov 抱歉,我认为您必须详细说明一下。我不明白你想说什么。
    • 使用map转换为数字是多余的。
    【解决方案3】:

    其中 Date 被调用为具有多个参数的构造函数,指定的参数表示本地时间。

    我还有一个比使用 string.split() 更快的方法,因为我们已经知道数字在哪里:

    return new Date(Number(date.substring(0, 4)), Number(date.substring(5, 7))-1, 
                    Number(date.substring(8, 10)), Number(date.substring(11, 13)), 
                    Number(date.substring(14, 16)), Number(date.substring(17, 19)));
    

    这将在有和/或没有“T”和“Z”字符串的情况下工作,并且仍然具有不错的性能。我添加了显式数字转换(比 parseInt 更快更好),所以这也可以在 TypeScript 中编译。 编号

    【讨论】:

    • 您不能忽略 Z,因为它区分了值应该被解析为 UTC 还是本地。
    猜你喜欢
    • 1970-01-01
    • 2011-08-02
    • 2019-11-22
    相关资源
    最近更新 更多