【问题标题】:Date parsing in javascript is different between safari and chromejavascript 中的日期解析在 safari 和 chrome 之间是不同的
【发布时间】:2011-09-19 14:39:08
【问题描述】:

我有以下代码

var c = new Date(Date.parse("2011-06-21T14:27:28.593Z"));
console.log(c);

在 Chrome 上,它会在控制台上正确打印出日期。在 Safari 中 它失败。谁是正确的,更重要的是什么是最好的方法 处理这个?

【问题讨论】:

  • 他们都给我Tue Jun 21 2011 10:27:28 GMT-0400 (Eastern Daylight Time)
  • 你确定。 jsfiddle.net/A26Gu 在 safari 版本 5.0.4 (6533.20.27) 上运行在“无效日期”的控制台中给我一个输出
  • 为什么要创建两次 Date 对象?你对正确的定义是什么?您可以使用“Date.toISOString()”方法。但请注意:旧版浏览器不支持它。
  • Javascript Date 支持 2 个时区,UTC 和来自操作系统的本地时区。您不能确定本地时区设置是否正确。由于 Javascript 是客户端,因此您不能真正相信它会做任何正确的事情 - 甚至不能解析日期。任何应用程序关键计算都应在服务器端完成。
  • @Erik——好评论,浏览器中的日期非常不可靠。在new Date(Date.parse(string)) 中使用Date.parse 是多余的,因为如果使用字符串调用Date constructor,它无论如何都会传递给Date.parse。此外,Safari 在创建日期方面存在一些错误(如果不是不可能的话)。

标签: javascript parsing date google-chrome safari


【解决方案1】:

你不能真正使用 Date.parse。我建议你使用:new Date (year, month [, date [, hours [, minutes [, seconds [, ms ] ] ] ] ] )

你可以尝试拆分字符串

var s = '2011-06-21T14:27:28.593Z';
var a = s.split(/[^0-9]/);
//for (i=0;i<a.length;i++) { alert(a[i]); }
var d=new Date (a[0],a[1]-1,a[2],a[3],a[4],a[5] );
alert(s+ " "+d);

【讨论】:

  • 这些日期字符串来自服务器。如果您有办法将它们解析为单独的组件,我会很高兴听到。
  • Date.parse 刚刚用旧的 safari 抓住了我,感谢您的回答。
  • 这仅在以当地时间给出日期时有效。它剥离时区并应用本地。示例:您在 -0500 时区,您在 UTC 时间上午 11 点发送,您应该在当地时间上午 6 点返回,但您在当地时间上午 11 点返回。
  • 正如 disso 所说,这个答案忽略了时区。它采用偏移量为 00:00 ("Z") 的字符串并将其解析为就好像它是本地的一样。应该使用 Date.UTC。
【解决方案2】:

我在几个浏览器中检查过,是的,safari 返回invalid date。顺便说一句,您不必在这里使用Date.parse,只需new Date([datestring]) 也可以。 Safari 显然需要对您提供的日期字符串进行更多格式设置。如果您将“-”替换为“/”,删除 T 和点 (.593Z) 之后的所有内容,它将为您提供有效日期。此代码经过测试,可在 Safari 中运行

var datestr = '2011-06-21T14:27:28.593Z'.split(/[-T.]/);
var safdat = new Date( datestr.slice(0,3).join('/')+' '+datestr[3] );

或者使用String.replace(...):

