Javascript日期解析在Chrome中返回奇怪的结果 [英] Javascript Date parsing returning strange results in Chrome

查看:107
本文介绍了Javascript日期解析在Chrome中返回奇怪的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Chrome浏览器中发现了一些奇怪的Date行为(版本74.0.3729.131(官方内部版本)(64位)). 在Chrome开发者控制台中执行了以下javascript:

I observed some strange Date behaviour in Chrome (Version 74.0.3729.131 (Official Build) (64-bit)). Following javascript was executed in the Chrome Dev Console:

new Date('1894-01-01T00:00:00+01:00')
// result: Mon Jan 01 1894 00:00:00 GMT+0100 (Central European Standard Time)

new Date('1893-01-01T00:00:00+01:00')
// result: Sat Dec 31 1892 23:53:28 GMT+0053 (Central European Standard Time)

尽管提供了有效的ISO8601值,但我已经在不同的浏览器中通过Date ctor了解了有关非标准日期解析的信息. 但这不仅仅是奇怪的o_o

I have already read about non standard date parsing via the Date ctor in different browsers, although providing valid ISO8601 values. But this is more than strange o_o

在Firefox(Quantum 66.0.3(64位))中,相同的调用会导致预期的Date对象:

In Firefox (Quantum 66.0.3 (64-Bit)) the same calls result in expected Date objects:

new Date('1894-01-01T00:00:00+01:00')
// result: > Date 1892-12-31T23:00:00.000Z

new Date('1893-01-01T00:00:00+01:00')
// result: > Date 1893-12-31T23:00:00.000Z

  • 这是Chrome中的错误吗?
  • 我输入的内容是有效的ISO8601吗?
  • 最重要的问题是,我该如何解决? (希望自己不解析输入字符串)
  • 推荐答案

    好的,似乎无法避免这种现象,因此您应该手动解析日期.但是解析它的方法非常简单.

    Okay, seems like this behaviour cannot be avoided, so you should parse dates manually. But the way to parse it is pretty simple.

    如果我们以ISO 8601格式解析日期,则日期字符串的掩码如下所示:

    If we are parsing date in ISO 8601 format, the mask of date string looks like this:

    <yyyy>-<mm>-<dd>T<hh>:<mm>:<ss>(.<ms>)?(Z|(+|-)<hh>:<mm>)?
    

    1.分别获取日期和时间

    字符串中的T将日期与时间分开.因此,我们可以将ISO字符串除以T

    1. Getting date and time separately

    The T in string separates date from time. So, we can just split ISO string by T

    var isoString = `2019-05-09T13:26:10.979Z`
    var [dateString, timeString] = isoString.split("T")
    

    2.从日期字符串中提取日期参数

    因此,我们有dateString == "2019-05-09".现在,分别获取此参数非常简单

    2. Extracting date parameters from date string

    So, we have dateString == "2019-05-09". This is pretty simple now to get this parameters separately

    var [year, month, date] = dateString.split("-").map(Number)
    

    3.处理时间字符串

    对于时间字符串,由于其可变性,我们应该执行更复杂的操作.
    我们有timeString == "13:26:10Z" 还有可能timeString == "13:26:10"timeString == "13:26:10+01:00

    3. Handling time string

    With time string we should make more complex actions due to its variability.
    We have timeString == "13:26:10Z" Also it's possible timeString == "13:26:10" and timeString == "13:26:10+01:00

    var clearTimeString = timeString.split(/[Z+-]/)[0]
    var [hours, minutes, seconds] = clearTimeString.split(":").map(Number)
    
    var offset = 0 // we will store offset in minutes, but in negation of native JS Date getTimezoneOffset
    if (timeString.includes("Z")) {
        // then clearTimeString references the UTC time
        offset = new Date().getTimezoneOffset() * -1
    } else {
        var clearOffset = timeString.split(/[+-]/)[1]
        if (clearOffset) {
            // then we have offset tail
            var negation = timeString.includes("+") ? 1 : -1 // detecting is offset positive or negative
            var [offsetHours, offsetMinutes] = clearOffset.split(":").map(Number)
            offset = (offsetMinutes + offsetHours * 60) * negation
        } // otherwise we do nothing because there is no offset marker
    }
    

    这时,我们的数据以数字格式表示:
    yearmonthdatehoursminutessecondsoffset的分钟数.

    At this point we have our data representation in numeric format:
    year, month, date, hours, minutes, seconds and offset in minutes.

    是的,我们无法避免,因为它太酷了. JS Date自动为所有负值和太大的值匹配日期.这样我们就可以以原始格式传递所有参数,并且JS Date构造函数将自动为我们创建正确的日期!

    Yes, we cannot avoid it, because it is too cool. JS Date automatically match date for all negative and too big values. So we can just pass all parameters in raw format, and the JS Date constructor will create the right date for us automatically!

    new Date(year, month - 1, date, hours, minutes + offset, seconds)
    

    Voila!这是一个完整的示例.

    Voila! Here is fully working example.

    function convertHistoricalDate(isoString) {
      var [dateString, timeString] = isoString.split("T")
      var [year, month, date] = dateString.split("-").map(Number)
      
      var clearTimeString = timeString.split(/[Z+-]/)[0]
      var [hours, minutes, seconds] = clearTimeString.split(":").map(Number)
      
      var offset = 0 // we will store offset in minutes, but in negation of native JS Date getTimezoneOffset
      if (timeString.includes("Z")) {
        // then clearTimeString references the UTC time
        offset = new Date().getTimezoneOffset() * -1
      } else {
        var clearOffset = timeString.split(/[+-]/)[1]
        if (clearOffset) {
          // then we have offset tail
          var negation = timeString.includes("+") ? 1 : -1 // detecting is offset positive or negative
          var [offsetHours, offsetMinutes] =   clearOffset.split(":").map(Number)
          offset = (offsetMinutes + offsetHours * 60) * negation
        } // otherwise we do nothing because there is no offset marker
      }
    
      return new Date(year, month - 1, date, hours, minutes + offset, seconds)
    }
    
    var testDate1 = convertHistoricalDate("1894-01-01T00:00:00+01:00")
    var testDate2 = convertHistoricalDate("1893-01-01T00:00:00+01:00")
    var testDate3 = convertHistoricalDate("1894-01-01T00:00:00-01:00")
    var testDate4 = convertHistoricalDate("1893-01-01T00:00:00-01:00")
    
    console.log(testDate1.toLocaleDateString(), testDate1.toLocaleTimeString())
    console.log(testDate2.toLocaleDateString(), testDate2.toLocaleTimeString())
    console.log(testDate3.toLocaleDateString(), testDate3.toLocaleTimeString())
    console.log(testDate4.toLocaleDateString(), testDate4.toLocaleTimeString())

    在这种情况下,我们得到的Date实例具有归一化的所有自身值(如.getHours()),包括时区偏移量. testDate1.toISOString仍将返回奇怪的结果.但是,如果您正在使用这个日期,它可能会100%满足您的需求.

    In this case we are getting Date instance with all its own values (like .getHours()) being normalized, including timezone offset. The testDate1.toISOString will still return weird result. But if you are working with this date, it will probably 100% fit your needings.

    希望有所帮助:)

    这篇关于Javascript日期解析在Chrome中返回奇怪的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