草庐IT

Javascript 日期解析在 Chrome 中返回奇怪的结果

coder 2024-07-16 原文

我在 Chrome(版本 74.0.3729.131(官方构建)(64 位))中观察到一些奇怪的日期行为。 在 Chrome Dev Console 中执行了以下 javascript:

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

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

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?
  • 最重要的问题是,我该如何解决这个问题? (希望自己不解析输入字符串)

最佳答案

好吧,看来这种行为无法避免,所以你应该手动解析日期。但是解析它的方式非常简单。

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

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

1。分别获取日期和时间

string 中的T 分隔日期和时间。所以,我们可以用 T

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

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

因此,我们有 dateString == "2019-05-09"。现在单独获取这些参数非常简单

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

3。处理时间字符串

对于时间字符串,由于它的可变性,我们应该做出更复杂的 Action 。
我们有 timeString == "13:26:10Z" 也有可能 timeString == "13:26:10"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
}

至此,我们有了数字格式的数据表示:
日期小时分钟offset 以分钟为单位。

4。使用 ...原生 JS 日期构造函数

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

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

瞧!这是完整的工作示例。

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% 满足您的需求。

希望对您有所帮助:)

关于Javascript 日期解析在 Chrome 中返回奇怪的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56057128/

有关Javascript 日期解析在 Chrome 中返回奇怪的结果的更多相关文章

  1. Ruby 解析字符串 - 2

    我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby - 用逗号、双引号和编码解析 csv - 2

    我正在使用ruby​​1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\

  4. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  5. ruby-on-rails - date_field_tag,如何设置默认日期? [ rails 上的 ruby ] - 2

    我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问

  6. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  7. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

    我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

  8. ruby - 检查日期是否在过去 7 天内 - 2

    我的日期格式如下:"%d-%m-%Y"(例如,今天的日期为07-09-2015),我想看看是不是在过去的七天内。谁能推荐一种方法? 最佳答案 你可以这样做:require"date"Date.today-7 关于ruby-检查日期是否在过去7天内,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/32438063/

  9. ruby-on-rails - 将 Ruby 中的日期/时间格式化为 YYYY-MM-DD HH :MM:SS - 2

    这个问题在这里已经有了答案:Railsformattingdate(4个答案)关闭4年前。我想格式化Time.Now函数以显示YYYY-MM-DDHH:MM:SS而不是:“2018-03-0909:47:19+0000”该函数需要放在时间中.现在功能。require‘roo’require‘roo-xls’require‘byebug’file_name=ARGV.first||“Template.xlsx”excel_file=Roo::Spreadsheet.open(“./#{file_name}“,extension::xlsx)xml=Nokogiri::XML::Build

  10. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

    我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

随机推荐