new Date("2016-02-17T00:05:01+0000".replace(/-/g,'/').replace('T',' ').replace(/(\..*|\+.*/,""))

【讨论】:

  • 这会导致您丢失时区和生成的 Date 对象的几分之一秒。我想你可以在最后添加一些额外的代码来重新添加这些组件。
  • 不需要第三个正则表达式中的括号:new Date("2016-02-17T00:05:01+0000".replace(/-/g,'/').replace('T',' ').replace(/\..*|\+.*/,""))
  • 只使用.replace(/-/g,'/') 就可以了。我的日期字符串是这样的“2019-06-26 23:59:59”
【解决方案3】:

我最终使用了一个库来抵消这一点:

http://zetafleet.com/blog/javascript-dateparse-for-iso-8601

一旦包含该库,您就可以使用此代码创建新日期:

var date = new Date(Date.parse(datestring));

我们的项目没有使用毫秒说明符,但我认为这不会给您带来问题。

【讨论】:

    【解决方案4】:

    根据此问题的其他答案,我倾向于避免使用 Date.parse。它似乎不是一种可靠地处理日期的便携方式。

    相反,我使用了类似下面的函数。这使用 jQuery 将字符串数组映射到数字数组,但这是一个非常容易删除/更改的依赖项。我还包括了我认为合理的默认值,以允许您使用相同的函数解析 2007-01-092007-01-09T09:42:00

    function dateFromString(str) {
      var a = $.map(str.split(/[^0-9]/), function(s) { return parseInt(s, 10) });
      return new Date(a[0], a[1]-1 || 0, a[2] || 1, a[3] || 0, a[4] || 0, a[5] || 0, a[6] || 0);
    }
    

    【讨论】:

      【解决方案5】:

      我尝试通过截断并解析它来转换日期,它在 safari 和 ios 上运行良好。

      var dateString = "2016-01-22T08:18:10.000+0000";
       var hours = parseInt(dateString.split("+")[1].substr("0","2"));
       var mins = parseInt(dateString.split("+")[1].substr("2"));
       var date = new Date(dateString.split("+")[0]);
       date.setHours(date.getHours()-hours);
       date.setMinutes(date.getMinutes()-mins);
      

      【讨论】:

        【解决方案6】:

        我使用以下函数来解析带有时区的日期。 Chrome 和 Safari 都可以正常工作:

        function parseDate(date) {
          const parsed = Date.parse(date);
          if (!isNaN(parsed)) {
            return parsed;
          }
        
          return Date.parse(date.replace(/-/g, '/').replace(/[a-z]+/gi, ' '));
        }
        
        console.log(parseDate('2017-02-09T13:22:18+0300'));  // 1486635738000 time in ms

        【讨论】:

        • 这是最安全的方法。我想您应该将最后一个替换更改为 /[a-z]+/gi 之类的内容,以匹配更广泛的受众,例如使用 UTC 而不是 T 的日期。
        • @Narayon 谢谢你的评论,我已经改变了答案。
        【解决方案7】:

        我的类似问题是由于 Safari 不知道如何以 RFC 822 时区格式读取时区。我能够通过使用 ISO 8601 格式来解决这个问题。如果您可以控制日期格式,我可以使用 java 的 SimpleDateFormat "yyyy-MM-dd'T'HH:mm:ss.sssXXX" 来为我生成,即。 “2018-02-06T20:00:00.000+04:00”。出于某种原因,Safari 无法读取“2018-02-06T20:00:00.000+0400”,请注意时区格式中缺少冒号。

        // Works
        var c = new Date("2018-02-06T20:00:00.000+04:00"));
        console.log(c);
        
        // Doesn't work
        var c = new Date("2018-02-06T20:00:00.000+0400"));
        console.log(c);
        

        【讨论】:

        • 发现同样的行为;还没有找到关于这是一个已知错误的文档。但是,这两种格式(带冒号和不带冒号)似乎都打算用作 acceptable formats: The UTC offset is appended to the time in the same way that 'Z' was above, in the form ±[hh]:[mm], ±[hh][mm], or ±[hh]. 实际上,Chrome 和 Firefox 能够解析不带冒号的偏移量
        • This blog post 解释了问题和一个正则表达式解决方案,适用于 Safari 和 Internet Explorer,但仍然没有表明 Safari 或 IE 是否在某个地方承认它们不符合 ISO 规范
        • 啊,这里是:bugs.webkit.org/show_bug.cgi?id=160287 尚未解决,鉴于 IE 肯定不会出现修复,如果可以的话,可能最简单的方法是包含冒号。
        • 如果您需要带时区的日期,那就太完美了。请注意,new Date("2020-04-16T20:00+04:00")) 在浏览器(Chrome、Firefox、Safari、Edge)中也能正常工作。
        【解决方案8】:

        您可以添加本地客户端时区偏移量,而不是在日期字符串的末尾使用“Z”。您可能需要一种方法来为您生成它:

        let timezoneOffset = () => {
            let date = new Date(),
                timezoneOffset = date.getTimezoneOffset(),
                hours = ('00' + Math.floor(Math.abs(timezoneOffset/60))).slice(-2),
                minutes = ('00' + Math.abs(timezoneOffset%60)).slice(-2),
                string = (timezoneOffset >= 0 ? '-' : '+') + hours + ':' + minutes;
            return string;
        }
        

        所以最终的结果是:

        var c = new Date("2011-06-21T14:27:28.593" + timezoneOffset());

        【讨论】:

        • Z是时区偏移量,它代表“零小时偏移量”也称为“祖鲁时间”(UTC),或+00:00
        【解决方案9】:

        这是一个比其他人发布的更强大的 ISO 8601 解析器。它不处理星期格式,但它应该在所有浏览器中一致地处理所有其他有效的 ISO 8601 日期。

        function newDate(value) {
          var field = value.match(/^([+-]?\d{4}(?!\d\d\b))(?:-?(?:(0[1-9]|1[0-2])(?:-?([12]\d|0[1-9]|3[01]))?)(?:[T\s](?:(?:([01]\d|2[0-3])(?::?([0-5]\d))?|24\:?00)([.,]\d+(?!:))?)?(?::?([0-5]\d)(?:[.,](\d+))?)?([zZ]|([+-](?:[01]\d|2[0-3])):?([0-5]\d)?)?)?)?$/) || [];
          var result = new Date(field[1], field[2] - 1 | 0, field[3] || 1, field[4] | 0, field[5] | 0, field[7] | 0, field[8] | 0)
          if (field[9]) {
            result.setUTCMinutes(result.getUTCMinutes() - result.getTimezoneOffset() - ((field[10] * 60 + +field[11]) || 0));
          }
          return result;
        }
        
        console.log(newDate('2011-06-21T14:27:28.593Z'));
        console.log(newDate('1970-12-31T06:00Z'));
        console.log(newDate('1970-12-31T06:00-1200'));

        【讨论】:

          【解决方案10】:

          这是我的 - 相对简单的 - 解决方案,而不是使用 3rd 方库:

          function parseDateTime(datetime, timezone) {
          
            base = new Date(datetime.replace(/\s+/g, 'T') + 'Z');
          
            hoursUTC = base.toLocaleTimeString('de-AT',{ timeZone: 'UTC' }).split(':')[0];
            hoursLocal = base.toLocaleTimeString('de-AT',{ timeZone: 'Europe/Vienna' }).split(':')[0];
            
            timeZoneOffsetSign = (hoursLocal-hoursUTC) < 0 ? '-':'+';
            timeZoneOffset = Math.abs(hoursLocal-hoursUTC);
            timeZoneOffset = timeZoneOffsetSign + timeZoneOffset.toString().padStart(2, '0') + ':00';
            
            return new Date(datetime.replace(/\s+/g, 'T') + timeZoneOffset);
          }
          
          localDate = parseDateTime('2020-02-25 16:00:00','Europe/Vienna');
          console.log(localDate);
          console.log(localDate.toLocaleString('de-AT','Europe/Vienna'));

          【讨论】:

            【解决方案11】:

            同时使用它(Safari / Chrome):

            Date.parse("2018-02-06T20:00:00.000-03:00")
            

            【讨论】:

            • 这种强大的格式在 Safari 和 Chrome 浏览器中都可以识别。
            猜你喜欢
            • 1970-01-01
            • 2012-09-10
            • 1970-01-01
            • 2016-05-18
            • 2017-01-09
            • 1970-01-01
            • 2012-09-12
            • 2015-12-16
            • 2023-03-29
            相关资源
            最近更新 更多